索引的作用
类似于一本书中的目录,起到优化查询的作用
索引的分类(算法)
B树(Btree) 默认使用的索引 B-tree B+tree B*tree
R树
Hash
FullText 全文索引
GIS索引
Btree索引算法演变
Btree索引 在功能上分离
a.管理员选择一个列创建辅助索引
b.Mysql会自动将此列的值,取出来
c.将此列值进行自动排序
d.将排好序的数据,均匀的存储到索引的叶子节点
e.生成枝节点和跟节点
1.辅助索引(二级索引)
a.提取索引列的所有值,进行排序
b.将排好序的值,均匀的存放在叶子节点,进一步生成枝节点和根节点
c.在叶子节点中的值,都会对应存储主建ID
2.聚集索引
a.mysql会自动选择主键作为聚集索引列,没有主键会选择唯一键,如果都没有会生成隐藏的
b.mysql进行存储数据时,会按照聚集索引列值得的顺序,有序存储数据行
c.聚集索引直接将原表数据页,作为叶子节点,然后提取聚集索引列向上生成枝节点和根节点
聚集索引和辅助索引的区别
1.表中任何一个列都可以创建辅助索引,在你有需要的时候,只要名字不同即可
2.在一张表中,聚集索引只能有一个,一般是主键
3.辅助索引,叶子节点只存储索引列的有序值+聚集索引列值
4.聚集索引,叶子节点存储的是有序的整行数据
5.mysql的表数据存储是聚集索引组织表
辅助索引细分
1.单列辅助索引
2.联合索引(覆盖索引)
3.唯一索引
索引树高度
1.索引树高度应当月底月好,一般维持在3-4层
2.数据行数较多
索引的命令操作
查询索引
mysql> desc city;
+-------------+----------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------+----------+------+-----+---------+----------------+
| ID | int(11) | NO | PRI | NULL | auto_increment |
| Name | char(35) | NO | | | |
| CountryCode | char(3) | NO | MUL | | |
| District | char(20) | NO | | | |
| Population | int(11) | NO | | 0 | |
+-------------+----------+------+-----+---------+----------------+
5 rows in set (0.00 sec)
PRI 主键索引
MUL 辅助索引
UNI 唯一索引
查看索引详细信息
mysql> show index from city;
+-------+------------+-------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+-------+------------+-------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| city | 0 | PRIMARY | 1 | ID | A | 4188 | NULL | NULL | | BTREE | | |
| city | 1 | CountryCode | 1 | CountryCode | A | 232 | NULL | NULL | | BTREE | | |
+-------+------------+-------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
2 rows in set (0.00 sec)
创建单列辅助索引(锁表,或者ptosc工具)
mysql> alter table city add index idx_name(name);
创建联合索引(多列辅助)
mysql> alter table city add index idx_c_p(countrycode,population);
创建唯一索引(不能有重复值)
mysql> alter table city add unique index uidx_dis(district);
ERROR 1062 (23000): Duplicate entry 'Zuid-Holland' for key 'uidx_dis'
这就是 有重复值
统计多少个重复值
mysql> select count(distinct district) from city;
+--------------------------+
| count(distinct district) |
+--------------------------+
| 1367 |
+--------------------------+
1 row in set (0.00 sec)
前缀索引(前5个)
mysql> alter table city add index idx_dis(district(5));
删除索引
查看索引名字
mysql> show index from city;
删除
mysql> alter table city drop index idx_dis;
执行计划分析
作用:将优化器 选择后的执行计划 截取出来,便于管理判断语句执行效率
获取执行计划:
desc sql语句
explain sql语句
desc select * from test.t100w where k2='MN89';
+----+-------------+-------+------------+------+---------------+------+---------+------+---------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+------+---------+------+---------+----------+-------------+
| 1 | SIMPLE | t100w | NULL | ALL | NULL | NULL | NULL | NULL | 1027638 | 10.00 | Using where |
+----+-------------+-------+------------+------+---------------+------+---------+------+---------+----------+-------------+
1 row in set, 1 warning (0.00 sec)
explain 与desc 是一样的
mysql> explain select * from test.t100w where k2='MN89';
+----+-------------+-------+------------+------+---------------+------+---------+------+---------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+------+---------+------+---------+----------+-------------+
| 1 | SIMPLE | t100w | NULL | ALL | NULL | NULL | NULL | NULL | 1027638 | 10.00 | Using where |
+----+-------------+-------+------------+------+---------------+------+---------+------+---------+----------+-------------+
1 row in set, 1 warning (0.00 sec)
分析执行计划
mysql> explain select * from test.t100w where k2='MN89';
+----+-------------+-------+------------+------+---------------+------+---------+------+---------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+------+---------+------+---------+----------+-------------+
| 1 | SIMPLE | t100w | NULL | ALL | NULL | NULL | NULL | NULL | 1027638 | 10.00 | Using where |
+----+-------------+-------+------------+------+---------------+------+---------+------+---------+----------+-------------+
1 row in set, 1 warning (0.00 sec)
table 表名
type 查询的类型
全表扫描:ALL
索引扫描:index,range,ref,eq_ref,const(system),null (从左到右 性能变好)
index:全索引扫描 desc select id from city;
range:索引范围扫描 desc select * from city id>2000;
ref:辅助索引等值查询
eq_ref: 多表连接时,子表使用主建列或唯一键列作为连接条件
const(system):主键或者唯一键的等值查询 desc select * from city where id=100;
null 不需要回表查询: select * from student weher tel='111111';没有查询到
对于辅助索引来讲 != 和not in等语句是不走索引的
对于主键列来讲 !=和not in等语句是走range
possible_key 可能用到的索引 desc select * from city where countrycode != 'CHN';
key :真正选择了那个索引
key_le:索引覆盖长度
extr:Extra:using filesort 有额外排序的情况,索引应用不是特别合理 oreder by ,group by,distinct,union,
压力测试(100w.sql语句)
use test;
source /tmp/t100w.sql
mysql> select count(*) from t100w;
+----------+
| count(*) |
+----------+
| 1030345 |
+----------+
1 row in set (0.30 sec)
mysql> select * from t100w limit 10;
+------+--------+------+------+---------------------+
| id | num | k1 | k2 | dt |
+------+--------+------+------+---------------------+
| 1 | 56914 | Hd | MN89 | 2019-07-09 16:01:41 |
| 2 | 542219 | tx | bc45 | 2019-07-09 16:01:41 |
| 3 | 944336 | 6i | XYPQ | 2019-07-09 16:01:41 |
| 4 | 137325 | PK | 34VW | 2019-07-09 16:01:41 |
| 5 | 81318 | wz | 67KL | 2019-07-09 16:01:41 |
| 6 | 574174 | LZ | wxuv | 2019-07-09 16:01:41 |
| 7 | 146558 | ZG | fg23 | 2019-07-09 16:01:41 |
| 8 | 649971 | e4 | ABxy | 2019-07-09 16:01:41 |
| 9 | 94891 | ey | YZ34 | 2019-07-09 16:01:41 |
| 10 | 22211 | Sv | HITU | 2019-07-09 16:01:41 |
+------+--------+------+------+---------------------+
10 rows in set (0.00 sec)
未做优化之前测试
选择一个值MN89
100个用户2000个查询
# mysqlslap --defaults-file=/etc/my.cnf --concurrency=100 --iterations=1 --create-schema='test' --query="select * from test.t100w where k2='MN89'" engine=innodb--number-of-queries=2000 -uroot -p123456 -verbose
mysqlslap: [Warning] Using a password on the command line interface can be insecure.
Benchmark
Running for engine rbose
Average number of seconds to run all queries: 39.887 seconds
Minimum number of seconds to run all queries: 39.887 seconds
Maximum number of seconds to run all queries: 39.887 seconds
Number of clients running queries: 100
Average number of queries per client: 1
加索引后在测试
mysql> alter table t100w add index idx_k2(k2);
mysql> desc t100w;
+-------+-----------+------+-----+-------------------+-----------------------------+
| Field | Type | Null | Key | Default | Extra |
+-------+-----------+------+-----+-------------------+-----------------------------+
| id | int(11) | YES | | NULL | |
| num | int(11) | YES | | NULL | |
| k1 | char(2) | YES | | NULL | |
| k2 | char(4) | YES | MUL | NULL | |
| dt | timestamp | NO | | CURRENT_TIMESTAMP | on update CURRENT_TIMESTAMP |
+-------+-----------+------+-----+-------------------+-----------------------------+
5 rows in set (0.00 sec)
在测压测
mysqlslap --defaults-file=/etc/my.cnf --concurrency=100 --iterations=1 --create-schema='test' --query="select * from test.t100w where k2='MN89'" engine=innodb--number-of-queries=2000 -uroot -p123456 -verbose
mysqlslap: [Warning] Using a password on the command line interface can be insecure.
Benchmark
Running for engine rbose
Average number of seconds to run all queries: 0.360 seconds
Minimum number of seconds to run all queries: 0.360 seconds
Maximum number of seconds to run all queries: 0.360 seconds
Number of clients running queries: 100
Average number of queries per client: 1
公司业务慢,进行分析
情况一 :应急性的慢,突然卡了
1.show processlist; 查看当前连接会话以及做的事情,获取到导致数据库hang的语句
2.explain 分析sql的执行计划,有没有走索引,索引的类型情况
3.创建索引,更改语句
情况二:一段时间慢(持续性)
1.记录慢日志slowlog,分析slowlog
2.explain 分析SQL的执行计划,有没有走索引,索引的情况类型
3.创建索引,改语句
索引应用规范
建立索引的原则(DBA运维规范)
1.必须要有主键,一般是无关列,自增长
2.经常做where条件列 order by,group by ,join on ,distinct的条件
3.最好使用唯一值多的列作为联合索引前导列,其他按照联合索引 优化细节来做
4.列值长度较长的索引列,我们建议使用前缀索引
5.降低索引条目,一方面不要创建没用索引,不常用的索引清理,percona toolkit(xxxx)
6.索引维护要避开业务繁忙期
7.小表不创建索引
不走索引的情况(开发规范)
1.没有查询条件,或者查询条件没有建立索引
2.查询结果集是原表中的大部分数据,应该是25%以上
3.索引本身失效,统计数据不真实
4.查询条件使用函数在索引列上,或者对索引列进行运算,运算包括(+,-,*,/,!等)
5.隐式转换导致索引失败
6.<>,not in 不走索引(辅助索引)
7.like "%aa" 百分号在最前面不走
8.联合索引