mysql 隐藏中间四位_MySQL知识体系——索引
本文直切主题,针对InnoDB引擎描述索引及优化策略。在开始之前,需要读者了解:
- 二叉查找树(包括2-3查找树、红黑树等数据结构)
- MySQL的InnoDB引擎基础知识
索引初探
要了解索引,当然要了解其数据结构。树有很多应用,流行的用法之一是包括UNIX和DOS在内的许多常用操作系统中的目录结构,二叉查找树又是Java中两种集合类TreeSet和TreeMap实现的基础。那么对于数据库,I/O是其性能瓶颈所在,减少树的深度是直接有效的,BTree和B+Tree应运而生。
BTree和B+Tree(Balance-Tree,多路搜索树,非二叉)
BTree
BTree是一种查找树,如同二叉查找树,红黑树等,都是为提高查找效率而产生的,BTree也是如此,可以把它看做二叉查找树的优化升级。二叉查找树的特点是每个非叶节点都最多只有两个子节点,但是当数据量非常大时,二叉查找树的深度过深,搜索算法自根节点向下搜索时,需要访问的节点也就变的相当多。如果这些节点存储在外存储器(磁盘)中,每访问一个节点,相当于就是进行了一次I/O操作,随着树高度的增加,频繁的I/O操作一定会降低查询的效率。BTree改二叉为多叉,每个节点存储更多的指针信息,以此达到减少树的深度、降低I/O操作数。
使用BTree结构可以显著减少定位记录时所经历的中间过程,从而加快存取速度。
定义(对于一个m阶BTree)
- 根节点至少有两个子节点(除非根结点为叶节点)
- 每个节点有m-1个关键字,并且以升序排列
- 位于 m-1和m 关键字的子节点的值位于 m-1和m 关键字对应的值之间
- 其它节点至少有m/2个子节点
特性
- 关键字集合分布在整棵树中;
- 任何一个关键字出现且只出现在一个节点中;
- 搜索有可能在非叶节点结束;
- 其搜索性能等价于在关键字全集内做一次二分查找;
- 自动层次控制。
B+Tree
InnoDB 存储引擎在绝大多数情况下使用B+Tree建立索引,B+Tree也是关系型数据库中最为常用和有效的索引结构,但是B+Tree索引并不能找到一个给定键对应的具体值,它只能找到数据行对应的页,然后正如上一节所提到的,数据库把整个页读入到内存中,并在内存中查找具体的数据行。
定义(其定义基本与 BTree同,除了:)
- 所有叶节点之间都有一个链指针;
- 所有关键字都在叶子结点出现;
- 非叶子节点只存储键值信息,数据记录都存放在叶节点中。
特性
- 单节点可以存储更多的元素,使得查询磁盘IO次数更少,更加高效的单元素查找;
- 所有查询都要查找到叶子节点,查询性能稳定;
- 叶子节点会包含所有的关键字,以及指向数据记录的指针,并且叶子节点本身是根据关键字的大小从小到大顺序链接,范围查找性能更优。
区别
B+Tree是BTree的一种变形树,它与BTree的差异在于:
- B+Tree只有达到叶子结点才命中(BTree可以在非叶子结点命中),其性能也等价于在关键字全集做一次二分查找;
- BTree树每个叶子节点都有双向指针;
- BTree分支节点和叶节点均保存记录的关键码和记录的指针;B+Tree分支节点只保存记录关键码的复制,无记录指针。所有记录都集中在叶节点一层,并且叶节点可以构成一维线性表,便于连续访问和范围查询。
聚集索引和辅助索引
数据库中的 B+Tree索引可以分为聚集索引(clustered index)和辅助索引(secondary index),它们之间的最大区别就是,聚集索引中存放着一条行记录的全部信息,而辅助索引中只包含索引列和一个用于查找对应行记录的“书签”。即在数据库的聚集索引中,叶子节点直接包含卫星数据。在辅助索引(NonClustered Index)中,叶节点带有指向卫星数据的指针。
聚集索引
InnoDB使用了聚集索引存储数据。
与非聚集索引的区别则是,聚集索引既存储了索引,也存储了行值。当一个表有一个聚集索引,它的数据是存储在索引的叶子页(leaf pages)上的。因此可以说InnoDB是基于索引的表。
当我们使用聚集索引对表中的数据进行检索时,可以直接获得聚集索引所对应的整条行记录数据所在的页,不需要进行第二次操作。
索引的建立规则
- 如果一个主键被定义了,那么这个主键就是作为聚集索引
- 如果没有主键被定义,那么该表的第一个唯一非空索引被作为聚集索引
- 如果没有主键也没有合适的唯一索引,那么InnoDB内部会生成一个隐藏的主键作为聚集索引,这个隐藏的主键是一个6个字节的列,改列的值会随着数据的插入自增
辅助索引
辅助索引,也叫做非聚集索引,叶节点不包含行的全部数据。除了包含关键字外,还包含了一个标记,这个标记用来告诉InnoDB引擎从哪里可以找到与索引相对应的行数据。由于InnoDB引擎是索引组织表,因此,这个标记就是相应的行数据的聚集索引关键字。
辅助索引的存在并不影响数据在聚集索引中的组织,因此一个表可以有多个辅助索引。
使用辅助索引查找一条表记录的过程:通过辅助索引查找到对应的关键字,最后在聚集索引中使用关键字获取对应的行记录,这也是通常情况下行记录的查找方式。
使用建议
聚集索引的优先选择列
- 含有大量非重复值的列
- 使用 between,>或
- 需要经常排序的列,列顺序和最常用的排序一致
- 返回大量结果集的查询
- 经常被 join 的列
不建议的聚集索引列
- 修改频繁的列
- 低选择性的列,如性别
- 新增内容太过离散随机的列
规范与建议
- 命名规则:表名_字段名
- 需要加索引的字段,要在where条件中
- 如果where条件中是OR关系,加索引不起作用
- 能用小类型别用大类型字段
- 索引 key_len 长度过大,也会影响 SQL 性能。所以尽量不默认 null,会占用字节、索引长度。
- 常用的字段放在前面;选择性高的字段放在前面
- 对较长的字符数据类型的字段建索引,优先考虑前缀索引,如 index(url(64))
- 只创建需要的索引,避免冗余索引,如:index(a,b),index(a)
- 使用联合索引,以避免回表,达到覆盖索引
- 联合索引遵循最左原则
- 索引不可滥用,索引会占用存储空间并且增加数据更新操作的复杂度,降低CUD(create/update/delate)效率
回表
先了解一个概念,MySQL对 WHERE 中条件的处理,根据索引使用情况分成三种:index key, index filter, table filter
1. index key
用于确定SQL查询在索引中的连续范围(起始范围+结束范围)的查询条件,被称之为Index Key。由于一个范围,至少包含一个起始与一个终止,因此Index Key也被拆分为Index First Key和Index Last Key,分别用于定位索引查找的起始,以及索引查询的终止条件。
2. index filter
在使用 index key 确定了起始范围和介绍范围之后,在此范围之内,还有一些记录不符合 WHERE 条件,如果这些条件可以使用索引进行过滤,那么就是 index filter。
3. table filter
WHERE 中的条件不能使用索引进行处理的,只能访问table,进行条件过滤了。
从普通索引查出主键索引,然后查询出数据的过程叫做回表。回表一次就会执行一次查询,所以避免回表是减少数据库压力、提高效率的有效手段。在InnoDB中,使用联合索引配合主键索引可以直接返回结果而不需要回表查询。
联合索引(复合索引)与前缀索引(最左原则)
Mysql从左到右的使用索引中的字段,一个查询可以只使用索引中的一部份,但只能是最左侧部分。例如索引是(a,b,c),可以支持 a | a,b | a,b,c 3种组合进行查找,但不支持 b,c 进行查找。这是最左原则的第一层意思:联合索引的多个字段中,只有当查询条件为联合索引的第一个字段时,索引才会有效。
条件 WHERE a LIKE 'perfix%'; 索引也会有效。这是最左原则的第二层意思:根据字段值最左若干个字符进行的模糊查询,索引有效。
覆盖索引
覆盖索引是对联合索引的合理利用。
比如 SELECT a, b FROM table WHERE a = 'wangnima'; ,如果我们已经创建了(a)或(a,b)的联合索引,那么这条语句会直接从索引返回而不会发生回表。即创建索引的字段覆盖了查询字段。
如果执行 SELECT c FROM table WHERE a = 'wangnima'; ,就会发生回表,因为我们的辅助索引树中,没有字段 c 的数据,需要拿到主键索引的关键字,去主键索引中回表查询。
但是需要注意的是,索引虽好不可滥用。
索引下推(Index Condition Pushdown (ICP))
结合在 回表 概念中引出的三种索引使用情况(index key, index filter, table filter),ICP 技术,就是 index filter 技术。MySQL的架构分为服务器层和引擎层。
官方解释(https://dev.mysql.com/doc/refman/5.6/en/index-condition-pushdown-optimization.html)
索引条件下推(ICP)是对MySQL使用索引从表中检索行的情况的优化。如果没有ICP,存储引擎将遍历索引以定位基表中的行,并将它们返回到MySQL服务器,该服务器将计算基表行的where条件。在启用ICP的情况下,如果部分where条件可以通过只使用索引中的列来计算,MySQL服务器会把where条件的这部分 推入 存储引擎。然后,存储引擎通过使用索引条目来评估所推送的索引条件,并且只有在满足该条件时才从表中读取行。ICP可以减少存储引擎必须访问基本表的次数和MySQL服务器必须访问存储引擎的次数。
根据官方的指导,我们来做个验证:
EXPLAIN SELECT * FROM people WHERE zipcode='95054' AND lastname LIKE '%lao%' AND address LIKE '%Main Street%';
官方解释:
EXPLAIN使用“索引条件下推”时,输出显示 Using index condition在 Extra列中。
假设一个表包含有关人员及其地址的信息,并且该表的索引定义为 INDEX (zipcode, lastname, firstname)。如果我们知道一个人的zipcode价值但不确定姓氏,我们可以这样搜索:
SELECT * FROM people WHERE zipcode='95054' AND lastname LIKE '%etrunia%' AND address LIKE '%Main Street%';
MySQL可以使用索引来扫描人 zipcode='95054'。第二部分(lastname LIKE '%etrunia%')不能用于限制必须扫描的行数,因此如果没有Index Condition Pushdown,此查询必须为所有拥有的人检索完整的表行 zipcode='95054'。
使用索引条件下推,MySQL lastname LIKE '%etrunia%'在读取整个表行之前检查该 部分。这样可以避免读取与索引元组相对应的完整行,这些行匹配 zipcode条件而不是 lastname条件。
默认情况下启用索引条件下推。可以optimizer_switch通过设置index_condition_pushdown标志来控制 系统变量 :
SET optimizer_switch = 'index_condition_pushdown=off'; SET optimizer_switch = 'index_condition_pushdown=on';
实践
*注意语句中的“[ ··· ]”中括号指代变量,书写时记得去掉
普通索引
这是最基本的索引,它没有任何限制。它有以下几种创建方式:
1. 创建索引
CREATE INDEX indexName ON mytable(username(length));
如果不是字符类型的字段,如int,则不要指定length;如果是CHAR,VARCHAR类型,length可以不指定,也可以小于字段实际长度;如果是BLOB和TEXT类型,必须指定 length。
2. 修改表结构(添加索引)
ALTER table tableName ADD INDEX indexName(columnName)
3. 创建表的时候直接指定
CREATE TABLE mytable( ID INT NOT NULL, username VARCHAR(16) NOT NULL, INDEX [indexName] (username(length)) );
唯一索引
它与前面的普通索引类似,不同的就是:索引列的值必须唯一,但允许有空值。如果是组合索引,则列值的组合必须唯一。它有以下几种创建方式:
1. 创建索引
CREATE UNIQUE INDEX indexName ON mytable(username(length))
2. 修改表结构
ALTER table mytable ADD UNIQUE [indexName] (username(length))
3. 创建表的时候直接指定
CREATE TABLE mytable( ID INT NOT NULL, username VARCHAR(16) NOT NULL, UNIQUE [indexName] (username(length)) );
删除索引的语法
DROP INDEX [indexName] ON mytable;
总结
合理利用索引对于提升数据库的性能、减轻数据库服务器的负担是最直接有效的手段。
其实,索引的本质就是通过缩小范围、把随机事件变成顺序事件来筛选出最终结果,同时可以总是用同一种查找方式来定位数据,这样就可以兼顾高效率和稳定性。
mysql 隐藏中间四位_MySQL知识体系——索引相关推荐
- mysql性能分析三驾马车_MySQL知识体系的三驾马车
MySQL知识体系的三驾马车 在我看来要掌握好MySQL的话要理解好这三个东西: 索引(B+树) 日志(WAL) 事务(可见性) 索引决定了查询的性能,也是用户感知到的数据库的关键所在,日常使用过程中 ...
- MySQL语言的算法_MySQL知识整理
写在前面的话:秋招来临,博主对MySQL知识进行了整理,全文包括数据库优化和数据库基础两部分 数据库优化 1.优化的目的 [1] 避免页面访问的出错(5xx错误:慢查询无法加载:阻塞无法提交) ...
- mysql 抓包乱码_mysql知识资源收集
收集一下mysql所需的文档,供后面查阅和学习.整理了下,大致需要如下的一些: 一.基础知识,包括安装,基础命令使用等 基础知识 命令行大全: 图形大纲: 二.mysql库中表对应的作用和字段作用 三 ...
- mysql btree检索策略_MySQL之Btree索引和HASH索引的区别以及索引优化策略
索引是帮助mysql获取数据的数据结构.最常见的索引是Btree索引和Hash索引. 不同的引擎对于索引有不同的支持:Innodb和MyISAM默认的索引是Btree索引:而Mermory默认的索引是 ...
- mysql字符串等于失效_MySql整型索引和字符串索引失效或隐式转换问题
问题概述 写代码的时候,有一段sql,表示该sql存在隐式转换,不走索引. 经过测试排查后,发现是类型varchar的字段, 我使用条件传入了数值型的值. 问题重现 首先我们先创建一张用户表test_ ...
- mysql数据库最多列_mysql多列索引和最左前缀
数据库的索引可以加快查询速度,原因是索引使用特定的数据结构(B-Tree)对特定的列额外组织存放,加快存储引擎(索引是存储引擎实现)查找记录的速度. 索引优化是数据库优化的最重要手段. 如果查询语句使 ...
- 前端知识树-构建你的知识体系
经常有人问,我想学前端,要从哪里学起,或者有点基础,想学点其他的,要学什么? 两年前我同样带着这样的疑问,搜索了前端知识体系这个关键词,被大神们各种图解和list吓到了,心想还是先做好当下的工作吧: ...
- 学习笔记:MySQL高阶知识体系(下)——索引、锁、日志、隔离级别与MVCC
转载自https://www.ydlclass.com/doc21xnv/database/mysqladvance/mysqlAdvance2.html MySQL高阶知识体系(下) 6. 索引 6 ...
- JAVA知识体系之数据库篇——MySQL
目录 1.一条查询语句的执行流程 1.1 MySQL基本架构 1.2 连接层 1.3 服务层 1.3.1 查询缓存 1.3.2 解析器(Parser) 词法解析 语法解析 1.3.3 预处理器(Pre ...
最新文章
- 【Java8新特性】关于Java8的Stream API,看这一篇就够了!!
- 简明 Vim 练级攻略
- Linux从零开始(二、基础命令(续)解决命令行无限输入,停不下来)
- 二叉树总结—建树和4种遍历方式(递归非递归)
- arcgis api for javascript从地图如何读取要素
- 【Blog.Core开源】网关统一集成下游服务文档
- .NET操作Excel
- GitHub博客开发上线实战
- QT5开发的程序打包发布
- 【Web动画】SVG 实现复杂线条动画
- 使用Anaconda3配置多版本Python虚拟开发环境详细步骤
- ORACLE多表查询优化
- LeetCode刷题(6)
- 15.10. Session/Cookie
- ACM学习历程—HDU 5025 Saving Tang Monk(广州赛区网赛)(bfs)
- dot格式绘图工具 html,使用dot来绘图
- python开发前景如何
- linux用户无法接收邮件,linux 下 搭建邮件邮件服务器(Postfix+Dovecot)(一)-系统账户登陆收发邮件...
- 已经有211大学发布计算机专业,研究生复试上机考试说明
- Django 学习 之ORM简介与单表操作
热门文章
- rest开发_REST 101开发人员专用
- 状态模式 设计模式_设计模式:状态
- stackexchange_通过Spring Social发推StackExchange问​​题
- 什么是JavaServer Faces(JSF)
- fork join框架_Java 7:Fork / Join框架示例
- 教程:测试期间的日志记录
- 使用djcproxy创建代理对象
- Apache CXF负载平衡和故障转移
- python读word文档doc公文标题_python – 从word doc中提取标题文本
- Linux命令之 mkfs -- 在特定的分区创建 Linux 文件系统