常见知识整理-mysql 索引

数据库设计应该考虑的问题

在这里插入图片描述

为什么要使用索引

  1. 快速查询数据

索引的数据结构

  1. 建立二叉查找树进行二分查找
  2. 建立BTree结构进行查找
  3. 建立B+Tree结构进行查找
  4. 建立Hash结构进行查找

BTree

  1. 根节点至少包括两个孩子
  2. 树中每个节点最多含有m个孩子
  3. 除了根节点和叶子节点,其它每个节点至少有ceil(m / 2)个孩子
  4. 所有叶子节点都位于同一层
    在这里插入图片描述

B+Tree

  1. 非叶子节点的子树指针与关键字个数相同
  2. 非叶子节点的子树指针p[i],指向关键字值[k[i],k[i+1])的子树
  3. 非叶子节点仅用来索引,数据都保存在叶子节点中
  4. 所有叶子节点均有一个链指针指向下一个叶子节点
    在这里插入图片描述

B+Tree更适合用来做存储索引

  1. B+树的磁盘读写代价更低(数据只存储在叶子节点,可以减少磁盘IO)
  2. B+树的查询效率更稳定
  3. B+树更加有利于对数据库的扫描

Hash索引

查询速度理论上比B+Tree快
缺点:

  1. 仅仅能满足=in,不能使用范围查询
  2. 无法被用来避免数据的排序操作
  3. 不能利用部分索引键查询
  4. 遇到大量的Hash碰撞,性能不一定比BTree高

密集索引和稀疏索引的区别

密集索引 叶子节点保存的不仅仅是键值,还有保存了同一行中其它列的信息。密集索引还决定了表的物理排序顺序。一个表只能有一个物理排序顺序,所以一个表只能有一个密集索引
稀疏索引 叶子节点仅保存了键位信息和主键信息,需要通过主键索引再查询到数据。

InnoDB

  1. 若一个主键被定义,该主键则作为密集索引
  2. 若没有主键被定义,该表的第一个唯一非空索引则作为密集索引
  3. 若不满足以上条件,Innodb内部会生成一个隐藏的主键(密集索引
  4. 非主键索引存储相关键位和其对应的主键值,包含两次查找
    InnoDB 密集索引示意图
    MyISAM稀疏索引示意图

如何定位并优化慢查询sql

  1. 根据慢日志定位慢查询SQL
  2. 使用explain等工具分析SQL
  3. 尽量修改SQL或者尽量让SQL走索引

查询跟慢日志相关的配置信息(基于mysql 8.0.x)

SHOW VARIABLES LIKE '%query%'

显示结果如下

Variable_name                 Value                                            
----------------------------  -------------------------------------------------
binlog_rows_query_log_events  OFF                                              
ft_query_expansion_limit      20                                               
have_query_cache              NO                                               
long_query_time               1.000000                                         
query_alloc_block_size        8192                                             
query_prealloc_size           8192                                             
slow_query_log                ON                                               
slow_query_log_file           /var/lib/mysql/izwz99rnmfr0cdntpgsfr9z-slow.log  

slow_query_log 为ON表示已经开启了慢日志
slow_query_log_file 为慢日志文件路径
long_query_time 表示多长时间被认为是慢SQL,单位微妙(us) 1.000000us = 1s

打开慢查询日志
如果slow_query_log为OFF则未打开慢日志,如下打开可以打开

SET GLOBAL slow_query_log = ON

修改被认为是慢查询的耗时

SET GLOBAL long_query_time = 1; #单位1s
SET GLOBAL long_query_time = 0.8; #单位0.8s = 800ms

修改过后客户端需要重连,才能生效,并查看修改后的结果,并且mysql重启之后,会恢复默认认值。可以通过修改mysql 配置文件永久生效

查询被统计的慢查询次数

SHOW STATUS LIKE '%slow_queries%'

只是显示当前连接的慢查询次数,重连之后恢复为 0

在mysql服务器查看慢日志文件

扫描二维码关注公众号,回复: 12822992 查看本文章
# Time: 2021-02-22T13:39:46.688722Z
# User@Host: root[root] @  [139.226.12.65]  Id:   201
# Query_time: 1.006213  Lock_time: 0.195229 Rows_sent: 0  Rows_examined: 0
use lwl_registry;
SET timestamp=1614001185;
select * from order_info where pwd = '122'

Query_time为本次查询耗时

通过explain分析sql语句

通过explain可以查看sql有没有利用到索引

EXPLAIN SELECT * FROM order_info WHERE username = '122'

显示结果如下

    id  select_type  table       partitions  type    possible_keys  key     key_len  ref       rows  filtered  Extra        
------  -----------  ----------  ----------  ------  -------------  ------  -------  ------  ------  --------  -------------
     1  SIMPLE       order_info  (NULL)      ALL     (NULL)         (NULL)  (NULL)   (NULL)  360772     10.00  Using where  

type:表示查找到数据行的方式,性能排序从高到低依次为:
system > const > eq_ref > ref > fulltext > ref_or_null > index_merge > unique_subquery > index_subquery > range > index > all

indexall 表示本次查询走的是全表扫描,如果慢查询语句中EXPLAIN结果是这两个值,则需要考虑优化

Extra:如果出现如下2项的值,则意味着mysql根本没有使用索引,需要考虑优化

Extra值 说明
Using filesort 表示MySQL会对结果使用一个外部索引排序,而不是从表里按索引依序读到相关内容,可能在内存或磁盘上进行排序。
MySQL中无法利用索引完成的排序操作称为文件排序
Using temporary 表示mysq在对查询结果排序时使用临时表。常见于排序order by和分组查询group by

常见优化方案:

  1. 如果业务允许,可以通过使用已有的索引字段查询。
  2. 适当的添加索引
    alter table order_info add index idx_name(username)
    
  3. 利用索引字段排序
  4. 索引总结
    MySQL只对以下操作符才使用索引,<,<=,=,>=,between and,like 非%开头使用索引, in可能走索引可能不走,!=不走索引,理论上每张表可创建16个索引。
  5. MySQL会对允许null列也加上索引,但只会对is null``的查询条件生效

问题:假如InnoDB中表中有id主键索引,并且有个不为空的唯一索引sessionId,那么通过count(id)统计数据条数时,会利用到哪个索引字段?

EXPLAIN SELECT COUNT(id) FROM `client`

答案:会利用不为空的唯一索引sessionId,结果如下:
在这里插入图片描述
原因: 查询优化器会选用最优的索引,因为InnoDB中主键使用的聚集索引,叶子节点中含有其它列的数据,需要读取更多的数据。而sessionId不为空,且是非聚集索引,只含有索引字段和主键,数据量小,读取快。

强制走索引
在这里插入图片描述
如果有where条件,则会利用条件中的索引

SELECT COUNT(id) FROM `client` WHERE id = 39  #走主键索引
SELECT COUNT(id) FROM `client` WHERE session_id = 1427325133344736216 #走唯一索引

联合(组合)索引最左匹配原则的原因

  1. 组合索引,最左匹配原则,mysql会一直向右匹配,直到遇到范围查询(><betweenlike)就停止匹配。例如组合索引(a,b,c,d) 查询条件 where a=3 and b=4 and c>5 and d = 6,则d用不到索引。
  2. =in可以乱序,例如组合索引(a,b,c) 查询条件 where a=3 and c=5 and b=4 即使查询条件不是abc的顺序,但是经过查询优化器优化后都可以走索引. 但是 where c=5 and b=4 不满足最左匹配,无法走索引

最左匹配原则的原因: 因为第二个字段的排序是在第一个字段基础上排序,单独以第二个字段来看是无序的。

索引是建立越多越好么?

  1. 数据量小的表不需要建立索引,建立索引会增加额外的索引开销
  2. 数据变更需要维护索引,因此更多的索引意味着更多的维护成本
  3. 更多的索引意味着需要很多的空间

猜你喜欢

转载自blog.csdn.net/u013202238/article/details/113934806
今日推荐