在Postgres的一张巨大的桌子上,Kaminari的COUNT(*)很慢

我正在使用Kaminari gem在大表(~1.5MM行)上分页查询。 虽然获取实际结果页面非常快(~20ms),但kaminari添加了SELECT COUNT(*) WHERE ....非常慢,并且在执行时间上增加了几秒钟。

有没有办法估算结果的数量?

全表的快速估算

对于整个表格的快速估计:

您的示例提示地址。 假设我们在模式public有一个名为adr的表:

 SELECT reltuples FROM pg_class WHERE oid = 'public.adr'::regclass; 

这个相关答案的更多细节:
如何加快PostgreSQL表中的行计数?

与条件一起计数

对于具有条件的计数,Postgres可以使用索引使其更快。 Postgres 9.2中的“覆盖索引”对此进行了改进,但必须满足某些要求才能从中获益。 Postgres Wiki中更多关于仅索引扫描的内容 。

对于具有city state条件的查询,如果条件是选择性的 (只有一小部分行符合条件),则此多列索引将有很大帮助:

 CREATE INDEX adr_foo_idx ON adr (city, state); 

如果您有一小组典型条件 ,您甚至可以使用部分索引 :

 CREATE INDEX adr_ny_ny_idx ON adr(adr_id) WHERE city = 'New York' AND state = 'NY'; 

…每一组(state, city)

或者两者兼而有之:

 CREATE INDEX adr_ny_idx ON adr (city) WHERE state = 'NY'; 

……每state一个

规范化

当然,使你的大表(和索引)更小的一切都有帮助。 城市和城市的查找表将大大减少冗余存储。 这里的关键词是规范化 。

代替:

 CREATE TABLE adr ( adr_id serial PRIMARY KEY ,state text ,city text ... ); SELECT count(*) FROM adr WHERE city = 'New York' AND state = 'NY'; 

规范化您的数据库设计并使用适当的索引:

 CREATE TABLE state ( state_id serial PRIMARY KEY ,state text UNIQUE ); CREATE TABLE city ( city_id serial PRIMARY KEY ,state_id int REFERENCES state ,city text ,UNIQUE (state_id, city) ); CREATE TABLE adr ( adr_id serial PRIMARY KEY city_id int REFERENCES city ... ); CREATE INDEX adr_city_idx ON adr (city_id); SELECT count(*) FROM state s JOIN city c USING (state_id) JOIN adr a USING (city_id) WHERE s.state = 'NY' AND c.city = 'New York' 

表和索引变小。 整数处理比文本更快。 一切都变得更快。

物化视图

最重要的是,如果性能至关重要,并且由于您不需要精确计数,则可以使用具有相关条件计数的物化视图。 在您选择的事件或时间刷新视图以使数字保持最新。 有关详细信息,请参阅手册链接。 需要Postgres 9.3,但您可以在任何版本中手动轻松实现它。

Interesting Posts