MySQL索引机制(详细+原理+解析)

MySQL索引机制(详细+原理+解析),第1张

MySQL 前缀索引能有效减小索引文件的大小,提高索引的速度。但是前缀索引也有它的坏处:MySQL 不能在 ORDER BY 或 GROUP BY 中使用前缀索引,也不能把它们用作覆盖索引(Covering Index)。

集一个索引包含多个列(最左前缀匹配原则)

索引列的值必须唯一,但允许有空值

全文索引为FUllText,在定义索引的列上支持值的全文查找,允许在这些索引列中插入重复值和空值,全文索引可以在CHAR,VARCHAR,TEXT类型列上创建

设定主键后数据会自动建立索引,InnoDB为聚簇索引

即一个索引只包含单个列,一个表可以有多个单列索引

覆盖索引是指一个查询语句的执行只用从所有就能够得到,不必从数据表中读取,覆盖索引不是索引树,是一个结果,当一条查询语句符合覆盖索引条件时候,MySQL只需要通过索引就可以返回查询所需要的数据,这样避免了查到索引后的回表 *** 作,减少了I/O效率

查看索引

列名解析:

删除索引

查看:

删除前:

删除后:

普通的索引,没有什么介绍

查看:(注意和前缀索引Sub_part的区别)

当索引的列是unique的时候,会生成唯一索引,唯一索引关于null有下列两种情况

SQLSERVER 下的唯一索引的列,允许null值,但最多允许有一个空值

MYSQL下的唯一索引的列,允许null值,并且允许多个空值

查看:

会建立两个索引,一个非聚簇索引,一个是唯一索引

结果:

可以插入两个空值(明人不说暗话,我喜欢MySQL)

一方面,它不会索引所有字段所有字符,会减小索引树的大小.

另外一方面,索引只是为了区别出值,对于某些列,可能前几位区别很大,我们就可以使用前缀索引。

一般情况下某个前缀的选择性也是足够高的,足以满足查询性能。对于BLOB,TEXT,或者很长的VARCHAR类型的列,必须使用前缀索引,因为MySQL不允许索引这些列的完整长度。

查看:

查看:

复合索引的最左前缀匹配原则

对于复合索引,查询在一定条件才会使用该索引

减少开销。 建一个联合索引(col1,col2,col3),实际相当于建了(col1),(col1,col2),(col1,col2,col3)三个索引。每多一个索引,都会增加写 *** 作的开销和磁盘空间的开销。对于大量数据的表,使用联合索引会大大的减少开销!

覆盖索引。 对联合索引(col1,col2,col3),如果有如下的sql: select col1,col2,col3 from test where col1=1 and col2=2。那么MySQL可以直接通过遍历索引取得数据,而无需回表,这减少了很多的随机io *** 作。减少io *** 作,特别的随机io其实是dba主要的优化策略。所以,在真正的实际应用中,覆盖索引是主要的提升性能的优化手段之一。

效率高。 索引列越多,通过索引筛选出的数据越少。有1000W条数据的表,有如下sql:select from table where col1=1 and col2=2 and col3=3,假设假设每个条件可以筛选出10%的数据,如果只有单值索引,那么通过该索引能筛选出1000W10%=100w条数据,然后再回表从100w条数据中找到符合col2=2 and col3= 3的数据,然后再排序,再分页;如果是联合索引,通过索引筛选出1000w10% 10% *10%=1w。

在模糊搜索中很有效,搜索全文中的某一个字段,可以参考这篇博文

: https://zhuanlan.zhihu.com/p/88275060

我们先进行下面一个实验看看InnoDB下的主键索引的一个现象。

查看:

我们插入进去的时候,数据的id都是乱序的,为什么这里最后select查询出来的结果都是进行了排序?

这是因为InnoDB索引底层实现的是B+tree,B+tree具有下列的特点:

所以上面的排序是为了使用B+tree的结构 ,B+tree为了范围搜索,将主键按照从小到大排序后,拆分成节点。后续还有新的节点进入的时候,和B-tree相同的 *** 作,会进行分裂。

一般来说,聚簇索引的B+tree都是三层

InnoDB中主键索引一定是聚簇索引,聚簇索引一定是主键索引。

为什么这里辅助索引叶子结点不直接存储数据呢?

MYISAM只有非聚簇索引,索引最终指向的都是物理地址。

Q:既然有回表的存在,那么聚簇索引的优势在哪里?

Q:主键索引作为聚簇索引需要注意什么

在查询语句中使用LIke关键字进行查询时,如果匹配字符串的第一个字符为"%",索引不会使用。如果“%”不是在第一位,索引就会使用

多列索引是在表的多个字段上创建的索引,满足最左前缀匹配原则,索引才会被使用

查询语句只有Or关键字时候,如果OR前后的两个条件都是索引,这这次查询将会使用索引,否则Or前后有一个条件的列不是索引,那么查询中将不使用索引

mysql的索引类型及使用索引时的注意事项有:

一、普通索引。这是最基本的索引,它没有任何限制。它有以下几种创建方式:

1、创建索引

代码如下:

CREATE INDEX indexName ON mytable(username(length))

如果是CHAR,VARCHAR类型,length可以小于字段实际长度;如果是BLOB和TEXT类型,必须指定 length,下同。

2、修改表结构

代码如下:

ALTER mytable ADD INDEX [indexName] ON (username(length)) -- 创建表的时候直接指定

CREATE TABLE mytable(   ID INT NOT NULL,    username VARCHAR(16) NOT NULL,   INDEX [indexName] (username(length))   ) 

-- 删除索引的语法:

DROP INDEX [indexName] ON mytable

二、唯一索引。它与前面的普通索引类似,不同的就是:索引列的值必须唯一,但允许有空值。如果是组合索引,则列值的组合必须唯一。它有以下几种创建方式:

代码如下:

CREATE UNIQUE INDEX indexName ON mytable(username(length))

-- 修改表结构

ALTER mytable ADD UNIQUE [indexName] ON (username(length))

-- 创建表的时候直接指定

CREATE TABLE mytable(   ID INT NOT NULL,    username VARCHAR(16) NOT NULL,   UNIQUE [indexName] (username(length))   )

三、主键索引。它是一种特殊的唯一索引,不允许有空值。一般是在建表的时候同时创建主键索引:

代码如下:

CREATE TABLE mytable(   ID INT NOT NULL,    username VARCHAR(16) NOT NULL,   PRIMARY KEY(ID)   )

当然也可以用 ALTER 命令。记住:一个表只能有一个主键。

四、组合索引。为了形象地对比单列索引和组合索引,为表添加多个字段:

代码如下:

CREATE TABLE mytable(   ID INT NOT NULL,    username VARCHAR(16) NOT NULL,   city VARCHAR(50) NOT NULL,   age INT NOT NULL  )

为了进一步榨取MySQL的效率,就要考虑建立组合索引。就是将 name, city, age建到一个索引里:

代码如下:

ALTER TABLE mytable ADD INDEX name_city_age (name(10),city,age)[code]

建表时,usernname长度为 16,这里用 10。这是因为一般情况下名字的长度不会超过10,这样会加速索引查询速度,还会减少索引文件的大小,提高INSERT的更新速度。

如果分别在 usernname,city,age上建立单列索引,让该表有3个单列索引,查询时和上述的组合索引效率也会大不一样,远远低于我们的组合索引。虽然此时有了三个索引,但MySQL只能用到其中的那个它认为似乎是最有效率的单列索引。

建立这样的组合索引,其实是相当于分别建立了下面三组组合索引:usernname,city,age   usernname,city   usernname  为什么没有 city,age这样的组合索引呢?这是因为MySQL组合索引“最左前缀”的结果。简单的理解就是只从最左面的开始组合。并不是只要包含这三列的查询都会用到该组合索引,下面的几个SQL就会用到这个组合索引:

[code]

SELECT * FROM mytable WHREE username="admin" AND city="郑州"  SELECT * FROM mytable WHREE username="admin"

联合索引又叫复合索引。两个或更多个列上的索引被称作复合索引。

对于复合索引:Mysql从左到右的使用索引中的字段,一个查询可以只使用索引中的一部份,但只能是最左侧部分。例如索引是 key index (a,b,c) 。 可以支持 a|a,b|a,b,c 3种组合进行查找,但不支持 b,c 进行查找 .当最左侧字段是常量引用时,索引就十分有效。

利用索引中的附加列,您可以缩小搜索的范围,但使用一个具有两列的索引不同于使用两个单独的索引。复合索引的结构与电话簿类似,人名由姓和名构成,电话簿首先按姓氏对进行排序,然后按名字对有相同姓氏的人进行排序。如果您知道姓,电话簿将非常有用;如果您知道姓和名,电话簿则更为有用,但如果您只知道名不姓,电话簿将没有用处。

所以说创建复合索引时,应该仔细考虑列的顺序。对索引中的所有列执行搜索或仅对前几列执行搜索时,复合索引非常有用;仅对后面的任意列执行搜索时,复合索引则没有用处。

如:建立 姓名、年龄、性别的复合索引。

(1) select * from myTest where a=3 and b=5 and c=4 ---- abc顺序

abc三个索引都在where条件里面用到了,而且都发挥了作用

(2) select * from myTest where c=4 and b=6 and a=3

where里面的条件顺序在查询之前会被mysql自动优化,效果跟上一句一样

(3) select * from myTest where a=3 and c=7

a用到索引,b没有用,所以c是没有用到索引效果的

(4) select * from myTest where a=3 and b>7 and c=3 ---- b范围值,断点,阻塞了c的索引

a用到了,b也用到了,c没有用到,这个地方b是范围值,也算断点,只不过自身用到了索引

(5) select * from myTest where b=3 and c=4 --- 联合索引必须按照顺序使用,并且需要全部使用

因为a索引没有使用,所以这里 bc都没有用上索引效果

(6) select * from myTest where a>4 and b=7 and c=9

a用到了 b没有使用,c没有使用

(7) select * from myTest where a=3 order by b

a用到了索引,b在结果排序中也用到了索引的效果,a下面任意一段的b是排好序的

(8) select * from myTest where a=3 order by c

a用到了索引,但是这个地方c没有发挥排序效果,因为中间断点了,使用 explain 可以看到 filesort

(9) select * from mytable where b=3 order by a

b没有用到索引,排序中a也没有发挥索引效果

对于单键索引,尽量选择针对当前query过滤性更好的索引

在选择组合索引的时候,当前Query中过滤性最好的字段在索引字段顺序中,位置越靠前越好。

在选择组合索引的时候,尽量选择可以能够包含当前query中的where子句中更多字段的索引

尽可能通过分析统计信息和调整query的写法来达到选择合适索引的目的


欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/8613634.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-04-18
下一篇 2023-04-18

发表评论

登录后才能评论

评论列表(0条)

保存