我有一张很棒的报告表。位图堆扫描步骤需要5秒以上。
我能做些什么吗?我在表中添加了列,重新索引它使用的索引会有帮助吗?
我做了工会并对数据求和,所以我不会向客户返回500K记录 我使用postgres 9.1 在这里解释:
Bitmap Heap Scan on foo_table (cost=24747.45..1339408.81 rows=473986 width=116) (actual time=422.210..5918.037 rows=495747 loops=1)
Recheck Cond: ((foo_id = 72) AND (date >= '2013-04-04 00:00:00'::timestamp without time zone) AND (date <= '2013-05-05 00:00:00'::timestamp without time zone))
Filter: ((foo)::text = 'foooooo'::text)
-> Bitmap Index Scan on foo_table_idx (cost=0.00..24628.96 rows=573023 width=0) (actual time=341.269..341.269 rows=723918 loops=1)
查询:
explain analyze
SELECT CAST(date as date) AS date, foo_id, ....
from foo_table
where foo_id = 72
and date >= '2013-04-04'
and date <= '2013-05-05'
and foo = 'foooooo'
Index def:
Index "public.foo_table_idx"
Column | Type
-------------+-----------------------------
foo_id | bigint
date | timestamp without time zone
btree, for table "public.external_channel_report"
表:
foo
是text
字段,有4个不同的值
foo_id
为bigint
,目前有10K个不同的值。
答案 0 :(得分:3)
在(foo_id, foo, date)
上创建一个复合索引(按此顺序)。
请注意,如果您选择500k记录(并将它们全部返回给客户端),则可能需要很长时间。
您确定需要客户端上的所有500k记录(而不是某种聚合或LIMIT
)吗?
答案 1 :(得分:3)
我是否需要索引的相同顺序的where列?
WHERE
子句中的表达式顺序完全不相关,SQL不是过程语言。
由于多种原因,时间戳列不应命名为“date”。显然,它是timestamp
,而不是date
。但更重要的是,date
它在所有SQL标准中都是reserved word,在Postgres中是一个类型和函数名称,不应该用作标识符。
您应该提供有关问题的正确信息,包括完整的表定义和有关现有索引的结论性信息。我可能最好先阅读chapter about indexes in the manual。
时间戳上的WHERE
条件很可能不正确:
and date >= '2013-04-04'
and date <= '2013-05-05'
时间戳列的上边框应该排除:
and date >= '2013-04-04'
and date < '2013-05-05'
使用多列索引@Quassnoi provided,您的查询将更快,因为所有符合条件的行都可以从索引的一个连续数据块中读取。没有任何行是徒劳的(后来被取消资格),就像你现在拥有它一样 但是500k行仍然需要一些时间。通常,您必须验证可见性并从表中获取其他列。 index-only scan 可能是Postgres 9.2 +中的一个选项。
列的顺序最好用这种方式,因为经验法则是:首先是相等的列 - 然后是范围。 this related answer on dba.SE中的更多解释和链接。
CLUSTER
/ pg_repack 您可以通过根据此索引简化表来进一步加快速度,以便必须从表中读取最少的块 - 如果您没有其他要求,则可以使用它!
如果您希望它更快,您可以简化表格中行的物理顺序。如果您能够专门锁定表几秒钟(例如在非工作时间),则根据索引重写表并订购行:
ALTER TABLE foo_table CLUSTER ON idx_myindex_idx;
如果并发使用是个问题,请考虑pg_repack
,它可以在没有排他锁的情况下执行相同操作。
效果:需要从表中读取更少的块,并且所有内容都已预先排序。如果你在桌子上写字,这是一次性的影响随着时间的推移而恶化。所以你会不时重新运行它。
我复制并改编了this related answer on dba.SE的最后一章。