高性能MySQL-创建高性能索引
创始人
2024-02-21 04:36:07

什么是索引

MySQL并没有统一的索引标准,不同存储引擎的索引的工作方式并不一样,也不是所有的存储引擎都支持所有类型的索引。即使多个存储引擎支持同一种类型的索引,其底层的实现也可能不同。

索引是存储引擎用于快速找到记录的一种数据结构,为数据库检索提供良好的性能。尤其是当表中的数据量越来越大时,索引对性能的影响愈发重要。

索引的优点

  • 索引大大减少了服务器需要扫描的数据量
  • 索引可以帮助服务器避免排序和临时表
  • 索引可以将随机I/O变为顺序I/O

索引的类型

索引的实现多种多样,在这里我们从数据结构的角度进行分类介绍下常见的两种索引类型。

B-Tree索引

书中使用“B-Tree”是因为 MySQL 在一些语句中也使用该关键字。不过底层的存储引擎也可能使用不同的存储结构,比如 InnoDB 使用的是 B+Tree

实现原理

B-Tree 通常意味着所有的值都是按照顺序存储的,并且每一个叶子页到根的距离相同。下图为 B-Tree 索引的抽象表示。
在这里插入图片描述
B-Tree 索引能够加快访问数据的速度,因为存储引擎不再需要进行全表扫描来获取需要的数据,取而代之的是从索引的根结点开始进行搜索。根结点的槽中存放了指向子节点的指针,存储引擎根据这些指针向下层查找。通过比较节点页的值和要查找的值可以找到合适的指针进入下层子节点,这些指针实际上定义了子节点页中值的上限和下限。最终存储引擎要么是找到对应的值,要么该记录不存在。

另外 B-Tree 对索引列是顺序组织存储的,所以很适合查找范围数据

对于如下数据表

CREATE TABLE People (
last_name varchar(50) not null,
first_name varchar(50) not null,
dob date not null,
gender enum (‘m’, ‘f’) not null,
key (last_name, first_name, dob) );

在这里插入图片描述

主要支持的查询方式

  • 全值匹配
  • 匹配最左前缀
  • 匹配列前缀
  • 匹配范围值
  • 精确匹配某一列并范围匹配另外一列
  • 只访问索引的查询

B-Tree 的限制

  • 如果不是按照索引的最左列开始查找的,则无法使用索引
  • 不能跳过索引中的列
  • 如果查询中有某个列的范围查询,则其右边所有列都无法使用索引优化查找

哈希索引

实现原理

对于每一行数据,存储引擎都会对所有的索引列计算一个哈希码 (hash code), 哈希码是一个较小的值,并且不同键值的行计算出来的哈希码不一样。哈希索引将所有的哈希码存储在索引中,同时在哈希表中保存指向每个数据行的指针。

哈希索引的限制

  • 不能避免读取行,因为索引只包含哈希值和行指针
  • 不是按照索引值顺序存储
  • 不支持部分索引列匹配查找
  • 只支持等值查询
  • 需要注意哈希冲突

用例

  • Memory 引擎、NDB 引擎支持唯一哈希索引
  • InnoDB 可以创建自定义哈希索引
    • 使用 CRC32 实现自定义哈希索引
    • 自定义哈希函数实现哈希索引

高性能的索引策略

索引评星

一星索引:如果与查询相关的索引行是相邻的或者至少相距足够靠近的话,这个索引就可以标记为一星索引。(即where条件能够最大限度的使用索引)
二星索引:在一星的基础上,索引行的顺序和查询语句的需求一致,则为二星索引。
三星索引:如果索引包含了查询语句中的所有列,仅访问索引就能够返回,则为三星索引。

前缀索引

当一个字符列的的字符数据很长时,索引会变得又大又慢,通常遇到这种场景,我们需要考虑使用前缀索引来降低索引空间从而提升索引效率。索引选择性(通常我们称之为索引区分度)是指不重复的索引值和数据表中的记录总数的比值,选择性越高则索引效率越好,最大值为1。

书中示例:比如我们要对一个城市名称进行索引,但是索引字段很长,于是我们开始考虑适应前缀索引方案,那么如何确定前置长度呢?
在这里插入图片描述
完成字段的选择性是0.0312
在这里插入图片描述
当前缀索引长度到7时,索引的区分度已经很接近完整字段的区分度了,再增加长度的收益非常小,因此7是比较合适的前缀索引长度。

  • 前缀索引的缺点:无法做ORDER BY和GROUP BY,也无法进行覆盖扫描。

多列索引

MySQL5.0之前查询只能使用单一索引进行查询,之后的版本引入了一种索引合并(index merge)策略,这种策略可以使用多个索引扫描数据,取得结果后进行合并。

select * from t1 where c1=1 or c2=1     #c1和c2均为独立索引列

在index merge的策略下,可以分别使用c1的索引和c2的索引查询出数据再进行合并。我们可以通过执行计划查看是否使用了索引合并策略。
在这里插入图片描述
索引合并缺点:优化器只关心随机页面读取,不会计算数据的缓存、排序和合并的时间成本,由于以上因素的存在,索引合并策略的触发很有可能还不如走全表扫描,因此一旦发现有index merge出现,我们应该考虑如何使用联合索引优化查询场景而不是依赖index merge。

聚簇索引

“聚簇”表示数据行和相邻的键值紧凑地存储在一起,聚簇索引不是一种索引的数据结构而是一种数据的存储方式。因为无法同时把数据行存放在两个不同的地方,所以一个表通常只能有一个聚簇索引。有些数据库服务器允许你选择用于聚簇的索引,但是MySQL内置的存储引擎都不支持这个特性。
InnoDB聚簇索引的创建方式:

  • 默认使用主键聚簇数据
  • 如果没有创建主键,则会选择一个唯一非空索引替代
  • 如果没有唯一非空索引,则会使用隐式定义一个主键作为聚簇索引
聚簇索引的优点:
1. 把相关数据保存在一起。例如实现电子邮箱时,可以根据用户id来聚集数据,这样只需要从磁盘中读取少量的数据页就能获取某个用户的全部邮件。如果没有使用聚簇索引,则每封邮件都可能导致一次磁盘I/O。
2. 根据主键查询时,减少了回表查询的I/O操作
3. 可以使用覆盖索引策略直接命中主键索引
聚簇索引的缺点:
1. 聚簇数据最大限度地提高了io密集型应用的性能,如果数据全部放在内存,则访问的顺序没那么重要
2. 插入速度依赖于插入顺序
3. 更新聚簇索引列的成本很高
4. 全表扫描可能会变得很慢
5. 二级索引可能比想象的要更大,因为二级索引的叶子节点包含了引用行的主键列
6. 二级索引存储的是主键值而不是行指针导致回表需要走索引扫描

覆盖索引

如果一个索引包含所有需要查询的字段的值,我们就称之为覆盖索引,需要注意的是只有B-tree索引可以用于覆盖索引。
索引覆盖的优点:

  • 索引条目大小远小于数据行大小,使用索引覆盖能够极大的减少数据访问量
  • 索引是有序存储的,在范围查找的场景中能够减少IO次数
    通过执行计划能够确认执行的SQL是否使用了覆盖索引,当使用EXPLAIN时,当Extra列的值为Using index时,代表使用了覆盖索引。
    在这里插入图片描述

索引排序

  • 当索引的顺序和ORDER BY子句的顺序完全一致,并且所有列的排序方向(倒序或正序)都一样时,MySQL才能使用索引来对结果做排序。
  • 如何判断MySQL是否使用索引进行排序?当使用执行计划EXPLAN时type列的结果是index,则说明MySQL使用了索引对结果进行排序。

使用索引排序也存在一些条件:

  • 索引顺序和order by子句的顺序完全一致或者最左前缀匹配,比如索引是(a,b,c)那么排序子句应该是order by a,b,c

例如 test_order 存在索引(a,b)如果以b,a进行排序则无法使用索引排序

EXPLAIN select * from test_order order by b,a DESC limit 10,10

在这里插入图片描述

  • 如果查询需要联结多张表那么order by子句引用的字段必须全部在第一个表中才能使用索引排序
  • 有一种特殊情况是如果最左前缀是字段在where中使用了等值查询(视为常量),则可以使用后面的字段进行排序
    例如:
select * from test_order where a='1' order by b desc

索引维护

冗余和重复索引

MySQL允许在相同列上创建多个索引,当你创建时只会抛出一个警告,并不会阻止创建。MySQL需要单独维护重复的索引,优化器在优化查询的时候需要逐个考虑,会影响性能。
重复索引:如若发现,尽快删除。
冗余索引:冗余索引一般存在于扩展索引的场景。
例如已经存在(a)列的索引,为了业务扩展增加了一个(a,b)的索引,此时(a)索引就变得冗余了,遇到冗余索引不要立即删除,需要重复review业务场景,特别是排序场景,确认没有被用到再进行删除。

未使用的索引

现实情况中有一部分索引因为错误的创建可能永远不会被数据库所使用,这样的索引不但没有提升查询效率还影响到了数据库写入数据时的创建效率和优化器进行索引分析时的性能,如果存在这样的索引建议直接删除。可以通过以下的方式进行未使用索引的检查:

select * from sys.schema_unused_indexes

索引和锁

InnoDB 只有在访问行的时候才会加行锁,而索引能帮助我们选中更少的行,进而减少行锁的数量。但是需要注意,只有 InnoDB 存储引擎过滤掉不需要的行时才能减少行锁。如果索引行过滤后的数据需要到服务器层再次过滤的话,此时 InnoDB 还是会锁住服务器层过滤前的所有的行。

思考下面的例子:
在这里插入图片描述
InnoDB 会选择索引列 actor_id,筛选出五条数据对应的 actor_id 为 1 ~4 行。而 MySQL 服务器层会再次过滤数据1, 返回最终结果 2~4 行,但是注意行锁仍会锁定 1~4 行。

开启第二个事务,会发现第一行更新语句被锁住无法执行。
在这里插入图片描述
使用 “EXPLAIN” 工具来查看执行计划,其中以下结果列和索引选择相关。

type

说明
ALL全表扫描,根据行次序扫描
index类似全表扫描,但是使用索引次序进行,而不是数据行次序。
range开始于索引里的某个点,范围查询。查询条件有两种:1. between 和 > ; 2. in 和 or这两种条件在索然都是 range 方式,但是性能差异较大。
ref1. 非唯一索引查询。2. 用于联表查询的情况,非主键和非唯一键联合查询触发。
eq_ref用于联表查询的情况,按联表的主键或唯一键联合查询。
const查找主键索引,返回的数据至多一条(0或者1条)

性能 ALL < index < range < ref < eq_ref < const

prossible_keys

满足条件的索引列表

keys

MySQL 真正选择的索引。部分特殊场景(如覆盖索引)会导致该索引可能会没有出现在 possible_keys 中。

key_len

索引的长度。联合索引因为最左匹配原则,可能只有部分索引参与计算,此时 key 的长度为参与计算部分的表定义字段总和。
在这里插入图片描述

Extra

比较重要的常见值列表:

Extra type含义
Using index覆盖索引,无需回表查询数据
Using index Condition索引下推(ICP)通过索引进行过滤,随后再用where进行过滤
Using whereMySQL 服务器需要在存储引擎执行后再次进行数据过滤。例如下面的查询 select * from test_order WHERE a = “1157175” and b > “2022-11-10” (索引为a,c),因为没有 a + b 的联合索引,存储引擎选用了 a + c 索引(最左匹配)。因此,需要额外过滤。
Using temprory没有命中索引,使用临时表。
Using filesort没有命中索引,使用内存或者磁盘进行排序。需要做优化。

相关内容

热门资讯

【看表情包学Linux】进程地...   🤣 爆笑教程 👉 《看表情包学Linux》👈 猛...
吉字五行及吉凶 吉字五行中代表... 五行解析在文化中,五行是非常重要的概念之一,在这里解析一下五行对于人们生活的影响。首先,金属代表的是...
月老姻缘灵签内容详解大全 月老... 月老灵签 姻缘签44签 求解签君尔目下之人。本是可心满意足之人。焉知后来之人。一个比一个更美好。就此...
六爻排盘蛇 六爻排盘预测绝招 ... 六爻排盘结果怎么看纳甲六爻在线排盘姓名:出生年:1981性别:男占事:起卦方式:手动摇卦公历时间:2...
吉凶由情绪决定 每日吉凶 每月... 情绪的力量情绪是我们生活中一个重要的组成部分。我们每天都会通过不同的方式感受到情绪的存在,而情绪的质...
吉凶悔吝的解释是什么 风水形势... 吉凶悔吝的解释是什么从古至今,人们对于吉凶悔吝都有着不同的看法。所谓吉,是指好的运气,让人们沾沾自喜...
如何看每日生肖运势 每日生肖运... 背景说明每个人都希望自己的运势越来越好,而对于人来说,生肖运势是一个参考价值很高的判断标准。按照传统...
最准观音灵签21签解签 观音灵... 观音灵签21签解签-遵医嘱,健康长寿观音精神签证是中国民间宗教信仰的重要形式,也是一种广泛流传的祈祷...
梦见红裤子被水冲走 梦见河里洗... 梦见红裤子被水冲走红裤子是一种比较鲜艳的颜色,在梦中出现可能代表着某种情绪或状态。而被水冲走则更加具...
十二星座对象配对 12星座最佳... 12星座配偶标准白羊座:温柔善良的人乐观单纯的白羊座在恋爱时喜欢另一半无条件的宠爱自己,另一半对自己...
带水又带土的名字女孩名字有哪些... 含水和土的字有哪些含水的字:淦、澜、浸、泼、滴、没、汪、沸、鸿、沔、浩、渣、溢、潺江、注、漭、淬、澧...
六爻失物卦 在线占卜失物 六爻... 六爻占卜 寻找失物公历起卦时间:2012年12月24日9时44分(按公历时间起卦)农历:仁辰年十一月...
天网今日生肖运势 每日特吉生肖... 天网今日生肖运势天网今日,十二生肖依旧是重要的关键词之一。根据传统文化和民间信仰,每个人都属于一个生...
六爻代表书籍 六爻预测好的书籍... 学六爻的书籍那些比较经典,最好适合初学者的。从古至今六爻类的书流传于世的非常少,六爻类最经典的几本书...
十二星座女生专属花卉 小葩画1... 狮子座的女生喜欢什么样的花1.狮子座的女生喜欢鲜艳、华丽、高贵的花。2.狮子座的女生通常有着自信、热...
客厅风水禁忌及化解 客厅推拉门... 客厅风水禁忌及解决方案客厅是家庭中最重要的空间之一,也是最容易受到风水影响的空间之一。在客厅里,我们...
吉凶参半牛兔在含义 牛兔相冲到... 吉凶参半牛兔在啥意思吉凶参半牛兔在是指属牛的和属兔的结婚以后生活吉凶各一半。丑牛与子鼠六合,因此最宜...
各生肖属相的车牌号码吉凶对照表... 十二生肖与车牌号的佳搭配 十二生肖车牌号吉凶对照表通常每个人的黄道十二宫都会影响车牌号码的运行模式,...
客厅西部尖角的风水 客厅有棱角... 客厅西南角最好的风水是什么?客厅西南角最好的风水是什么?客厅西南角最好的风水是什么?房子的方形风水是...
带昶字的女孩名字 带滢的女孩名... 长字命名的寓意及意义长字命名的寓意和意义是正直、坚强、努力、阳光、前途似景、忠诚。长是一个通用词。长...
六壬怎么算命 六壬掐指神算金口... 什么是六仁?刘仁是中国古代的算命方法,起源于汉代,是中国道教学派的经典之一。刘仁包括六个神:天乙、天...
四月二十九生肖运势 十二生肖鸡... 女1993农历四月二十九早上十点生辰八字是什么如何出生时间:公历 1993年 6月 18日 10点本...
带心字的游戏女孩名字大全集 游... 2020男孩怎么起名有内涵 带心字的男孩名字大全心繁体:心起名五行:金姓名学笔画:4画简体笔画:4画...
八字鬼谷子算命 鬼谷子精髓50... 什么是八字鬼谷子算命?八字鬼谷子算命,又称李静算命,是中国传统的民间算命方式。八字鬼谷子算命起源于六...
十二星座下个月的运势女生 十二... 白羊座下个月的运势女生白羊座女生本身就充满了无限活力和热情,下个月的运势也不会让你失望。职业上可能会...
号令天下手机吉凶预测 号令天下... 手机号怎么算吉凶?用最后四个手机号码除以80,然后减去整数部分(只留小数),再乘以80,就会得到一个...
命理十二生肖今年运势 明天运势... 命理十二生肖今年运势今年每年都有不同的转瞬即逝的岁月。对于不同的黄道十二宫来说,它每年都有自己独特的...
八字长生好吗 八字中帝旺到长生... 八字日坐长生一定富吗丁火曰元生于未月,余气通根,年支丙火也能助身,但于上两透旺食,生财耗身过甚,故命...
带日的名字女孩名字大全 起名带... 日字旁边的女孩名字大全日字旁边的女孩名字推荐1、诗晗、慧曦、Xi、仲晴2、小芸、小娟、会晴、若昕、敏...
号令天下固话号码测吉凶 查电话... 周易81测手机号码吉凶,号令天下手机号码测吉凶提起周易81测手机号码吉凶,大家都知道,有人问天下手机...