我有两个表,user和sku_pro,两个表中的count查询如下
```
的MySQL> SELECT COUNT(id)FROM user WHERE user.is_active = 1 \ G;
COUNT(id):239568
1行(0.20秒)
的MySQL> SELECT COUNT(id)FROM sku_pro WHERE is_agent = 1 \ G;
COUNT(id):1254286
1行(0.11秒)
```
用户有61列,在用户表中运行show table status,结果为
mysql> show table status like 'user' \G;
*************************** 1. row ***************************
Name: user
Engine: MyISAM
Version: 10
Row_format: Dynamic
Rows: 239606
Avg_row_length: 252
Data_length: 60483836
Max_data_length: 281474976710655
Index_length: 34577408
Data_free: 0
Auto_increment: 239623
Create_time: 2016-08-24 12:01:55
Update_time: 2016-09-14 10:48:10
Check_time: 2016-08-24 12:02:04
Collation: utf8_bin
Checksum: NULL
Create_options:
Comment:
sku_pro有16列,在sku_pro表中运行show table status,结果是
mysql> show table status like 'sku_pro' \G;
*************************** 1. row ***************************
Name: sku_pro
Engine: MyISAM
Version: 10
Row_format: Fixed
Rows: 1281901
Avg_row_length: 53
Data_length: 67940753
Max_data_length: 14918173765664767
Index_length: 52064256
Data_free: 0
Auto_increment: 1988051
Create_time: 2016-09-09 14:06:37
Update_time: 2016-09-14 10:19:39
Check_time: 2016-09-09 14:06:44
Collation: utf8_general_ci
Checksum: NULL
Create_options:
Comment:
1 row in set (0.01 sec)
我不知道为什么用户中的count(id)比sku_pro中的count(id)慢。
答案 0 :(得分:2)
简短回答:缓存。
答案真的很长:
首先注意一些
COUNT(ID)
需要计算非NULL ID的数量。除非确实需要避免使用NULL,否则不要使用该构造。
现在,我将查看您的特定查询,两者都看起来像
SELECT COUNT(id)
FROM tbl
WHERE flag=1;
正如你所提到的,这些表是“大”的。这意味着所需的数据/索引块可能会或可能不会缓存在RAM中。这个问题很容易使查询运行速度提高10倍/更慢。试试这个:重启mysql,运行查询两次。第二轮比第一轮快10倍。
我假设您已关闭“查询缓存”。如果它正在使用,那将增加一个大皱纹。
解析您的查询
要优化查询,您需要以下综合索引:
INDEX(flag, id) -- with the columns in that order.
鉴于此,查询将完全在索引中执行。我们称之为“覆盖”指数。 (MyISAM和InnoDB在此处的行为相同。)因为您为flag
指定了一个值,所以它只会对索引的一部分进行“范围”扫描。 (因此,我们不能轻易说出需要触摸多少个磁盘块。)
如果你只有INDEX(flag)
,优化器可能会忽略它并进行全表扫描。
全表扫描(如果表未缓存)将在与表大小(Data_length
)成比例的时间内运行。
<强> InnoDB的强>
本讨论假定 no WHERE
子句。并使用COUNT(*)
。
(对不起,我提供了一些关于InnoDB的无关信息。)
MyISAM保留每个表中行数的精确计数。因此,没有SELECT COUNT(*) FROM myisam_table
的{{1}}几乎是即时的。 (这个
InnoDB保留一个近似的行数,它从少量随机探测到BTree。此号码显示在WHERE
和SHOW TABLE STATUS
中。 information_schema.TABLES
派生自avg_row_length
,因此也不精确。这两个数字都会不时变化。 (最近版本的变化频率发生了显着变化。)
使用 Data_length/Rows
子句使两个引擎处于非常相似的位置。这将进入索引的工作方式。