为啥 count(*) 查询在某些表上很慢,而在其他表上却没有?
Posted
技术标签:
【中文标题】为啥 count(*) 查询在某些表上很慢,而在其他表上却没有?【英文标题】:Why is count(*) query slow on some tables but not on others?为什么 count(*) 查询在某些表上很慢,而在其他表上却没有? 【发布时间】:2015-05-05 21:45:21 【问题描述】:我有一个运行在 wamp 服务器上的 mysql 数据库,我用它来对 Flickr 数据进行频繁的模式挖掘。在将数据加载到数据库中的过程中,我运行了一个计数查询来确定我已经加载了多少张图像。我很惊讶它花了 3 分 49 秒
select count(*) from image;
在一个单独的表“概念”中,我存储了用户为其图像提供的标签列表。对“概念”表的类似查询耗时 0.8 秒。奥秘在于这两个表都有大约 200,000 行。 select count(*) from image;
返回 283,890,select count(*) from concept;
返回 213,357。
这是每个表的描述
显然,“图像”表的行数更大。我认为基于this blog post 可能“图像”太大而无法保存在内存中,因此我还使用this answer 中的代码测试了表的大小。
SELECT table_name AS "Tables",
round(((data_length + index_length) / 1024 / 1024), 2) "Size in MB"
FROM information_schema.TABLES
WHERE table_schema = "$DB_NAME"
ORDER BY (data_length + index_length) DESC;
“图片”为 179.98 MB,“概念”为 15.45 MB
我在具有 64 GB RAM 的机器上运行 mysql,因此这两个表应该很容易适应。我错过了什么会减慢我的查询速度?我该如何解决?
【问题讨论】:
两张表使用的是什么存储引擎?是image
innoDB 吗?
如果你改为使用 count(id) 会改变执行所需的时间吗?
@Interrobang 是的,两者都是 innoDB。这是“图像”的错误选择吗?
@Aziz 我尝试使用 count(id),“图像”花了 3 分 13 秒,所以只好 30 秒。
@2cents 有趣!然后我什么都没得到:)
【参考方案1】:
在对 InnDB 表执行 SELECT COUNT(*)
时,MySQL 必须扫描索引以计算行数。在这种情况下,您唯一的索引是主(聚集)索引,因此 MySQL 会扫描它。
对于聚集索引,实际的表数据也存储在那里。不包括开销,您的 image
表每行大约 1973 个字节(我假设两个主键列都有一个单字节字符集)。每 (16k) 页最多大约 8 条记录,因此大约 35,486 页。您的 comcept
表每行大约 257 个字节。每页大约有 63 条记录,因此大约是 3,386 页。这是必须扫描的数据量的巨大差异。
它必须完整地阅读每一页,因为页面可能没有完全填满。
那么,就性能而言,也许其中一些页面在内存中,而另一些则不在。由于 MySQL 的 15/16 偏好,也存在一些微小差异,但以上所有数字都应视为近似值。
解决方案
将二级索引添加到较大的表中,SELECT COUNT(*)
的性能应该与较小的表大致相同。当然,如果要更新另一个索引,更新速度会慢一些。
为了提高性能,请缩短主键,因为二级索引包括索引列和完整的主键。
如果您只需要估计的行数,您可以使用以下之一中的 rows
值,它使用表统计信息而不是扫描索引:
SHOW TABLE STATUS LIKE 'image'
或
EXPLAIN SELECT COUNT(*) FROM image
【讨论】:
如果添加二级索引会有一些折衷。更新需要更长的时间,但 SELECT COUNT(*) 会更快。要进一步改进,请使用较小的主键,因为二级索引中的每条记录都有索引列和主键。 于是我把主键换成了自增整数主键,结果超级快,0.05秒。谢谢! 现在,您明白为什么我提到将 AI PK 值作为表中的第一列,无论您的 varchar 字段是否唯一。恕我直言,这是一种很好的做法,除非你能证明,否则将 AI PK 值作为所有表格的第一列。【参考方案2】:如果您正在寻找一个大致数字而不是精确计数,那么 show table status
中的 Rows 列可能就足够了。对于 InnoDB 表而言,它并不总是准确的,但无论如何粗略估计您似乎都可以接受。
【讨论】:
以上是关于为啥 count(*) 查询在某些表上很慢,而在其他表上却没有?的主要内容,如果未能解决你的问题,请参考以下文章