MySql的Myisam索引、Innodb索引 、count性能分析个人见解

在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)

这里的结果与上面的差不多。本人水平有限,有错请指导指导^-^

时间: 2024-10-19 09:18:09

MySql的Myisam索引、Innodb索引 、count性能分析个人见解的相关文章

mysql索引结构原理、性能分析与优化

原文  http://wulijun.github.com/2012/08/21/mysql-index-implementation-and-optimization.html 第一部分:基础知识 索引 官方介绍索引是帮助MySQL高效获取数据的数据结构.笔者理解索引相当于一本书的目录,通过目录就知道要的资料在哪里, 不用一页一页查阅找出需要的资料. 唯一索引(unique index) 强调唯一,就是索引值必须唯一. 创建索引: create unique index 索引名 on 表名(列

由浅入深探究mysql索引结构原理、性能分析与优化

转载自:http://www.phpben.com/?post=74 第一部分:基础知识: 索引 官方介绍索引是帮助MySQL高效获取数据的数据结构.笔者理解索引相当于一本书的目录,通过目录就知道要的资料在哪里,不用一页一页查阅找出需要的资料.关键字index ------------------------------------------------------------- 唯一索引 强调唯一,就是索引值必须唯一,关键字unique index 创建索引: 1.create unique

MyISAM和InnoDB索引实现对比

InnoDB 特点: 支持ACID事务(具有提交,回滚和崩溃恢复能力),支持存储过程,视图,支持行级锁定,支持外键,处理巨大数据量时拥有最大性能(可以说它的CPU效率是其他基于磁盘关系数据库引擎所不能匹敌的),表可以是任何尺寸,不支持全文类型的索引,插入缓冲.二次写.自适应哈希索引(三个特性详细介绍见: InnoDB的三个关键特性 (http://blog.csdn.net/z702143700/article/details/46049101). 应用场景: 以INSERT.UPDATE为主的

转:由浅入深探究mysql索引结构原理、性能分析与优化

摘要: 第一部分:基础知识 第二部分:MYISAM和INNODB索引结构 1. 简单介绍B-tree B+ tree树 2. MyisAM索引结构 3. Annode索引结构 4. MyisAM索引与InnoDB索引相比较 第三部分:MYSQL优化 1.表数据类型选择 2.sql语句优化 (1)     最左前缀原则 (1.1)  能正确的利用索引 (1.2)  不能正确的利用索引 (1.3)  如果一个查询where子句中确实不需要password列,那就用“补洞”. (1.4)  like

由浅入深探究 MySQL索引结构原理、性能分析与优化

第一部分:基础知识: 索引 官方介绍索引是帮助MySQL高效获取数据的数据结构.笔者理解索引相当于一本书的目录,通过目录就知道要的资料在哪里,不用一页一页查阅找出需要的资料.关键字index --------------------- 唯一索引 强调唯一,就是索引值必须唯一,关键字unique index 创建索引: 1.create unique index 索引名 on 表名(列名); 2.alter table 表名 add unique index 索引名 (列名); 删除索引: 1.

由浅入深探究mysql索引结构原理、性能分析与优化(转)

add by zhj:原文链接已经失效了,网上看到的都是转载,向作者Benwin致敬 摘要: 第一部分:基础知识 第二部分:MYISAM和INNODB索引结构 1.简单介绍B-tree B+ tree树 2.MyisAM索引结构 3.Annode索引结构 4.MyisAM索引与InnoDB索引相比较 第三部分:MYSQL优化 1.表数据类型选择 2.sql语句优化 (1)     最左前缀原则 (1.1)  能正确的利用索引 (1.2)  不能正确的利用索引 (1.3)  如果一个查询where

【转】由浅入深探究mysql索引结构原理、性能分析与优化

摘要: 第一部分:基础知识 第二部分:MYISAM和INNODB索引结构 1.简单介绍B-tree B+ tree树 2.MyisAM索引结构 3.Annode索引结构 4.MyisAM索引与InnoDB索引相比较 第三部分:MYSQL优化 1.表数据类型选择 2.sql语句优化 (1)     最左前缀原则 (1.1)  能正确的利用索引 (1.2)  不能正确的利用索引 (1.3)  如果一个查询where子句中确实不需要password列,那就用“补洞”. (1.4)  like (2)

[转]mysql索引结构原理、性能分析与优化

第一部分:基础知识 索引 官方介绍索引是帮助MySQL高效获取数据的数据结构.笔者理解索引相当于一本书的目录,通过目录就知道要的资料在哪里, 不用一页一页查阅找出需要的资料. 唯一索引(unique index) 强调唯一,就是索引值必须唯一. 创建索引: create unique index 索引名 on 表名(列名); alter table 表名 add unique index 索引名 (列名); 删除索引: drop index 索引名 on 表名; alter table 表名 d

【mysql中myisam和innodb的区别】

单击进入源网页 要点摘要: 1.查看mysql存储引擎的状态mysql> show engines; 2.查看mysql默认的存储引擎mysql> show variables like '%storage_engine%'; 3.修改mysql默认存储引擎ALTER TABLE engineTest ENGINE = INNODB 4.创建表时设置存储引擎CREATE TABLE mytable (id int, titlechar(20)) ENGINE = INNODB 5.修改my.i