【问题标题】:Kaminari is slow with COUNT(*) on a huge table in Postgres [duplicate]Kaminari 在 Postgres 的一张大桌子上使用 COUNT(*) 很慢 [重复]
【发布时间】:2014-03-17 08:29:51
【问题描述】:

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

有没有办法来近似结果的数量?

【问题讨论】:

  • 您想知道如何加快速度以及如何将其与 kaminari 结合起来吗?
  • 我不关心结果的确切数量,我只是不想在可能非常大的结果集上执行COUNT(*)。跨度>
  • 我看不出所谓的副本实际上是一个副本。正如@Shadwell 所写,问题是如何使用 Kaminari 加快速度。链接的“重复”是答案的一部分,但后半部分仍然存在:如何改变 Kaminari 的行为以使用它?

标签: sql ruby-on-rails postgresql will-paginate kaminari


【解决方案1】:

整个表的快速估算

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

您的示例暗示了地址。假设我们在架构 public 中有一个名为 adr 的表:

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

此相关答案中的更多详细信息:
How do I speed up counting rows in a PostgreSQL table?

按条件计数

对于有条件的计数,Postgres 可以使用 indexes 使其更快。这在 Postgres 9.2 中通过“覆盖索引”得到了改进,但必须满足某些要求才能从中获利。更多内容请关注Postgres Wiki about Index-only scans

对于具有citystate 条件的查询,如果条件是选择性(只有一小部分行满足条件),这个多列索引会很有帮助:

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'

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

Materialized view

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

【讨论】:

  • 这似乎返回了表中有多少行。如果我想通过查询条件来限制它,比如WHERE city='New York' AND state='NY'
  • @Avishai:你的条件是稳定的还是任意的?
  • 任意性。大多数搜索至少会按 [City, State] 以及其他几列的任意值进行过滤。
  • @Avishai:我添加了更多指针。这实际上取决于您的确切环境、要求以及您的 Postgres 版本。他们都不是你的问题。
猜你喜欢
  • 2017-01-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-02-07
  • 2011-11-17
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多