我使用Kaminari gem在大表(~1.5MM行)上对查询进行分页。虽然获取实际结果页面非常快(约20毫秒),但kaminari添加SELECT COUNT(*) WHERE ....
的速度极慢,并且在执行时间上增加了几秒钟。
有没有办法估算结果的数量?
答案 0 :(得分:4)
快速估算整个表格:
您的示例提示地址。假设我们在架构adr
中有一个名为public
的表:
SELECT reltuples FROM pg_class WHERE oid = 'public.adr'::regclass;
此相关答案的更多细节:
How do I speed up counting rows in a PostgreSQL table?
对于有条件的计数,Postgres可以使用索引来加快速度。 Postgres 9.2中的“覆盖索引”对此进行了改进,但必须满足某些要求才能从中获益。更多内容见Postgres Wiki about Index-only scans。
对于city
和state
条件的查询,如果条件是 selective ,则此多列索引会有很大帮助(只有一小部分行符合条件):
CREATE INDEX adr_foo_idx ON adr (city, state);
如果你有一小组典型条件,你甚至可以使用partial indexes:
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
当然,让你的大表(和索引)更小的一切都有帮助。城市和城市的查找表将大大减少冗余存储。这里的关键词是normalization。
而不是:
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,但您可以在任何版本中手动轻松实现它。