在MySQL 5.6下做测试的。
Myisam引擎:
当创建一个数据表时,mysql会生成3个文件,分别是(如表:test):
test.frm、test.MYD、test.MYI文件,
test.frm是表结构,test.MYD是存放数据的文件,test.MYI是存放索引的文件,
索引文件存储关系key-value,value是存储一个指向test.MYD中数据行的指针。
在这里就可以看出myisam引擎的数据与索引是分开存储的。
当使用索引搜寻数据时,mysql服务器会先到test.MYI文件中找出数据存储的位置指针,
再到test.MYD中取出数据。
Innodb引擎:
该引擎创建一个数据表,只会生成两个文件,一个是表结构文件test.frm,另一个文件是存储数据与索引的test.ibd。
它的索引存储模式有两种:聚簇索引与第二索引。当用户创建表是没有设置主键,表自动生成一个主键,主键是与数据
一起存储的,这时也就是聚簇了,当用户创建了普通索引时(index、unique等),这时也就是第二索引。
当使用主键搜寻数据时,直接取出数据,当使用secondary key搜寻数据,因secondary key 索引存储模式跟myisam引擎的
索引存储类似,key-value,value是指向primary key的指针,所以此过程会先找出主键的指针,通过聚簇索引找出数据。
count性能分析:
很多人都是count(*),count(1),count(col)那个高,那个低,以下是鄙人做的测试:
一:
myisam引擎,20971520条数据。
表结构:
| t1 | CREATE TABLE `t1` (
`id` int(10) NOT NULL AUTO_INCREMENT,
`t` int(10) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `fuck_index` (`t`)
) ENGINE=MyISAM AUTO_INCREMENT=20971521 DEFAULT CHARSET=latin1
/*!50100 PARTITION BY HASH (id)
PARTITIONS 5 */ |
mysql> select count(*) from t1;
+----------+
| count(*) |
+----------+
| 20971520 |
+----------+
1 row in set (0.00 sec)
此处无论是 count(*),count(1),count(col)都是0.00 sec,重复结果就不贴出来了。
卧槽,这么快?我们看下是什么原因的,是不是做了神马优化的?
mysql> explain select count(id) from t1;
+----+-------------+-------+------+---------------+------+---------+------+------+------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+------+------+------------------------------+
| 1 | SIMPLE | NULL | NULL | NULL | NULL | NULL | NULL | NULL | Select tables optimized away |
+----+-------------+-------+------+---------------+------+---------+------+------+------------------------------+
1 row in set (0.00 sec)
这里count(*),count(1),count(col)结果也是一样的。
从结果中我们看到 Extra列的值是:Select tables optimized away,表明这里使用了优化器了,原因是myisam引擎在insert、update、
delete使用统计器统计记录的变化,当使用count()无条件统计时,直接调用统计器。
此时我们来使用有条件统计:
mysql> select count(*) from t1 where id > 0;
+----------+
| count(*) |
+----------+
| 20971520 |
+----------+
1 row in set (7.73 sec)
mysql> select count(1) from t1 where id > 0;
+----------+
| count(1) |
+----------+
| 20971520 |
+----------+
1 row in set (7.62 sec)
mysql> select count(id) from t1 where id > 0;
+-----------+
| count(id) |
+-----------+
| 20971520 |
+-----------+
1 row in set (7.91 sec)
此时我们看到 count(*),count(1),count(col) 它三俩差别不到,测试多次其实可以预见它们的性能其实都是一个鸟样的。
我们来看下它的执行情况:
mysql> explain select count(1) from t1 where id > 0;
+----+-------------+-------+-------+---------------+---------+---------+------+----------+--------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+---------------+---------+---------+------+----------+--------------------------+
| 1 | SIMPLE | t1 | index | PRIMARY | PRIMARY | 4 | NULL | 20971520 | Using where; Using index |
+----+-------------+-------+-------+---------------+---------+---------+------+----------+--------------------------+
1 row in set (0.00 sec)
这里看extra与type列的值,使用索引统计,rows列看出是全表扫描的。
二:
innodb引擎,10485760条数据
表结构:
t1 | CREATE TABLE `t1` (
`id` int(10) NOT NULL AUTO_INCREMENT,
`t` int(10) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=10485761 DEFAULT CHARSET=latin1
/*!50100 PARTITION BY HASH (id)
PARTITIONS 5 */ |
mysql> select count(id) from t1;
+-----------+
| count(id) |
+-----------+
| 10485760 |
+-----------+
1 row in set (7.08 sec)
mysql> select count(1) from t1;
+----------+
| count(1) |
+----------+
| 10485760 |
+----------+
1 row in set (7.02 sec)
mysql> select count(*) from t1;
+----------+
| count(*) |
+----------+
| 10485760 |
+----------+
1 row in set (7.01 sec)
结果表明 count(*),count(1),count(col) 它三俩还是差不多的。
我们再来看它们的执行情况:
mysql> explain select count(id) from t1;
+----+-------------+-------+-------+---------------+---------+---------+------+----------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+---------------+---------+---------+------+----------+-------------+
| 1 | SIMPLE | t1 | index | NULL | PRIMARY | 4 | NULL | 15313711 | Using index |
+----+-------------+-------+-------+---------------+---------+---------+------+----------+-------------+
1 row in set (0.00 sec)
由于count(*),count(1),count(col)结果都是一样的,就不一一贴出来了,
这里我们关注一下type列、rows列、key列,后面有比较,type值表明了它是全表扫描了。
然后我们添加第二索引:
mysql> alter table t1 add index `fuck_index` (t);
Query OK, 0 rows affected (1 min 2.95 sec)
Records: 0 Duplicates: 0 Warnings: 0
再来重复上面的操作:
mysql> select count(1) from t1;
+----------+
| count(1) |
+----------+
| 10485760 |
+----------+
1 row in set (5.34 sec)
mysql> select count(*) from t1;
+----------+
| count(*) |
+----------+
| 10485760 |
+----------+
1 row in set (5.40 sec)
mysql> select count(id) from t1;
+-----------+
| count(id) |
+-----------+
| 10485760 |
+-----------+
1 row in set (5.37 sec)
这里的 count(*),count(1),count(col) 执行时间还是差不多的,但比上面测试的没有secondary key快了一些,原因与上面
所说的innodb引擎聚簇索引与第二索引有关,我们分析一下它们的执行过程:
mysql> explain select count(1) from t1;
+----+-------------+-------+-------+---------------+------------+---------+------+----------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+---------------+------------+---------+------+----------+-------------+
| 1 | SIMPLE | t1 | index | NULL | fuck_index | 5 | NULL | 15313711 | Using index |
+----+-------------+-------+-------+---------------+------------+---------+------+----------+-------------+
此时我们看到type列是index,全表扫描,key是刚建立的索引,而不是上面测试的PRIMARY。
下面测试有条件的(主键id):
mysql> select count(*) from t1 where id > 0;
+----------+
| count(*) |
+----------+
| 10485760 |
+----------+
1 row in set (6.60 sec)
mysql> select count(1) from t1 where id > 0;
+----------+
| count(1) |
+----------+
| 10485760 |
+----------+
1 row in set (6.62 sec)
mysql> select count(id) from t1 where id > 0;
+-----------+
| count(id) |
+-----------+
| 10485760 |
+-----------+
1 row in set (6.42 sec)
此时 哥三俩 还是差不多的,我们来看一下执行过程:
mysql> explain select count(*) from t1 where id > 0;
+----+-------------+-------+-------+---------------+---------+---------+------+---------+--------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+---------------+---------+---------+------+---------+--------------------------+
| 1 | SIMPLE | t1 | range | PRIMARY | PRIMARY | 4 | NULL | 7656854 | Using where; Using index |
+----+-------------+-------+-------+---------------+---------+---------+------+---------+--------------------------+
1 row in set (0.00 sec)
它们哥三俩结果是一样的,不一一贴出来了。
这时我们关注一下type列、key列、rows列,type的值是range,范围搜索(执行时间:all > index > range > null,null是最快的),
rows的值是上面的一半。
我们再来一次测试有条件(索引t):
mysql> select count(id) from t1 where t > 0;
+-----------+
| count(id) |
+-----------+
| 10485760 |
+-----------+
1 row in set (6.35 sec)
mysql> select count(1) from t1 where t > 0;
+----------+
| count(1) |
+----------+
| 10485760 |
+----------+
1 row in set (6.24 sec)
mysql> select count(*) from t1 where t > 0;
+----------+
| count(*) |
+----------+
| 10485760 |
+----------+
1 row in set (6.06 sec)
mysql> explain select count(*) from t1 where t > 0;
+----+-------------+-------+-------+---------------+------------+---------+------+---------+--------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+---------------+------------+---------+------+---------+--------------------------+
| 1 | SIMPLE | t1 | range | fuck_index | fuck_index | 5 | NULL | 7656854 | Using where; Using index |
+----+-------------+-------+-------+---------------+------------+---------+------+---------+--------------------------+
1 row in set (0.28 sec)
这里的结果与上面的差不多。本人水平有限,有错请指导指导^-^