【问题标题】:Why are both SELECT count(PK) and SELECT count(*) so slow?为什么 SELECT count(PK) 和 SELECT count(*) 都这么慢?
【发布时间】:2015-07-31 19:48:48
【问题描述】:

我有一个简单的表,其中包含名为 id 的单列 PRIMARY KEY,输入 serial。那里正好有 100,000,000 行。表占用 48GB,PK 索引 ca 2,1GB。运行的机器仅适用于 Postgres,它类似于 Core i5、500GB HDD、8GB RAM。 Pg 配置由 pgtune 实用程序创建(共享缓冲区 ca 2GB,有效缓存 ca 7GB)。操作系统是 Ubuntu 服务器 14.04,Postgres 9.3.6。

为什么SELECT count(id)SELECT count(*) 在这种简单的情况下都这么慢(大约 11 分钟)?

为什么 PostgreSQL 规划器选择全表扫描而不是索引扫描,它应该至少快 25 倍(在它必须从 HDD 读取整个索引的情况下)。或者我哪里错了?

顺便说一句,连续多次运行查询并没有改变任何东西。仍然 cca 11 分钟。

执行计划在这里:

 Aggregate  (cost=7500001.00..7500001.01 rows=1 width=0) (actual time=698316.978..698316.979 rows=1 loops=1)
   Buffers: shared hit=192 read=6249809
   ->  Seq Scan on transaction  (cost=0.00..7250001.00 rows=100000000 width=0) (actual time=0.009..680594.049 rows=100000001 loops=1)
         Buffers: shared hit=192 read=6249809
 Total runtime: 698317.044 ms

【问题讨论】:

  • 要读取的数据量要小 25 倍,并且包含所有足以计数的键,不是吗?我已经运行了 VACUUM FULL 和 ANALYZE (顺便说一句,总共花了 6 个多小时)。
  • 你有很多并发 DML 发生在那个表上吗?只有在可靠的情况下才能(并且将)使用该索引。如果有很多并发事务(或未完成的事务),那么 Postgres 可能不会选择使用索引。您是否有修改该表的“事务中的空闲”连接?还有random_page_cost (postgresql.org/docs/current/static/…) 的值是多少,该设置会影响规划者使用索引的倾向。
  • 您可能还想阅读以下内容:wiki.postgresql.org/wiki/Index-only_scans

标签: sql postgresql select postgresql-9.3


【解决方案1】:

考虑到 HDD 的规格通常介于 50Mb/s 和 100Mb/s 之间,然后对于 48Gb,我希望读取 500 到 1000s 之间的所有内容。

由于您没有 where 子句,因此规划器会看到您对大部分记录感兴趣,因此它不使用索引,因为这需要额外的索引。 postgresql 不能使用索引的原因在于 postgresql 用于事务一致性的 MVCC。这需要拉取行以确保准确的结果。 (见https://wiki.postgresql.org/wiki/Slow_Counting

缓存、CPU 等不会影响这一点,也不会更改缓存设置。这是 IO 绑定的,查询后缓存将被完全丢弃。

如果您可以接受近似值,则可以使用表元数据中的 reltuples 字段:

SELECT reltuples FROM pg_class WHERE relname = 'tbl';

因为这只是一行,所以速度非常快。

更新:自 9.2 起,一种存储可见性信息的新方法允许发生仅索引计数。但是有很多警告,特别是在没有谓词来限制行的情况下。详情请见https://wiki.postgresql.org/wiki/Index-only_scans

【讨论】:

  • 好吧,如果我想要计数 id,那么只扫描索引就足够了,而且会大获全胜,因为它要小得多。顺序读取时的平均读取速率几乎为 100MB/s。我不明白的是为什么计划者没有弄清楚我只想计算索引值。我现在不能测试同样的东西,但我很确定甲骨文会弄清楚。明天将尝试使用 Oracle。
  • 调查了一下。由于 postgres 使用的 MVCC 系统,这无法完成。为了获得准确的计数,它需要扫描表。使用不同并发控制的其他数据库可能允许这样做。我正在更新我的答案。
  • 请提供源代码。谢谢。
  • 几秒钟前刚刚找到该站点 :-)。请从答案中删除不相关的内容,我会接受。
  • @PeterTillemans:如果 Postgres 可以(并且将)使用索引进行计数,如果它认为索引扫描比表扫描便宜。
猜你喜欢
  • 2013-11-07
  • 2017-12-19
  • 1970-01-01
  • 2014-01-19
  • 1970-01-01
  • 1970-01-01
  • 2015-01-15
  • 2011-09-25
  • 1970-01-01
相关资源
最近更新 更多