首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在大型MySQL InnoDB表上,完整计数查询真的如此缓慢吗?

在大型MySQL InnoDB表上,完整计数查询真的如此缓慢吗?
EN

Stack Overflow用户
提问于 2019-09-13 09:57:13
回答 2查看 3.4K关注 0票数 4

我们有一张有数百万入口的大桌子。完整的计数非常慢,请参阅下面的代码。对于MySQL InnoDB表来说,这种情况很常见吗?没有办法加速这件事吗?即使使用查询缓存,它仍然“慢”。我还想知道,为什么2.8百万条目的“通信”表的计数要比对4.5百万条目的"transaction“计数要慢。

我知道用where子句更快。我只想知道糟糕的表现是否正常。

我们使用的是Amazon 5.7和m4.xsize (4 CPU,16 GB RAM,500 GB存储)。我也尝试过更大的实例,有更多的CPU和RAM,但查询时间没有太大变化。

代码语言:javascript
复制
mysql> SELECT COUNT(*) FROM transaction;
+----------+
| COUNT(*) |
+----------+
|  4569880 |
+----------+
1 row in set (1 min 37.88 sec)

mysql> SELECT COUNT(*) FROM transaction;
+----------+
| count(*) |
+----------+
|  4569880 |
+----------+
1 row in set (1.44 sec)

mysql> SELECT COUNT(*) FROM communication;
+----------+
| count(*) |
+----------+
|  2821486 |
+----------+
1 row in set (2 min 19.28 sec)
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2019-09-13 16:52:44

除了比尔说的..。

最小指数

InnoDB为执行COUNT(*)选择了最小的索引。结果表明,communication的各项指标均大于transaction的最小值,因此存在时间差。在判断索引的大小时,使用任何二级索引包括PRIMARY KEY列:

代码语言:javascript
复制
PRIMARY KEY(id),   -- INT (4 bytes)
INDEX(flag),       -- TINYINT (1 byte)
INDEX(name),       -- VARCHAR(255) (? bytes)

为了测量大小,PRIMARY KEY很大,因为它包含(由于集群)表的所有列。INDEX(flag)是"5字节“。INDEX(name)可能平均有几十个字节。SELECT COUNT(*)显然会选择INDEX(flag)

显然,transaction有一个“小”指数,但communication没有。

TEXT/BLOG列有时被存储为“非记录”。因此,它们不计算PK索引的大小。

查询缓存

如果打开“查询缓存”,则查询的第二次运行可能比第一次快得多。但这只是在同一时间内没有改变表的情况。由于对表的任何更改都会使该表的所有QC条目无效,因此QC在生产系统中很少有用。我所说的“更快”指的是0.001秒,而不是1.44秒。

1m38s和1.44s之间的差异可能是由于buffer_pool中缓存的内容-- InnoDB的通用缓存区域。第一次运行可能没有发现RAM中最小的索引,所以它做了大量的I/O操作,花费了98秒来获取该索引的所有450万行。第二次运行发现所有缓存在buffer_pool中的数据,因此它以CPU速度运行(无I/O),因此运行速度要快得多。

足够好的

在这种情况下,我质疑做COUNT(*)的必要性。请注意您是如何说"2.8百万条目“的,就好像两个重要的数字”足够好“一样。如果您在UI上向用户显示计数,这难道不是“足够好”吗?如果是这样的话,性能的一个解决方案是每天进行一次计数,并将其存储在某个地方。这将允许即时访问“足够好”的值。

还有其他的技巧。一种是使用活动代码或使用某种形式的汇总表保持计数器的更新。

向it抛出硬件

您已经发现更改硬件没有帮助。

  • 98是任何RDS的I/O产品都能运行的最快速度。
  • 1.44s与任何一个RDS CPU运行的速度一样快。
  • MySQL (及其变体)每个查询不使用一个以上的CPU。
  • 您有足够的内存,所以整个“小”索引将适合在buffer_pool中,直到您的第二个SELECT COUNT(*).. (内存太少会导致第二个运行非常慢)。
票数 3
EN

Stack Overflow用户

发布于 2019-09-13 15:06:09

这是使用支持多版本并发控制(MVCC)的数据库存储引擎的缺点。

InnoDB允许在事务中隔离查询,而不阻塞正在读取和写入数据行的其他并发客户端。这些并发更新不会影响您的事务所拥有的数据视图。

但是,考虑到在进行计数时,许多行正在被添加或删除,那么表中的行数是多少?答案是模糊的。

您的事务不应该能够“看到”在您的事务启动后创建的行版本。同样,即使有人请求删除行,您的事务也应该对行进行计数,但它们是在事务启动后进行的。

答案是,当您执行SELECT COUNT(*) - or时,需要检查许多行的任何其他类型的查询-- InnoDB必须访问每一行,以查看该行的当前版本在您的事务的数据库视图中是可见的,并计算它是否可见。

在不支持事务或并发更新(如MyISAM )的表中,存储引擎将行总数保持为表的元数据。此存储引擎不能同时支持多个线程更新行,因此行总数不太模糊。因此,当您从一个SELECT COUNT(*)表请求MyISAM时,它只返回它在内存中拥有的行的计数(但是如果您使用WHERE子句执行SELECT COUNT(*)来根据某些条件来计数某些行子集,那么这是没有用的,所以在这种情况下它必须实际计数它们)。

一般来说,大多数人认为InnoDB对并发更新的支持很有价值,他们愿意牺牲SELECT COUNT(*)的优化。

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/57921400

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档