Innodb存储引擎 索引优化查询管理
Posted 我的紫霞辣辣
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Innodb存储引擎 索引优化查询管理相关的知识,希望对你有一定的参考价值。
Innodb 索引优化管理
实验环境
- 索引优化的实验效果需要在一张表中有海量数据的情况下,实验效果才会比较明显,我们在实验前需要先准备一张300万条数据的表。
# 创建表格
create table t1(
id int,
name varchar(20),
gender char(6),
email varchar(50)
);
# 创建存储过程,插入3000000条数据
delimiter $$
create procedure auto_insert1()
BEGIN
declare i int default 1;
while(i<3000000)do
insert into t1 values(i,'nana','male',concat('nana',i,'@haha'));
set i=i+1;
end while;
END$$
delimiter ;
# 查看存储过程
show create procedure auto_insert1\\G
# 调用存储过程
call auto_insert1();
查看数据文件大小
# 插入三百万条数据,大概大小为188M
[root@db01 db01]# ll -h /service/mysql/data/db01
total 189M
-rw-rw---- 1 mysql mysql 67 Jul 14 15:38 db.opt
-rw-rw---- 1 mysql mysql 8.5K Jul 14 15:39 t1.frm
-rw-rw---- 1 mysql mysql 188M Jul 14 16:06 t1.ibd
# 查看表格式内容
mysql> select * from t1 where id<3;
+------+------+--------+------------+
| id | name | gender | email |
+------+------+--------+------------+
| 1 | nana | male | nana1@haha |
| 2 | nana | male | nana2@haha |
+------+------+--------+------------+
2 rows in set (0.95 sec)
# 查看表属性
mysql> desc t1;
+--------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+--------+-------------+------+-----+---------+-------+
| id | int(11) | YES | | NULL | |
| name | varchar(20) | YES | | NULL | |
| gender | char(6) | YES | | NULL | |
| email | varchar(50) | YES | | NULL | |
+--------+-------------+------+-----+---------+-------+
4 rows in set (0.00 sec)
命中索引也未必会加速,如下所示:
关于等值查询
1. 以重复度低的字段为基础创建索引,加速效果明显
mysql> select count(id) from t1 where id = 33;
+-----------+
| count(id) |
+-----------+
| 1 |
+-----------+
1 row in set (0.83 sec)
# explain(查询优化神器)的rows值越小,查询效率越高
# explain查询sql语句的执行计划,rows为2990010,速度慢
mysql> explain select count(id) from t1 where id = 33;
+----+-------------+-------+------+---------------+------+---------+------+---------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+------+---------+-------------+
| 1 | SIMPLE | t1 | ALL | NULL | NULL | NULL | NULL | 2990010 | Using where |
+----+-------------+-------+------+---------------+------+---------+------+---------+-------------+
1 row in set (0.00 sec)
# 创建主键索引
mysql> create index xxx on t1(id);
Query OK, 0 rows affected (3.78 sec)
Records: 0 Duplicates: 0 Warnings: 0
# explain查询sql语句的执行计划,rows为1,速度快
mysql> explain select count(id) from t1 where id = 33;
+----+-------------+-------+------+---------------+------+---------+-------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+-------+------+-------------+
| 1 | SIMPLE | t1 | ref | xxx | xxx | 5 | const | 1 | Using index |
+----+-------------+-------+------+---------------+------+---------+-------+------+-------------+
1 row in set (0.00 sec)
mysql> desc t1;
+--------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+--------+-------------+------+-----+---------+-------+
| id | int(11) | YES | MUL | NULL | |
| name | varchar(20) | YES | | NULL | |
| gender | char(6) | YES | | NULL | |
| email | varchar(50) | YES | | NULL | |
+--------+-------------+------+-----+---------+-------+
4 rows in set (0.00 sec)
# 命中主键索引后查询速度得到了优化
mysql> select count(id) from t1 where id = 33;
+-----------+
| count(id) |
+-----------+
| 1 |
+-----------+
1 row in set (0.00 sec)
2. 以重复度高的字段为基础创建索引,加速效果不明显
# 查看无索引字段name的sql语句执行计划,rows为2990010,速度慢
mysql> explain select count(id) from t1 where name="nana";
+----+-------------+-------+------+---------------+------+---------+------+---------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+------+---------+-------------+
| 1 | SIMPLE | t1 | ALL | NULL | NULL | NULL | NULL | 2990010 | Using where |
+----+-------------+-------+------+---------------+------+---------+------+---------+-------------+
1 row in set (0.00 sec)
# 创建name字段的辅助索引
mysql> create index yyy on t1(name);
Query OK, 0 rows affected (5.14 sec)
Records: 0 Duplicates: 0 Warnings: 0
# 给name创建了普通索引,我们发现查看name字段的执行计划查询速度并没有得到很好的优化,rows为1495005,速度慢
mysql> explain select count(id) from t1 where name="nana";
+----+-------------+-------+------+---------------+------+---------+-------+---------+-----------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+-------+---------+-----------------------+
| 1 | SIMPLE | t1 | ref | yyy | yyy | 83 | const | 1495005 | Using index condition |
+----+-------------+-------+------+---------------+------+---------+-------+---------+-----------------------+
1 row in set (0.00 sec)
# 我们发现命中了辅助索引name字段后,查询的速度依然很慢。
# 原因是因为我们的name字段,数据全部都是nana。
# 这时候我们给name字段添加普通索引,该辅助索引的key值全部都是nana,不但没有优化查询效率,反而使查询效率变得更低了。
mysql> select count(id) from t1 where name="nana";
+-----------+
| count(id) |
+-----------+
| 2999999 |
+-----------+
1 row in set (3.73 sec)
# 我们通过explain查询sql语句的执行计划,查看name字段不等于nana的值,查询速度得到了优化,rows为2,速度快
mysql> explain select count(id) from t1 where name!="nana";
+----+-------------+-------+-------+---------------+------+---------+------+------+-----------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+---------------+------+---------+------+------+-----------------------+
| 1 | SIMPLE | t1 | range | yyy | yyy | 83 | NULL | 2 | Using index condition |
+----+-------------+-------+-------+---------------+------+---------+------+------+-----------------------+
1 row in set (0.00 sec)
# 命中索引重复度高的字段,取反的情况下,查询效率的得到了优化
mysql> select count(id) from t1 where name!="nana";
+-----------+
| count(id) |
+-----------+
| 0 |
+-----------+
1 row in set (0.00 sec)
3. 以占用空间大的字段为基础创建索引,加速效果不明显
mysql> select count(id) from t1 where email="nana1562562@haha";
+-----------+
| count(id) |
+-----------+
| 1 |
+-----------+
1 row in set (1.16 sec)
# 创建普通索引
mysql> create index zzz on t1(email);
Query OK, 0 rows affected (6.48 sec)
Records: 0 Duplicates: 0 Warnings: 0
# 以占用空间大的字段为基础创建索引,理论上加速效果是不明显的。
# 但是我们email字段的数据占用的空间不够大,所以实验效果不佳。
mysql> select count(id) from t1 where email="nana1562562@haha";
+-----------+
| count(id) |
+-----------+
| 1 |
+-----------+
1 row in set (0.00 sec)
关于等值查询结论 : 给重复度低、且占用空间小的字段值为基础构建索引!!
关于范围查询
mysql> desc t1;
+--------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+--------+-------------+------+-----+---------+-------+
| id | int(11) | YES | MUL | NULL | |
| name | varchar(20) | YES | MUL | NULL | |
| gender | char(6) | YES | | NULL | |
| email | varchar(50) | YES | MUL | NULL | |
+--------+-------------+------+-----+---------+-------+
4 rows in set (0.00 sec)
1. innodb存储引擎能够加速范围查询,但是查询范围越大,加速效果越不明显
# id>33的数据范围很大,速度慢
mysql> explain select count(id) from t1 where id>33;
+----+-------------+-------+-------+---------------+------+---------+---引擎 索引 日志查询 权限管理