索引
# 索引定义
索引是帮助MySQL高效获取数据的排好序的数据结构
# 数据结构
# Hash表
咯
# B+Tree
二叉树
红黑树(自平衡二叉树)
B-Tree
- 一个节点下面有多个
- 所有索引元素不重复
- 节点中的数据索引从左到右递增排列
- 叶节点具有相同的深度,叶节点的指针为空
B+Tree
- 非叶子节点不存储data,只存储索引(冗余)和下层指针,以便放更多的索引
- 叶子节点包含所有索引字段 ,和数据
- 叶子节点用双指针连接,提高区间访问的性能
# 倒排索引
# R-tree
# 索引类型
# 底层数据结构
# hash索引
不支持范围查询
# B+树索引
# 全文索引
- 倒排索引
- 全文索引只能用于数据库引擎为MYISAM的数据表,5.6以后支持了
- MySql自带的全文索引只能对英文进行全文检索,目前无法对中文进行全文检索,如果需要对包含中文在内的文本数据进行全文检索,需要采用Sphinx(斯芬克斯)/Coreseek技术来处理中文。
- 一般我们用es来做全文/分词 搜索.
# R-tree
- 空间数据索引
- myisam支持空间索引,可以用作地理数据存储
# 索引字段个数
# 单值索引
# 复合(联合)索引
- 存储结构: order by A,B,C
- 最左前缀原理
# 是否是在主键上建立的索引
- 主键索引
- 辅助索引(非主键索引)(二级索引)
# 索引的存储关联
- 聚集/聚簇索引 : 叶节点包含了完整的数据记录,不需要回表
- 非聚集索引 : 回表操作,影响性能
# 功能分类
唯一索引
主键索引
普通索引
用表中的普通列构建的索引,没有任何限制
全文索引
使用 match 和 against 关键 来做精确度的匹配.
前缀索引(短索引)
对于BLOB、text或者很长的varchar类型的列必须使用前缀索引
前缀索引无法使用order by和group by也无法使用覆盖索引
索引最大长度是768字节,当字符串过长时,mysql会做一个类似左前缀索引的处理,将前半部分的字符提取出来做索
ALTER table 表名 add index title_pre(列名(100))列名后面的数字代表前缀的长度,前缀长度并不是越长越好,这里涉及到一个选择性问题,
空间数据索引
用于存放地理位置,和相关操作的。
# 聚集索引
MyISAM索引文件和数据文件是分离的(非聚集)
InnoDB索引实现
(索引文件和数据文件在一起)表数据文件本身就是按B+Tree组织的一个索引结构文件
聚集索引-叶节点包含了完整的数据记录
为什么建议InnoDB表必须建主键,并且推荐使用整型的自增主键?
以主键为默认索引,和数据聚集的。
为什么非主键索引结构叶子节点存储的是主键值?(一致性和节省存储空间)
# 索引设计原则
- 代码先行,索引后上
- 联合索引尽量覆盖条件
- 不要在小基数(如: 性别)字段上建立索引
- 长字符串我们可以采用前缀索引
- where与order by冲突时优先where
- 基于慢sql查询做优化 (opens new window)
# 索引优化
# 索引类型
- 降序索引 (Mysql8以上)
# 索引实践
- 全值匹配
- 最左前缀法则
- 不在索引列上做任何操作(计算、函数、(自动or手动)类型转换),会导致索引失效而转向全表扫描
- 存储引擎不能使用索引中范围条件右边的列
- 尽量使用覆盖索引(只访问索引的查询(索引列包含查询列)),减少 select * 语句
- 在使用不等于(!=或者<>),not in ,not exists 的时候无法使用索引会导致全表扫描 < 小于、 > 大于、 <=、>= 这些,mysql内部优化器会根据检索比例、表大小等多个因素整体评估是否使用索引
- .is null,is not null 一般情况下也无法使用索引
- like以通配符开头('$abc...')mysql索引失效会变成全表扫描操作。 like KK%相当于=常量,%KK和%KK% 相当于范围
- 字符串不加单引号索引失效
- 少用or或in,用它查询时,mysql不一定使用索引,mysql内部优化器会根据检索比例、表大小等多个因素整体评 估是否使用索引,详见范围查询优化,in和or在表数据量比较大的情况会走索引,在表记录不多的情况下会选择全表扫描
- 范围查询优化,优化方法:可以将大的范围拆分成多个小范围
# 索引失效常见的问题
- 联合索引第一个字段用范围不会走索引,(结果集应该很大,回表效率不高,还不如就全表扫描)
# 索引下推
可以在索引遍历过程中,对索引中包含的所有字段先做判断,过滤掉不符合条件的记录之后再回表,可以有效的减少回表次数。索引下推会减少回表次数,对于innodb引擎的表索引下推只能用于二级索引
# 参考资料
mysql B-Tree、哈希索引、R-Tree、全文索引、前缀索引 (opens new window)
MySQL索引分类,90%的开发都不知道 (opens new window)
主键索引和唯一索引的区别 (opens new window)
主键列在创建时,已经默认为空值 + 唯一索引了。
唯一性索引列允许空值,而主键列不允许为空值。
一个表最多只能创建一个主键,但可以创建多个唯一索引。
主键可以被其他表引用为外键,而唯一索引不能。
多个单列索引和联合索引的区别详解 (opens new window)
多个单列索引在多条件查询时优化器会选择最优索引策略,可能只用一个索引,也可能将多个索引全用上! 但多个单列索引底层会建立多个B+索引树,比较占用空间,也会浪费一定搜索效率,故如果只有多条件联合查询时最好建联合索引!
MySQL 之全文索引 (opens new window)
MySQL创建全文索引 (opens new window)
Mysql主键、普通索引、唯一索引和全文索引的区别 (opens new window)
MySQL Index--NOT IN和不等于两类操作无法走索引? (opens new window)
MySQL中 IS NULL、IS NOT NULL、!= 能用上索引吗? (opens new window)
MySql整型索引和字符串索引失效或隐式转换问题 (opens new window)
- 当我们使用的字段是数值类型时,加引号或者不加引号(sql中单引号和双引号实现相同效果)都不影响索引的使用
- 当我们的字段是字符串类型时,不加引号的查询无法使用索引,加引号的查询才可正常使用索引,存在隐式转换,不走索引
- string类型转换成int类型 代价比较小,所以会走索引