mysql索引优化
学习资料:
慢Sql、索引失效、不会优化?这套MySQL优化课程帮你解决! | 图灵学院诸葛 | 哔哩哔哩_bilibili
sql优化的方法
索引概述
索引就是方便数据查询的结构
常用索引结构
二叉树
理论上可以二分查找
但未必平衡 极端情况下就是链表
红黑树
通过算法实现自旋的平衡二叉树
B树(B-树)
B即Balanced,平衡树的意思,不局限于二叉(红黑树被发明初被称为二叉B树,symmetric binary B-trees)
换而言之就是自平衡多叉树
B树的说明:
B树的阶: 节点的最多子节点个数。比如2-3树的阶是3, 2-3-4树的阶是4 B-树的搜索,从根结点开始,对结点内的关键字(有序)序列进行二分查找,如果命中则结束,否则进入查询关键字所属范围的儿子结点重复,直到所对应的儿子指针为空,或已经是叶子结点 关键字集合分布在整颗树中,即叶子节点和非叶子节点都存放数据. 搜索有可能在非叶子结点结束 其搜索性能等价于在关键字全集内做一-次
B+树
B树虽然查询效率很高 但它对区域的查询(大于10小于100之类的)并不友好(B树的数据在树里,每次判断都需要回溯上去)
B+树是B树的变形,它把数据全都顺序存储到了叶子节点 在树中只有指向叶子的主键
阶的判别同B树,MySQL中使用的是16阶B+树
顺便如果一个表没有主键,MySQL会使用不重复的键创建B+树 如果没有不允许重复的列则会创建一个rowId来创建
Hash索引
以hash作为索引 key-行数据 的形式存储
hash的优势
无论存储空间(O(n)没有额外的空间消耗)还是查询消耗时间(不考虑hash冲突是O(1))
hash冲突
因为hash的key并不保证唯一,所以可能会有一个key对应多行,此时会把多个value以顺序表都存储在key上hash的劣势
- 查询性能受hash冲突率影响,性能不稳定
- 只能通过等值匹配的方式查询,不能范围查询
- 结构存储上没有顺序,查询时排序无法支持 在数据库软件应用场景日益复杂的今天,简单的hash表已经很难满足关系型数据库的基础查询功。
聚集索引
非聚集索引(又叫二级索引) 通常将索引和数据存放在不同的文件 索引中携带的是数据的指针(位置指向)
而聚集索引则是索引直接指向数据
在MySQL中只有主键索引是聚集索引其他都是非聚集索引
非聚集(二级)索引实例
建一个简单的表
|
|
建立一个age的二级索引
|
|
此时MySQL中存在两个索引(下图数据并不对应表的数据,偷懒直接用了课程的图)
一个是主键id的聚集索引 它的叶子节点携带整个行的数据
另一个就是刚刚创建的age二级索引 它只携带了主键id 其他的数据例如
|
|
它会去查找 age = 11的节点的id 再根据id去主键索引里进行回表
查询其他数据
覆盖索引
|
|
不同于上面的查询所有 只查询age二级索引表中存在的id属性的话就不必回表查询 能提高查询效率 就叫覆盖索引
因此可以创建组合索引提高查找效率
特别的:
当一次查询返回多条数据 按照原本的思路应当每条数据拿到主键(假设索引指向主键) 之后都需要回表
mysql在5.6版本之后使用了索引下推
(index condition pushdown,ICP) 不再一条数据回一次表 而是把所有主键一起带到主键索引里统一查询(todo:这个理解可能有误)
单列、组合索引
单列索引和组合索引的区别 就是在索引中是否只有一个索引列
比如上面的
|
|
就是一个单列索引 可以查询到的数据是 age携带主键id
而下面这个就是age 携带了name和id的组合索引
|
|
这个索引是根据age建立的 因此如果查询条件不包含age则不会触发该索引(最左前缀原则)
当一个age对应多个数据时它会按照其他的属性(先name再id)进行(默认asc)排序 在8.0之后可以指定字段desc
mysql 8.0之后允许了逆序索引
mysql 文档中对于索引定义中,ASC 和 DESC 的描述
MySQL < 8.0A key_part specification can end with ASC or DESC. These keywords are permitted for future extensions for specifying ascending or descending index value storage.
Currently, they are parsed but ignored; index values are always stored in ascending order.
MySQL >= 8.0A key_part specification can end with ASC or DESC to specify whether index values are stored in ascending or descending order. The default is ascending if no order specifier is given. ASC and DESC are not permitted for HASH indexes. As of MySQL 8.0.12, ASC and DESC are not permitted for SPATIAL indexes.
所以,在8.0之前的版本中, DESC 是无效的,索引 (a ASC, b DESC, c DESC) 等于 (a ASC, b ASC, c ASC),故而无法使用整个联合索引进行排序。
联合索引的优点
- 减少开销 例如建立一个联合索引(a,b,c) 能包括(a),(a,b),(a,c),(a,b,c)四个索引的功能 减少了写开销 与存储开销
- 覆盖索引 直接查询到数据 不必回表 这能 减少很多io操作 是主要的性能提升手段之一
- 多条件查询效率高 相比于单列索引 当索引条件指向多个数据时 组合索引对更多列进行了排序 查询效率也会更高
缺点是:
- 需要消耗物理存储空间(相比只存主键的单列 会多很多)
- 创建和维护需要消耗时间 且该时间会随数据量增加
索引的优缺点
优点:
- 提高检索效率
- 降低排序成本
缺点:
- 创建和维护需要消耗时间 且该时间会随数据量增加
- 需要消耗物理存储空间
- 降低增删改效率 增删需要维护表所有的索引 改需要维护涉及到的索引
索引优化的最佳实践
测试用例
|
|
使用存储过程插入10万条数据
|
|
全值匹配
保证查询的所有属性都在联合索引里面 完全不需要回表操作 这是最优的情况
对于下面四条语句(使用[Explain](# Explain推荐阅读)来判别它的查询方式)
|
|
|
|
减少函数计算
面对计算 不能保证结果总是符合原本值的排序 所以不能使用索引
下面两个查询的意思是一样的 但前者无法使用索引 idx_name_age_position
|
|
特别的 日期的date函数还是比较常用的 可以使用范围 来代替date函数
|
|
|
|
todo:
我尝试了一下为计算结果创建索引,结果失败了
1
ALTER TABLE `employees` ADD INDEX `idx_hire_na` (LEFT(`name`,2)) USING BTREE;
报错:
查询:ALTER TABLE
employees
ADD INDEXidx_hire_na
(left(name
,2)) USING BTREE错误代码: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ’left(name
,2)) USING BTREE’ at line 1网上好像也没有看到相关文章,也可能是查找的关键词错了
**特殊的:**string(var)类型应当加上引号 否则会进行类型转换
范围查询之后会失效
|
|
范围查询(非等值查询或者or或者涉及null的is null和is not null)的结果是一组数据而不是一个数据
后面的索引只在前面一个值相等时才有序
面对一组数据 后面的值都相当于是无序的
关于is null
null可以被看做一个特殊的值 直觉是不影响索引的 但实际测试它等待结果是Using where;Using index
我不知道这个extra是什么意思 网络上的结果也与之不同 但我想我们可以认为 is null会导致索引失效
|
|
使用force index (索引名) 可以强制使用索引
todo:
存疑:按照网课的意思应该是加了force index就不需要回表了 但不管是他的演示 还是我自己的尝试结果都是回表了的
|
|
like使用后模糊
比如’三%‘比’%三’要快很多 如果不得不使用前模糊 可以尝试直接将数据反着存比如张三
存成三张
取到值之后再翻转
如果要使用’%三%‘或者对’%三’和’三%‘都有需求的话 可以正反各存一列(吗?感觉可行 但是存储开销很大,而且对于已存在的表 随便改数据真的好吗)
或者使用ElasticSearch
其他
Explain推荐阅读
MySQL5.6之后进行了索引下推的优化 包括explain也有比较大的改动
(18条消息) MySQL 5.7 优化:Explain 执行计划近万字详解_Roc.Chang的博客-CSDN博客
ElasticSearch(ES)
这个没看 先放着
(18条消息) ElasticSearch搜索引擎结合Mysql数据库,查询mysql数据_es搜索引擎结合mysql_幻秋秋秋丘的博客-CSDN博客
go-elasticSearch实战篇,带你学会go开发Es - 掘金 (juejin.cn)
trace工具
MySQL5.6版本后提供了对SQL的跟踪工具trace,通过使用trace可以让我们明白optimizer如何选择执行计划的(此功能默认关闭)
参数详解推荐阅读这篇文章
|
|
|
|
|
|
得到
|
|
trace可分析如下语句:
- SELECT
- INSERT
- REPLACE
- UPDATE
- DELETE
- EXPLAIN
- SET
- DECLARE
- CASE
- IF
- RETURN
- CALL