我有一个包含大约2000万条记录的表,其索引超过created_at
时间戳字段。索引的大小很大,即使使用索引扫描,通过该字段查询表也不够快(7秒)。所以我决定用较小的表达索引来玩。事情是计划者永远不会打他们,而是进行顺序扫描。我做错了什么?
db=# SELECT COUNT(*) FROM xxx;
count
----------
19527175
(1 row)
条件表达指数定义为:
CREATE INDEX xxx_idx ON xxx (DATE(created_at)) WHERE created_at > '2016-01-01';
该分数仅占整个数据的2%。
db=# SELECT COUNT(*) FROM xxx WHERE created_at > '2016-01-01';
count
---------
335895
(1 row)
然而,当通过指定相同的条件和表达式来尝试使用索引时,会使用顺序扫描。
db=# EXPLAIN ANALYZE SELECT * FROM xxx WHERE DATE(created_at) > '2016-01-01';
QUERY PLAN
-----------------------------------------------------------------------
Seq Scan on xxx (cost=0.00..1533675.37 rows=6509853 width=884) (actual time=23.104..120704.554 rows=319278 loops=1)
Filter: (date(created_at) > '2016-01-01'::date)
Rows Removed by Filter: 19208882
Planning time: 0.245 ms
Execution time: 120748.839 ms
(5 rows)
答案 0 :(得分:1)
您混淆了查询中的created_at
用法(使用DATE(created_at)
)和索引定义。
为了确保您的所有查询都使用您的索引(使用index only scan),您应该在索引'中使用相同的表达式/列。表达式和索引中的表达式WHERE
子句(partial index)。
F.ex:
CREATE INDEX xxx_idx ON xxx (DATE(created_at)) WHERE DATE(created_at) > '2015-12-01';
然后,如果您查询DATE(created_at)
将使用索引 - 最有可能的是:当PostgreSQL的引擎确定顺序时,它仍然有可能不会被使用扫描更快(索引将在significantly smaller than its table时使用)。
只有在明确过滤索引时,才会使用原始索引。 WHERE
条款也是DATE(created_at) > '2015-12-01' AND created_at > '2015-12-01'
。