mysql - 为什么 COUNT() 从大表查询比 SUM() 快得多

标签 mysql sql performance

我有一个包含下表的数据仓库:

主要

大约800万条记录

CREATE TABLE `main` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`cid` mediumint(8) unsigned DEFAULT NULL, //This is the customer id
`iid` mediumint(8) unsigned DEFAULT NULL, //This is the item id
`pid` tinyint(3) unsigned DEFAULT NULL, //This is the period id
`qty` double DEFAULT NULL,
`sales` double DEFAULT NULL,
`gm` double DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `idx_pci` (`pid`,`cid`,`iid`) USING HASH,
KEY `idx_pic` (`pid`,`iid`,`cid`) USING HASH
) ENGINE=InnoDB AUTO_INCREMENT=7978349 DEFAULT CHARSET=latin1

时期

这张表大约有50条记录,有如下字段

  • 编号
  • 年份

客户

这有大约 23,000 条记录和以下文件

  • 编号
  • number//这个字段是唯一的
  • name//这只是一个描述字段

以下查询运行速度非常快(不到 1 秒)并返回大约 2,000:

select count(*) 
from mydb.main m 
INNER JOIN mydb.period p ON p.id = m.pid 
INNER JOIN mydb.customer c ON c.id = m.cid 
WHERE p.year = 2013 AND c.number = 'ABC';

但是这个查询要慢得多(超过 45 秒),这与之前的查询相同,但是求和而不是计数:

select sum(sales)
from mydb.main m 
INNER JOIN mydb.period p ON p.id = m.pid 
INNER JOIN mydb.customer c ON c.id = m.cid 
WHERE p.year = 2013 AND c.number = 'ABC';

当我解释每个查询时,我看到的唯一区别是“count()” 查询“额外”字段显示“使用索引”,而对于“sum()”查询,该字段为 NULL。

解释 count() 查询

| id | select_type | table | type  | possible_keys        | key          | key_len | ref                 | rows | Extra       |
|  1 | SIMPLE      | c     | const | PRIMARY,idx_customer | idx_customer | 11      | const               |    1 | Using index |
|  1 | SIMPLE      | p     | ref   | PRIMARY,idx_period   | idx_period   | 4       | const               |    6 | Using index |
|  1 | SIMPLE      | m     | ref   | idx_pci,idx_pic      | idx_pci      | 6       | mydb.p.id,const     |    7 | Using index |

解释 sum() 查询

| id | select_type | table | type  | possible_keys        | key          | key_len | ref                 | rows | Extra       |
|  1 | SIMPLE      | c     | const | PRIMARY,idx_customer | idx_customer | 11      | const               |    1 | Using index |
|  1 | SIMPLE      | p     | ref   | PRIMARY,idx_period   | idx_period   | 4       | const               |    6 | Using index |
|  1 | SIMPLE      | m     | ref   | idx_pci,idx_pic      | idx_pci      | 6       | mydb.p.id,const     |    7 | NULL        |
  • 为什么 count() 比 sum() 快这么多?它不应该为两者都使用索引吗?
  • 我该怎么做才能使 sum() 运行得更快?

提前致谢!

编辑

所有表都显示它使用的是Engine InnoDB

此外,作为旁注,如果我只执行“SELECT *”查询,则运行速度非常快(不到 2 秒)。我希望“SUM()”不会花费比这更长的时间,因为 SELECT * 无论如何都必须检索行...

已解决

这是我学到的:

  • 由于销售字段不是索引的一部分,它必须从硬盘驱动器中检索记录(这可能有点慢)。
  • 我不太熟悉这个,但看起来 I/O 性能可以通过切换到 SSD(固态驱动器)来提高。我必须对此进行更多研究。
  • 现在,我想我要创建另一层摘要以获得我正在寻找的性能。
  • 我将主表上的索引重新定义为 (pid,cid,iid,sales,gm,qty),现在 sum() 查询运行得非常快!

谢谢大家!

最佳答案

索引是关键行的列表。

当您执行 count() 查询时,可以忽略数据库中的实际数据,只使用索引。

当您执行 sum(sales) 查询时,必须从磁盘读取每一行以获得销售数字,因此速度要慢得多。

此外,索引可以批量读取,然后在内存中处理,而磁盘访问将随机破坏试图从磁盘读取行的驱动器。

最后,索引本身可能包含计数摘要(以帮助生成计划)

更新

您的表上实际上有三个索引:

PRIMARY KEY (`id`),
KEY `idx_pci` (`pid`,`cid`,`iid`) USING HASH,
KEY `idx_pic` (`pid`,`iid`,`cid`) USING HASH

因此,您只有 idpidcidiid 列的索引。 (顺便说一句,大多数数据库都足够智能,可以组合索引,因此您可能可以对索引进行一些优化)

如果您添加另一个键,如KEY idx_sales(id,sales)可以提高性能,但考虑到销售值的可能数字分布,您将添加额外的更新的性能成本可能是一件坏事

关于mysql - 为什么 COUNT() 从大表查询比 SUM() 快得多,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17148819/

相关文章:

performance - <ui :param> facelet tag performance

c# - DataTable 是否比 List<T> 消耗更多内存?

php - MySQL 查询 - 替换或删除列中的 0(零),但不删除单词或数字中的数字零?

php - 如何限制 HTML 中的列数

php - 我需要在另一个中使用一个 mySQL 查询的输出(它的值)

mysql - 在 mysql 的 Select If 条件中使用更新查询

java - 通过 ssh 运行 mysql 命令

mysql - 在不在磁盘上创建临时文件的情况下在 MySQL 中创建索引

mysql - 如何根据父字段检索数据

php - 如何在PHP中执行多张图片插入和上传?