位图堆扫描性能

时间:2013-05-05 17:22:56

标签: sql postgresql indexing postgresql-performance

我有一张很棒的报告表。位图堆扫描步骤需要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"

表:
footext字段,有4个不同的值 foo_idbigint,目前有10K个不同的值。

2 个答案:

答案 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的最后一章。