MySQL索引
我们知道一般的应用系统,读写比例在10:1左右,而且插入操作和一般的更新操作很少出现性能问题,遇到最多的,也是最容易出问题的,还是一些复杂的查询操作,所以查询语句的优化显然是重中之重。
索引目的
索引的目的在于提高查询效率,可以类比字典,如果要查“mysql”这个单词,我们肯定需要定位到m字母,然后从下往下找到y字母,再找到剩下的sql。如果没有索引,那么你可能需要把所有单词看一遍才能找到你想要的。除了词典,生活中随处可见索引的例子,如火车站的车次表、图书的目录等。它们的原理都是一样的,通过不断的缩小想要获得数据的范围来筛选出最终想要的结果,同时把随机的事件变成顺序的事件,也就是我们总是通过同一种查找方式来锁定数据。
索引的分类
普通索引(NORMAL):加速查询
唯一索引(UNIQUE):加速查询 + 列值唯一
全文索引(FULLTEXT):只能在 CHAR、VARCHAR 或 TEXT 类型的列上创建。在 MySQL 中只有 MyISAM 存储引擎支持全文索引。全文索引允许在索引列中插入重复值和空值。不过对于大容量的数据表,生成全文索引非常消耗时间和硬盘空间。
空间索引(SPATIAL):空间索引是对空间数据类型的字段建立的索引,使用 SPATIAL 关键字进行扩展。创建空间索引的列必须将其声明为 NOT NULL,空间索引只能在存储引擎为 MyISAM 的表中创建。
组合索引:组合索引也称为复合索引或多列索引,相对于单列索引来说,组合索引是将原表的多个列共同组成一个索引。多列索引是在表的多个字段上创建一个索引。该索引指向创建时对应的多个字段,可以通过这几个字段进行查询。但是,只有查询条件中使用了这些字段中第一个字段时,索引才会被使用。
hash索引和tree索引
- 查询时间。B+ Tree为
O(log(n))
,与树的高度有关;Hash为O(1)
- 数据库中的索引一般是在磁盘上,数据量大的情况可能无法一次装入内存,B+树的设计可以允许数据分批加载,同时树的高度较低,提高查找效率。
- 哈希索引数据并不是按照索引列的值顺序存储的,故无法用于排序
- 哈希索引只支持等值比较查询,如:
=
、in()
、<=>
(安全比较运算符,用来做 NULL 值的关系运算),不支持任何范围查询
hash索引
hash索引通过hash的数据结构存储数据,对于随机访问,hash可以做到O(1)的访问速度。但是相对的,hash是一种无序的数据结构,hash是通过键值对的形式存储数据,底层的数据结构通常使用数组,通过计算key的hash值找到数据的存储位置。这种存储方式会引起hash值相同的情况,也就是hash冲突,一般解决hash冲突的方法有链表法和开放寻址法。链表法是比较常用的方法。
B-tree
B树和平衡二叉树稍有不同的是B树属于多叉树又名平衡多路查找树(查找路径不只两个),
- 排序方式:所有节点关键字是按递增次序排列,并遵循左小右大原则。
- 子节点数:非叶子节点的子节点数>1,且<=M ,且M>=2,空树除外(注:M阶代表一个树节点最多有多少个查找路径,M=M路,当M=2则是2叉树,M=3则是3叉)。
- 关键字数:枝节点的关键字数量大于等于ceil(m/2)-1个且小于等于M-1个(注:ceil()是个朝正无穷方向取整的函数。如ceil(1.1)结果为2)。
- 所有叶子节点均在同一层、叶子节点除了包含了关键字和关键字记录的指针外也有指向其子节点的指针只不过其指针地址都为null对应下图最后一层节点的空格子。
B+树
B+树是B树的一个升级版,B+树更充分的利用了节点的空间,让查询速度更加稳定,其速度完全接近于二分法查找。B+树查找的效率要比B树更高、更稳定。
规则:
- B+跟B树不同。B+树的非叶子节点不保存关键字记录的指针,只进行数据索引,这样使得B+树每个非叶子节点所能保存的关键字大大增加。
- B+树叶子节点保存了父节点的所有关键字记录的指针,所有数据地址必须要到叶子节点才能获取到。所以每次数据查询的次数都一样。
- B+树叶子节点的关键字从小到大有序排列,左边结尾数据都会保存右边节点开始数据的指针。
- 非叶子节点的子节点数=关键字数(百度百科。根据各种资料,这里有两种算法的实现方式,另一种为非叶节点的关键字数=子节点数-1(维基百科),虽然数据排列结构不一样,但其原理还是一样的。Mysql 的 B+树是用第一种方式实现)
特点
- B+树的层级更少:相较于B树B+每个非叶子节点存储的关键字数更多,树的层级更少所以查询数据更快。
- B+树查询速度更稳定:B+所有关键字数据地址都存在叶子节点上,所以每次查找的次数都相同所以查询速度要比B树更稳定。
- B+树天然具备排序功能:B+树所有的叶子节点数据构成了一个有序链表,在查询大小区间的数据时候更方便,数据紧密性很高,缓存的命中率也会比B树高。
- B+树全节点遍历更快:B+树遍历整棵树只需要遍历所有的叶子节点即可,而不需要像B树对每一层进行遍历,这有利于数据库做全表扫描。
- B树相对于B+树的优点是,如果经常访问的数据离根节点很近,而B树的非叶子节点本身存有关键字其数据的地址,所以这种数据检索的时候会要比B+树快。
explain分析sql
在日常工作中,我们会有时会开慢查询去记录一些执行时间比较久的SQL语句,找出这些SQL语句并不意味着完事了,些时我们常常用到explain这个命令来查看一个这些SQL语句的执行计划,查看该SQL语句有没有使用上了索引,有没有做全表扫描,这都可以通过explain命令来查看。所以我们深入了解MySQL的基于开销的优化器,还可以获得很多可能被优化器考虑到的访问策略的细节,以及当运行SQL语句时哪种策略预计会被优化器采用。
expain出来的信息有10列,分别是id、select_type、table、type、possible_keys、key、key_len、ref、rows、Extra
概要描述:
id:选择标识符
select_type:表示查询的类型。
table:输出结果集的表
partitions:匹配的分区
type:表示表的连接类型
possible_keys:表示查询时,可能使用的索引
key:表示实际使用的索引
key_len:索引字段的长度
ref:列与索引的比较
rows:扫描出的行数(估算的行数)
filtered:按表条件过滤的行百分比
Extra:执行情况的描述和说明
select_type
示查询中每个select子句的类型
- SIMPLE(简单SELECT,不使用UNION或子查询等)
- PRIMARY(子查询中最外层查询,查询中若包含任何复杂的子部分,最外层的select被标记为PRIMARY)
- UNION(UNION中的第二个或后面的SELECT语句)
- DEPENDENT UNION(UNION中的第二个或后面的SELECT语句,取决于外面的查询)
- UNION RESULT(UNION的结果,union语句中第二个select开始后面所有select)
- SUBQUERY(子查询中的第一个SELECT,结果不依赖于外部查询)
- DEPENDENT SUBQUERY(子查询中的第一个SELECT,依赖于外部查询)
- DERIVED(派生表的SELECT, FROM子句的子查询)
- UNCACHEABLE SUBQUERY(一个子查询的结果不能被缓存,必须重新评估外链接的第一行)
table
查询涉及到的表
type
对表访问方式,表示MySQL在表中找到所需行的方式,又称“访问类型”。
常用的类型有: ALL、index、range、 ref、eq_ref、const、system、NULL(从左到右,性能从差到好)
- ALL:Full Table Scan, MySQL将遍历全表以找到匹配的行
- index: Full Index Scan,index与ALL区别为index类型只遍历索引树
- range:只检索给定范围的行,使用一个索引来选择行
- ref: 表示上述表的连接匹配条件,即哪些列或常量被用于查找索引列上的值
- eq_ref: 类似ref,区别就在使用的索引是唯一索引,对于每个索引键值,表中只有一条记录匹配,简单来说,就是多表连接中使用primary key或者 unique key作为关联条件
- const、system: 当MySQL对查询某部分进行优化,并转换为一个常量时,使用这些类型访问。如将主键置于where列表中,MySQL就能将该查询转换为一个常量,system是const类型的特例,当查询的表只有一行的情况下,使用system
- NULL: MySQL在优化过程中分解语句,执行时甚至不用访问表或索引,例如从一个索引列里选取最小值可以通过单独索引查找完成。
possible_keys
指出MySQL能使用哪个索引在表中找到记录,查询涉及到的字段上若存在索引,则该索引将被列出,但不一定被查询使用(该查询可以利用的索引,如果没有任何索引显示 null)
key
key列显示MySQL实际决定使用的键(索引),必然包含在possible_keys中
key_len
表示索引中使用的字节数,可通过该列计算查询中使用的索引的长度(key_len显示的值为索引字段的最大可能长度,并非实际使用长度,即key_len是根据表定义计算而得,不是通过表内检索出的)。不损失精确性的情况下,长度越短越好
sql查询优化
多个查询条件可使用联合索引,因为多个索引下第一个有效
包含多个索引的查询条件可以指定索引:select * from t force index(a) where a between 10000 and 20000;
建立合适的数据索引
选择合适的索引数据结构
多用代码优化器(explain)分析sql瓶颈
至于网上说的各种原则就见仁见智了,结合实际的业务场景针对优化才是硬道理
开启sql慢查询
开启慢查询日志及时记录比较慢的和影响性能的sql,有助于我们有针对性的优化,特别是在系统比较大的时候,这个时候就真香了,否则面对一个庞大的系统和大量的sql会显得力不从心且无从下口。
修改配置文件my.cnf,在[mysqld]下的下方加入
[mysqld]
# 是否开启
slow_query_log = ON
# 存储位置
slow_query_log_file = /usr/local/mysql/data/slow_query.log
# 忙查询时间(查询超过多少秒才记录;秒:)
long_query_time = 1
总结
本篇文章主要和大家分享sql的索引及一些优化和排查的手段,希望对大家有帮助~~