索引基础知识总结及常见索引优化手段


一、索引简介

什么是索引?
  • MySQL官方对索引的定义为:索引(Index)是帮助MySQL高效获取数据的数据结构。

  • 可以简单理解为“排好序的快速查找数据结构”。

  • 一般来说索引本身也很大,不可能全部存储在内存中,因此索引往往以索引文件的形式存储的磁盘上

索引的优点
  • 类似大学图书馆建书目索引,提高数据检索的效率,降低数据库的IO成本

  • 通过索引列对数据进行排序,降低数据排序的成本,降低了CPU的消耗

索引的缺点
  • 虽然索引大大提高了查询速度,同时却会降低更新表的速度,如对表进行INSERT、UPDATE和DELETE。因为更新表时,MySQL不仅要保存数据,还要保存一下索引文件每次更新添加了索引列的字段,都会调整因为更新所带来的键值变化后的索引信息

  • 实际上索引也是一张表,该表保存了主键与索引字段,并指向实体表的记录,所以索引列也是要占用空间的

索引结构

MySQL支持诸多存储引擎,而各种存储引擎对索引的支持也各不相同,因此MySQL数据库支持多种索引类型,如BTree索引,哈希索引,全文索引等等。

下面简单介绍下BTree索引、B+Tree索引、聚簇索引与非聚簇索引

  • BTree索引


  • B+Tree索引

InnoDB使用B+Tree作为索引结构


拓展:B+Tree与B-Tree 的区别

1)B树的关键字和记录是放在一起的,叶子节点可以看作外部节点,不包含任何信息;B+树的非叶子节点中只有关键字和指向下一个节点的索引,记录只放在叶子节点中。
2)在B树中,越靠近根节点的记录查找时间越快,只要找到关键字即可确定记录的存在;而B+树中每个记录的查找时间基本是一样的,都需要从根节点走到叶子节点,而且在叶子节点中还要再比较关键字。从这个角度看B树的性能好像要比B+树好,而在实际应用中却是B+树的性能要好些。因为B+树的非叶子节点不存放实际的数据,这样每个节点可容纳的元素个数比B树多,树高比B树小,这样带来的好处是减少磁盘访问次数。尽管B+树找到一个记录所需的比较次数要比B树多,但是一次磁盘访问的时间相当于成百上千次内存比较的时间,因此实际中B+树的性能可能还会好些,而且B+树的叶子节点使用指针连接在一起,方便顺序遍历(例如查看一个目录下的所有文件,一个表中的所有记录等),这也是很多数据库和文件系统使用B+树的缘故。

思考:为什么说B+树比B树更适合实际应用中操作系统的文件索引和数据库索引?

1) B+树的磁盘读写代价更低
B+树的内部结点并没有指向关键字具体信息的指针。因此其内部结点相对B 树更小。如果把所有同一内部结点的关键字存放在同一盘块中,那么盘块所能容纳的关键字数量也越多。一次性读入内存中的需要查找的关键字也就越多。相对来说IO读写次数也就降低了。
2) B+树的查询效率更加稳定
由于非终结点并不是最终指向文件内容的结点,而只是叶子结点中关键字的索引。所以任何关键字的查找必须走一条从根结点到叶子结点的路。所有关键字查询的路径长度相同,导致每一个数据的查询效率相当。

  • 聚簇索引与非聚簇索引

聚簇索引并不是一种单独的索引类型,而是一种数据存储方式。
术语‘聚簇’表示数据行和相邻的键值聚簇的存储在一起。
如下图,左侧的索引就是聚簇索引,因为数据行在磁盘的排列和索引排序保持一致。


聚簇索引的好处:

按照聚簇索引排列顺序,查询显示一定范围数据的时候,由于数据都是紧密相连,数据库不不用从多个数据块中提取数据,所以节省了大量的io操作。

聚簇索引的限制:

对于mysql数据库目前只有innodb数据引擎支持聚簇索引,而Myisam并不支持聚簇索引。
由于数据物理存储排序方式只能有一种,所以每个Mysql的表只能有一个聚簇索引。一般情况下就是该表的主键。
为了充分利用聚簇索引的聚簇的特性,所以innodb表的主键列尽量选用有序的顺序id,而不建议用无序的id,比如uuid这种。

MySQL索引分类
  • 单值索引

即一个索引只包含单个列,一个表可以有多个单列索引
单独建单值索引:
CREATE INDEX idx_customer_name ON customer(customer_name);
删除索引:
DROP INDEX idx_customer_name on customer;

  • 唯一索引

索引列的值必须唯一,但允许有空值
单独建唯一索引:
CREATE UNIQUE INDEX idx_customer_no ON customer(customer_no);
删除索引:
DROP INDEX idx_customer_no on customer;

  • 主键索引

设定为主键后数据库会自动建立索引,innodb为聚簇索引
单独建主键索引:
ALTER TABLE customer add PRIMARY KEY customer(customer_no);
删除建主键索引:
ALTER TABLE customer drop PRIMARY KEY;

  • 复合索引

即一个索引包含多个列
单独建索引:
CREATE INDEX idx_no_name ON customer(customer_no,customer_name);
删除索引:
DROP INDEX idx_no_name on customer;

  • 基本语法总结

创建:
CREATE [UNIQUE ] INDEX [indexName] ON table_name(column));
删除:
DROP INDEX [indexName] ON mytable;
查看:
SHOW INDEX FROM table_name;
还可以使用ALTER命令

哪些情况需要创建索引?☆
  • 主键自动建立唯一索引

  • 频繁作为查询条件的字段应该创建索引

  • 查询中与其它表关联的字段,外键关系建立索引

  • 单键/组合索引的选择问题, 组合索引性价比更高

  • 查询中排序的字段,排序字段若通过索引去访问将大大提高排序速度

  • 查询中统计或者分组字段

哪些情况不要创建索引?☆
  • 表记录太少

  • 经常增删改的表或者字段

虽然提高了查询速度,但是会降低更新表的速度,如对表进行INSERT、UPDATE和DELETE。更新表时,MySQL不仅要保存数据,还要保存一下索引文件。

  • Where条件里用不到的字段不创建索引

  • 过滤性不好的不适合建索引

二、借助Explain进行性能分析

Explain是什么(查看执行计划)
  • 使用EXPLAIN关键字可以模拟优化器执行SQL查询语句,从而知道MySQL是如何处理你的SQL语句的。分析你的查询语句或是表结构的性能瓶颈。

Explain用途
  • 查看表的读取顺序

  • 查看哪些索引可以使用

  • 查看数据读取操作的操作类型

  • 查看哪些索引被实际使用

  • 查看表之间的引用

  • 查看每张表有多少行被物理查询

Explain使用方法
  • Explain + SQL语句

  • 执行计划包含的信息:


各字段解释:☆
  • id

select查询的序列号,包含一组数字,表示查询中执行select子句或操作表的顺序
id相同,执行顺序由上至下


id不同,如果是子查询,id的序号会递增,id值越大优先级越高,越先被执行


id相同不同,同时存在


每个id号码,表示一趟独立的查询。一个sql的查询趟数越少越好。

  • select_type

查询的类型,主要是用于区别普通查询、联合查询、子查询等的复杂查询


  • table

    显示这一行的数据是关于哪张表的

  • partitions

    代表分区表中的命中情况,非分区表,该项为null

  • type

type显示的是访问类型,是较为重要的一个指标,结果值从最好到最坏依次是:
system > const > eq_ref > ref > fulltext > ref_or_null > index_merge > unique_subquery > index_subquery > range > index > ALL一般来说,得保证查询至少达到range级别,最好能达到ref。



  • possible_keys

    显示可能应用在这张表中的索引,一个或多个。
    查询涉及到的字段上若存在索引,则该索引将被列出,但不一定被查询实际使用。

  • key

    实际使用的索引。如果为NULL,则没有使用索引。查询中若使用了覆盖索引,则该索引和查询的select字段重叠。

  • key_len

表示索引中使用的字节数,可通过该列计算查询中使用的索引的长度。key_len字段能够帮你检查是否充分的利用了索引。


  • ref

    显示索引的哪一列被使用了,如果可能的话,是一个常数。哪些列或常量被用于查找索引列上的值

  • rows

    rows列显示MySQL认为它执行查询时必须检查的行数。rows越小,性能越高。

  • filtered

    这个字段表示存储引擎返回的数据在server层过滤后,剩下多少满足查询的记录数量的比例,注意是百分比,不是具体记录数

  • Extra

包含不适合在其他列中显示但十分重要的额外信息


三、查询优化策略☆

单表优化策略
  • 全列匹配

  • 最左前缀法则

    如果索引了多列,要遵守最左前缀法则。指的是查询从索引的最左前列开始命中并且不跳过索引中的列。

    注意:由于MySQL的查询优化器会自动调整where子句的条件顺序以使用适合的索引。

  • 不要在索引列上做任何操作(计算、函数、(自动or手动)类型转换),会导致索引失效而转向全表扫描

  • 存储引擎不能使用索引中范围条件右边的列

  • mysql 在使用不等于(!= 或者<>)的时候无法使用索引,会导致全表扫描

  • is not null 无法使用索引,但is null是可以使用索引的

  • 若like以通配符开头('%abc…'),则mysql索引失效,会变成全表扫描的操作

  • 字符串不加单引号索引失效

  • 练习


  • 对于单键索引,尽量选择针对当前query过滤性更好的索引

  • 在选择组合索引的时候,当前Query中过滤性最好的字段在索引字段顺序中,位置越靠前越好。

  • 在选择组合索引的时候,尽量选择可以能够包含当前query中的where字句中更多字段的索引

  • 在选择组合索引的时候,如果某个字段可能出现范围查询时,尽量把这个字段放在索引次序的最后面

  • 书写sql语句时,尽量避免造成索引失效的情况

多表关联查询优化策略
  • 保证被驱动表的join字段已经被索引

  • left join 时,选择小表作为驱动表,大表作为被驱动表。

  • inner join 时,mysql会自己帮你把小结果集的表选为驱动表。

  • 子查询尽量不要放在被驱动表,有可能使用不到索引。

  • 能够直接多表关联的尽量直接关联,不用子查询。

子查询优化
  • 尽量不要使用not in或者not exists。用left outer join on xxx is null 替代。

排序分组优化
  • ORDER BY子句,尽量使用Index方式排序,避免使用FileSort方式排序

  • 当范围条件是group by 或者 order by 的字段出现二选一时 ,优先观察条件字段的过滤数量,如果过滤的数据足够多,而需要排序的数据并不多时,优先把索引放在范围字段上。反之,亦然。

  • 如果不在索引列上,filesort有两种算法:
    mysql就要启动双路排序和单路排序


  • GROUP BY关键字优化

group by 使用索引的原则几乎跟order by一致 ,唯一区别是groupby 即使没有过滤条件用到索引,也可以直接使用索引。


本文简单总结了下MySQL常见常用的索引优化策略


—END—

分享知识|一起成长


【DragonWell】

mysql单列索引和多列索引_浅谈MySQL索引优化相关推荐

  1. 支付宝的数据库是MySQL变种_浅谈MySql的储存引擎(表类型)

    浅谈mysql的存储引擎(表类型) 什么是MySql数据库 通常意义上,数据库也就是数据的集合,具体到计算机上数据库可以是存储器上一些文件的集合或者一些内存数据的集合. 我们通常说的MySql数据库, ...

  2. mysql revoke 授权_浅谈MySQL中授权(grant)和撤销授权(revoke)用法详解

    MySQL 赋予用户权限命令的简单格式可概括为: grant 权限 on 数据库对象 to 用户 一.grant 普通数据用户,查询.插入.更新.删除 数据库中所有表数据的权利 grant selec ...

  3. MySQL子查询的优缺点_浅谈mysql的子查询

    浅谈mysql的子查询 mysql的子查询的优化一直不是很友好,一直有受业界批评比较多,也是我在sql优化中遇到过最多的问题之一,你可以点击这里 ,这里来获得一些信息,mysql在处理子查询的时候,会 ...

  4. mysql 用户通配符_浅谈mysql通配符进行模糊查询的实现方法

    在mysql数据库中,当我们需要模糊查询的时候 ,我们会使用到通配符. 首先我们来了解一下2个概念,一个是操作符,一个是通配符. 操作符 like就是SQL语句中的操作符,它的作用是指示在SQL语句后 ...

  5. mysql declare与set的区别_浅谈MySQL存储过程中declare和set定义变量的区别

    在存储过程中常看到declare定义的变量和@set定义的变量.简单的来说,declare定义的类似是局部变量,@set定义的类似全局变量. 1.declare定义的变量类似java类中的局部变量,仅 ...

  6. mysql维护计划任务_浅谈MySQL event 计划任务

    一.查看event是否开启 show variables like '%sche%'; set global event_scheduler =1; 二. -- 设置时区并设置计划事件调度器开启,也可 ...

  7. mysql 计划任务消耗_浅谈MySQL event 计划任务

    一.查看event是否开启 show variables like '%sche%'; set global event_scheduler =1; 二. -- 设置时区并设置计划事件调度器开启,也可 ...

  8. mysql事务的管理方式_浅谈MySQL事务管理(基础)

    本篇文章给大家带来的内容是浅谈MySQL事务管理(基础),有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助.事务处理用来维护数据库等完整性,保证mysql操作要么成功,要么失败(myisa ...

  9. mysql存储过程set什么意思_浅谈MySQL存储过程中declare和set定义变量的区别

    在存储过程中常看到declare定义的变量和@set定义的变量.简单的来说,declare定义的类似是局部变量,@set定义的类似全局变量. 1.declare定义的变量类似java类中的局部变量,仅 ...

最新文章

  1. JavaEE SSH集成框架(两) struts2 本地加载dtd文件,action组态
  2. OpenVINO FPS也可以达100帧
  3. Centos基础优化
  4. Object类有哪些公用方法?
  5. bzoj 4300 绝世好题 —— 思路
  6. openssl java aes_请问如何使用AES对使用OpenSSL命令加密的Java文件进行解密?
  7. Js数组去重的多种方法
  8. XP远程桌面连接网络无法验证解决办法
  9. android自定义View之仿携程首页点击缩放ImageView
  10. Ubuntu16.04,16.05系列最全深度美化教你如何变得有格调
  11. android状态栏半透明灰色,快速解决Android7.0下沉浸式状态栏变灰的问题
  12. 【毕设资料】 Web版RSS阅读器(一)——dom4j读取xml(opml)文件
  13. matepadpro升级鸿蒙,鸿蒙OS下月推出!MatePad Pro升级EMUI 11,提前预演
  14. c语言学习——设圆半径r = 1.5,圆柱高h = 3,求圆周长,圆面积,圆球表面积,圆球体积,圆柱体积
  15. HTML5中weight属性的作用,css font-weight属性怎么用
  16. 不同产品生命周期的营销策略
  17. 蛋糕究竟是怎样做大的
  18. 树莓派-linux内核编译
  19. MOS管中的N型/P型是什么意思?沟道呢?金属氧化物膜又是什么
  20. 体育竞技游戏的团队AI

热门文章

  1. 强化学习(五)---基于模型的强化学习实战
  2. MATLAB实战系列(三十七)-MATLAB基于PQ解耦风电场并网潮流计算
  3. Hadoop在Ubuntu下的安装配置(配置成功)
  4. 4路组相连cache设计_移动图形处理器的纹理Cache设计
  5. Python编程基础:第三节 字符串方法String Methods
  6. 【LeetCode从零单排】No.169 Majority Element(hashmap用法)
  7. 如何在github发布个人网站或开源项目-手把手教您制作并发布个人网站或主页(二)
  8. 深入剖析神秘的“零拷贝”
  9. lucene-solr本地调试方法
  10. @Query Annotation in Spring Data JPA--转