sql - 带有(不正确的?)索引的缓慢 PostgreSQL 查询

标签 sql database postgresql

我有一个包含 3000 万行的事件表。以下查询在 25 秒后返回

SELECT DISTINCT "events"."id", "calendars"."user_id" 
FROM "events" 
LEFT JOIN "calendars" ON "events"."calendar_id" = "calendars"."id" 
WHERE "events"."deleted_at" is null 
AND tstzrange('2016-04-21T12:12:36-07:00', '2016-04-21T12:22:36-07:00') @> lower(time_range) 
AND ("status" is null or (status->>'pre_processed') IS NULL) 

status 是一个 jsonb 列,在 status->>'pre_processed' 上有一个索引。这是在事件表上创建的其他索引。 time_rangeTSTZRANGE 类型。

CREATE INDEX events_time_range_idx ON events USING gist (time_range);
CREATE INDEX events_lower_time_range_index on events(lower(time_range));
CREATE INDEX events_upper_time_range_index on events(upper(time_range));
CREATE INDEX events_calendar_id_index on events (calendar_id)

我绝对超出了我的舒适范围,我正在努力减少查询时间。这是解释分析的输出

  HashAggregate  (cost=7486635.89..7486650.53 rows=1464 width=48) (actual time=26989.272..26989.306 rows=98 loops=1)
  Group Key: events.id, calendars.user_id
  ->  Nested Loop Left Join  (cost=0.42..7486628.57 rows=1464 width=48) (actual time=316.110..26988.941 rows=98 loops=1)
    ->  Seq Scan on events  (cost=0.00..7475629.43 rows=1464 width=50) (actual time=316.049..26985.344 rows=98 loops=1)
          Filter: ((deleted_at IS NULL) AND ((status IS NULL) OR ((status ->> 'pre_processed'::text) IS NULL)) AND ('["2016-04-21 19:12:36+00","2016-04-21 19:22:36+00")'::tstzrange @> lower(time_range)))
          Rows Removed by Filter: 31592898
    ->  Index Scan using calendars_pkey on calendars  (cost=0.42..7.50 rows=1 width=48) (actual time=0.030..0.031 rows=1 loops=98)
          Index Cond: (events.calendar_id = (id)::text)
Planning time: 1.468 ms
Execution time: 26989.370 ms

下面是删除了查询的 events.deleted_at 部分的解释分析

HashAggregate  (cost=7487382.57..7487398.33 rows=1576 width=48) (actual time=23880.466..23880.503 rows=115 loops=1)
  Group Key: events.id, calendars.user_id
  ->  Nested Loop Left Join  (cost=0.42..7487374.69 rows=1576 width=48) (actual time=16.612..23880.114 rows=115 loops=1)
    ->  Seq Scan on events  (cost=0.00..7475629.43 rows=1576 width=50) (actual time=16.576..23876.844 rows=115 loops=1)
          Filter: (((status IS NULL) OR ((status ->> 'pre_processed'::text) IS NULL)) AND ('["2016-04-21 19:12:36+00","2016-04-21 19:22:36+00")'::tstzrange @> lower(time_range)))
          Rows Removed by Filter: 31592881
    ->  Index Scan using calendars_pkey on calendars  (cost=0.42..7.44 rows=1 width=48) (actual time=0.022..0.023 rows=1 loops=115)
          Index Cond: (events.calendar_id = (id)::text)

规划时间:0.372 毫秒 执行时间:23880.571 毫秒

我在 status 列上添加了索引。其他一切都已经存在,我不确定如何继续前进。关于如何将查询时间减少到更易于管理的数字有什么建议吗?

最佳答案

lower(time_range) 上的 B 树索引只能用于涉及 < 的条件, <= , = , >=>运营商。 @> operator 可能在内部依赖这些,但是对于 planner 来说,这个范围检查操作是一个黑盒子,所以它不能使用索引。

您需要根据 B 树运算符重新表述您的条件,即:

lower(time_range) >= '2016-04-21T12:12:36-07:00' AND
lower(time_range) < '2016-04-21T12:22:36-07:00'

关于sql - 带有(不正确的?)索引的缓慢 PostgreSQL 查询,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36782549/

相关文章:

更新用户配置文件时mysql语法显示错误

sql - 当可以使用 GROUP BY 时,为什么不使用 DISTINCT?

sql - Postgresql,一个函数调用另一个函数并向调用者获取2个输出值

mysql - 最好使用两列或 DATETIME

Django ORM 错误 : FieldError: Cannot resolve keyword XXX into field

java - 托管 HIPPO CMS

mysql - SQL索引优化WHERE查询

mysql - 使用变量并重用它时,SELECT 语句无法正确显示数据

php - 某列分组显示的SQL语句

python - sqlalchemy 和 postgresql 中的大表