1

我有一个大报告表。位图堆扫描步骤需要 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_id目前bigint有 10K 个不同的值。

4

2 回答 2

3

(foo_id, foo, date)在(按此顺序)上创建复合索引。

请注意,如果您选择 500k 条记录(并将它们全部返回给客户端),这可能需要很长时间。

您确定您需要客户端上的所有 500k 记录(而不是某种聚合或 a LIMIT)吗?

于 2013-05-05T18:43:04.773 回答
3

回复评论

我是否需要与索引顺序相同的 where 列?

WHERE子句中表达式的顺序完全不相关,SQL 不是过程语言。

修正错误

出于多种原因,时间戳列不应命名为“日期”。显然,它是一个timestamp,而不是一个date。但更重要的是,date它是所有 SQL 标准中的保留字,也是 Postgres 中的类型和函数名称,不应用作标识符。

您应该为您的问题提供适当的信息,包括完整的表定义和有关现有索引的结论性信息。从阅读手册中有关索引的章节开始可能是一个好主意。

时间戳上的WHERE条件很可能是不正确的:

and date >= '2013-04-04'
and date <= '2013-05-05'

时间戳列的上边界可能应该被排除

and date >= '2013-04-04'
and date <  '2013-05-05'

指数

使用@Quassnoi 提供的多列索引,您的查询会更快,因为所有符合条件的行都可以从索引的一个连续数据块中读取。没有一行是徒劳的(后来被取消资格),就像你现在拥有的一样。
但是 500k 行仍然需要一些时间。通常,您必须验证可见性并从表中获取其他列。Postgres 9.2+ 中可能会选择仅索引扫描。

列的顺序最好采用这种方式,因为经验法则是:列首先是相等的,然后是范围。在 dba.SE 上的这个相关答案中有更多解释和链接。

CLUSTER/ pg_repack

您可以通过根据此索引简化表来进一步加快速度,以便必须从表中读取最少的块 - 如果您没有其他要求反对它!

但是,如果您希望它更快,您可以简化表中行的物理顺序。如果您有能力仅将表锁定几秒钟(例如在下班时间)以重写表并根据索引对行进行排序:

ALTER TABLE foo_table CLUSTER ON idx_myindex_idx;

如果并发使用是一个问题,请考虑pg_repack,它可以在没有排他锁的情况下做同样的事情。

效果:需要从表中读取的块更少,并且所有内容都是预先排序的。如果您在桌子上写字,这是一种一次性效果,会随着时间的推移而恶化。所以你会时不时地重新运行它。

我从dba.SE 上的相关答案中复制并改编了最后一章。

于 2013-05-05T23:47:43.943 回答