Mysql-索引

索引的作用

类似于一本书中的目录,起到优化查询的作用

索引的分类(算法)

B树(Btree) 默认使用的索引 B-tree B+tree B*tree
R树
Hash
FullText 全文索引
GIS索引

Btree索引算法演变

image.png

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.联合索引

你可能感兴趣的:(Mysql-索引)