为什么计数查询在数据量较少的情况下比在MyISAM

时间:2016-09-14 03:03:07

标签: mysql myisam

我有两个表,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)慢。

1 个答案:

答案 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}}几乎是即时的。 (这个一个查询是关于MyISAM始终优于InnoDB的唯一一个

另一方面,InnoDB不能。这是因为不同的连接可以运行不同的事务,其中任何事务都可以回滚,从而搞乱任何死亡计算的确切计数。相反,InnoDB找到“最小”的索引并进行扫描。

InnoDB保留一个近似的行数,它从少量随机探测到BTree。此号码显示在WHERESHOW TABLE STATUS中。 information_schema.TABLES派生自avg_row_length,因此也不精确。这两个数字都会不时变化。 (最近版本的变化频率发生了显着变化。)

使用 Data_length/Rows子句使两个引擎处于非常相似的位置。这将进入索引的工作方式。