4.MySQL索引

  索引是数据库中帮助快速查询数据的一种数据结构,它将数据表中的数据放在索引文件中,以便于快速查询。索引存在磁盘中,会占据物理空间,因此不恰当的索引会影响性能。MySQL索引存储在存储引擎中。

为什么要使用索引呢?

  1、索引能够大大的减少存储引擎需要扫描的数据量

索引的大小通常远小于数据的大小,以InnoDB为例,引擎发生一次I/O最小的存取单位是页。页内存储信息越多则读取效率越快,一页存放很多索引,通过索引查找则读取页的数量就越少

  2、索引可以帮助我们进行排序以避免使用临时表

B-Tree索引按键值的顺序存放,可以排序。避免了使用临时表排序的I/O消耗同时提高MySQL处理能力

  3、索引可以把随机I/O变成顺序I/O

B-Tree索引按键值的顺序存放,可以排序。而数据行的物理地址是随机分布的,使用索引让随机I/O变为顺序I/O

索引是否越多越好呢?

  1、索引会增加些操作的成本

数据更新时,需要同时对相关索引进行维护,索引越多修改数据所需要的时间越长。InnoDB针对这种情况,引入了插入缓存,将多次插入合并为一次

  2、太多的索引会增加查询优化器的选择时间

MySQL查询优化器会根据索引的统计信息和查询条件来查询选择合适的索引,如果对一个查询有很多个索引可以使用,则会增加查询优化器对查询的分析时间。

索引的常见类型:

  • 哈希表:key-value结构,把值放在数组里,用一个哈希函数把key换成一个确定位置,然后把value放在数组的这个位置。出现哈希冲突,通过链表来解决。由于哈希表存值是无序的,所以做区间查询时,会扫描整个哈希表,更适用于只有等值查询的场景。
  • 有序数组:有序数组在等值查询和范围查询中性能都非常优秀,但是如果更新了数据,比如往中间插入一个记录,那么需要挪动所有的后面的记录,成本太高了。所以有序数组索引只适用于静态存储引擎,比如某个城市所有人口信息这类不会再修改的数据。
  • 二叉搜索树:左子树不空,则左子树上所有结点的值均小于它的根结点的值; 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值。二叉树是搜索效率最高的,但是索引不止存在内存中,还要写到磁盘上。如果数据量过大,树的节点和高度就会很高,二叉树查询就会很慢,因此需要使用N叉树。
  • N叉树:以InnoDB的一个整数字段索引为例,N差不多1200,树高是4时,可以存储17亿的数据。树根的数据块总是在内存中的,一个10亿行的表上一个整数字段的索引,查找一个值最多访问3次磁盘。N叉树在读写上性能优越,其适配磁盘的访问模式,被广泛应用于数据库引擎中。

 MySQL索引分类


存储结构分类:

  BTree索引(B-Tree或B+Tree),Hash索引,full-index(全文索引),R-Tee索引(空间数据)。
应用层次分类:
  普通索引,唯一索引,复合索引
数据的物理顺序与键值的逻辑顺序分类:
  聚簇(集)索引

一种数据存储方式而非索引类型,具体细节取决于不同的实现。
InnoDB的聚簇索引其实就是在同一个结构中保存,B-Tree索引(技术上来说是B+Tree)和数据行。

  非聚簇(集)索引:不是聚簇索引,就是非聚簇索引


 索引的创建


 普通(单列)索引:

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

新建:CREATE INDEX 索引名 ON '表名'('字段名')
修改:ALTER TABLE 表名 ADD INDEX 索引名('字段名')

 唯一索引:

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

新建:CREATE UNIQUE INDEX 索引名 ON 表名('字段名')

主键索引:

  索引列的值唯一且不允许有空值。建立规则一般是int优于varchar。最好在建表时创建,最好是与表其他字段不相关的列或业务不相关的列。一般设为int而且是AUTO_INCREMENT自增类型的。

复合(组合)索引:
  一个索引包含多个列

新建:CREATE INDEX 索引名 ON 表名('字段1名','字段2名','字段3名')

覆盖索引:

  查询的列要被所使用的索引覆盖,无须从数据表中读取数据。

全文索引:

  可以让查询命令去检索那些包含一个或多个给定单词的数据记录,适用于大量数据通过关键字匹配来查找过滤。

ALTER TABLE 表名 ADD FULLTEXT('列1','列2') 
SELECT * FROM 表名 WHERE MATCH('列1','列2') AGAINST('aaa','bbb')

这条命令会把两个列字段里包含aaa,bbb的数据记录全查出来


  索引底层实现


 B-Tree:

  平衡多路查找树,B-Tree是为磁盘等外存储设备设计的一种平衡查找树,学习前需先了解磁盘相关知识:

  •   系统从磁盘读取数据到内存是以磁盘块(block)为基本单位,位于同一个磁盘块的数据会被一次性读取出来
  •   InnoDB存储引擎中其磁盘管理的最小单位是页(Page),默认大小16KB,通过参数innodb_page_size设置(4K/8K/16K),通过show variables like 'innodb_page_size'进行查看。
  •   系统中一个block的存储空间往往没有这么大,因此InnoDB每次申请磁盘空间都会是若干的址连续的block来达到页的大小,InnoDB把磁盘数据读入内存是以页为单位。
  •   查询数据时,通过索引来定位数据在哪页,再将数据所在页读入内存(如果索引定位数据为6,则把6所在页都读入到内存),MySQL通过条件在内存中筛选数据。

  B-Tree的结构可以让系统高效的找到数据所在的磁盘块。B-Tree的数据存储方式是一个二元数组[key,data]。key为表中的主键值,data为一行记录中除主键外的数据。
一棵m阶的B-Tree特性如下:

  • 每个节点最多有m个孩子
  • 除了根节点和叶子节点外,其他每个节点至少有ceil(m/2)个孩子
  • 若根节点不是叶子节点,则至少有2个孩子
  • 所有叶子节点在同一场,且不包含其他关键信息

 如图所示三阶B-Tree

4.MySQL索引_第1张图片模拟查找关键字29的过程:

  1. 根据根节点所在找到磁盘块1,读入内存(磁盘IO第1次)
  2. 比较关键字29在区间(17~35),找到磁盘1的指针P2
  3. 根据P2指针找到磁盘块3,读入内存(磁盘IO第2次)
  4. 比较关键字29在区间(26~30),找到磁盘3的指针P2
  5. 根据P2指针找到磁盘块3,读入内存(磁盘IO第3次)
  6. 在磁盘8的关键字中找到关键字29

为什么B-Tree比AVLTree快:
  此过程一共发生了3次随机IO,3次内存查找。由于内存中的关键字是一个有序表结构,可以利用二分法查找提高效率,而3次磁盘IO操作是影响整个B-Tree查找效率的决定因素。B-Tree相对AVLTree缩减了节点个数,使每次磁盘IO取到的内存数据都有了作用,从而提高了查询效率。


 B+Tree:

  InnoDB引擎的索引实现利用了B+Tree,B+Tree是在B-Tree基础上的优化,更适用于外存储索引结构。B-Tree的每个节点不仅包含key,还有data值,但每个页的大小有限,如果data数据较大将会导致每个节点(一个页)能存储的key数量很小,当存储数量大时会导致B-Tree深度较大,增大磁盘I/O次数,影响查询效率.
  在B+Tree中,所有数据记录节点都是按照键值大小顺序存放在同一层的叶子节点上,而非叶子节点上只存储key,这样可以大大加大每个节点存储的key值数,降低B-Tree的深度.
B+Tree于B-Tree的不同:

  • 非叶子节点只存储键值信息
  • 所有叶子节点之间都有一个链指针
  • 数据记录都存放在叶子节点中

三阶B+Tree示意图:

 4.MySQL索引_第2张图片

  通常B+Tree上有两个头指针,一个指向根节点,一个指向关键字最小的叶子节点,而且所有叶子节点之间是链式环结构。

  因此B+Tree支持两种查找运算:

    •   对主键的范围查找和分页查找
    •   从根节点开始的随机查找

计算InnoDB的B+Tree存储记录条数:
  假设页的大小为16KB,表的主键是INT(4字节)或BIGINT(8字节),指针类型一般是4或8字节。那么一个页(B+Tree的一个节点)中大概存储【16KB/(8B+8B)=1K】个键值,方便计算此处取10^3。也就是一个深度为3的B+Tree索引可以维护10^3 * 10^3 * 10^3=10亿条记录。实际上每个节点不可能填充满,因此B+Tree一般高度都是2~4层。MySQL的InnoDB引擎是将根节点常驻在内存的,也就是说查找某一行键值的记录最多只需要1~3次磁盘I/O。
  数据库中的B+Tree索引可以分为聚集索引(clustered index)和辅助索引(secondary index)。上面的B+Tree示例图在数据库中的实现即为聚集索引,聚集索引的B+Tree中的叶子节点存放的是整张表的行记录数据。辅助索引与聚集索引的区别在于辅助索引的叶子节点并不包含行记录的全部数据,而是存储相应行数据的聚集索引键,即主键。当通过辅助索引来查询数据时,InnoDB存储引擎会遍历辅助索引找到主键,然后再通过主键在聚集索引中找到完整的行记录数据。
B-Tree索引特点:

  • 能够加快数据的查询速度
  • B-Tree顺序存储索引,适合进行范围查找

B-Tree索引使用限制:

  • 如果不遵循最左前缀原则,则无法使用索引
  • 使用索引时不能跳过索引的列
  • Not in和<> 操作无法使用索引
  • 如果查询中有某个列的范围查询,则其右边所有列都无法使用索引

 哈希索引:

  基于哈希表实现,只有精确匹配索引所有列的查询才有效,对于每一行数据,存储引擎都会对所有的索引列计算一个哈希码,如果多个列哈希码一致,则以链表的方式存放多个记录指针到同一个哈希条目中,哈希索引会将所有的哈希码存在索引中,同时在哈希表中保存指向每个数据行的指针。
哈希索引示意图: 

4.MySQL索引_第3张图片 

示意图解析:

  • keys:代表创建索引的列值A、B、C、D
  • buckets:哈希结构,计算出来的hash值和对应指针存放的链表
  • entries:具体的数据行

创建哈希索引后,通过特定算法为每个键值计算出一个哈希码,有哈希冲突时,如A/C计算出来的都是101,找到101在hash表中存储的位置,然后找到对应存储数据的物理位置,这个位置对应着两条数据A和C,然后再次遍历这两条数据,找到需要的数据。这就是发生冲突导致索引效率低的原因。
限制:

  • 哈希索引只包含了哈希值跟行指针,不存字段值,所以不能使用索引中的值来避免读取行,须进行二次查找,不过访问内存中行的速度很快,性能影响不明显。
  • 哈希索引数据不按索引值顺序存储,不能用于排序
  • 哈希索引不支持部分索引列匹配查找,如(A,B)索引,只查A则无法使用该索引
  • 哈希索引只支持等值比较查询,包括=、IN()、<=>,不支持任何范围查找
  • 访问哈希索引的数据非常快,除非有哈希冲突,出现冲突时,引擎会遍历链表中所有的行指针,直到找到符合条件的行
  • 当哈希冲突很多时,索引维护操作代价会很高

  Memory引擎和NDB集群引擎都支持哈希索引,InnoDB引擎有个特殊功能:自适应哈希索引。当InnoDB注意到某些索引值被频繁使用,它会在内存中基于B-Tree索引之上再创建一个哈希索引,这就可以让B-Tree索引具备哈希索引的一些优点,如快速哈希查找,该行为是自动的内部行为,用户无法配置和控制,但可关闭。
空间数据索引(R-Tree):
  MyISAM支持空间索引,可以用作地理数据存储。这类索引无须前缀查询,空间索引会从所有维度来索引数据,可以有效地使用任意维度来组合查询。


 B-Tree索引的适用类型及限制


B-Tree索引适用于全键值、键值范围或键全缀查找。其中键全缀查询只适用于根据最左前缀的查找。以下图为例,如index(姓名,年龄)

  • 全值匹配:
    •   和索引中的所有列进行匹配,姓名+年龄
  • 匹配列前缀:
    •   也可以只匹配一列的值的开头部分,姓名中姓张的只用第一列,like '张%'
  • 匹配范围值:
    •   查找索引列中值在某一范围的部分,姓名中,姓李和姓张之间,只用第一列
  • 精确匹配某一列并范围匹配另一列:
    •   查找索引中姓张的,但年龄在10到20之间的。即第一列全匹配,第二列范围匹配
  • 最左前缀原则:
    •   B+树的索引结构,可以利用索引的最左前缀,来定位记录。索引项会按照索引定义里出现的字段顺序排序。

索引示意图如下:

4.MySQL索引_第4张图片

 

   需要找张三时,快速定位到ID4,并向后遍历得到所有需要的结果。只要满足最左前缀,就可以利用索引来加速检索。

使用查询时遵循mysql组合索引的"最左前缀":

  • 不按索引最左列开始查询(多列索引),例如index('c1','c2','c3),当where c2 = 'aaa'时不会使用索引,当where c2 ='aaa' and c3 ='bbb'时不会使用索引。
  • 查询中某个列有范围查询,则其右边所有的列都无法使用查询(多列查询),当where c1 ='aaa' and c2 like 'aa%' and c3 = 'bbb' ,该查询只会使用索引中的前两列,因为like是范围查询。  
  • 不能跳过某个字段来查询,这样利用不到索引。比如 where c1 > 'aaa' and c2 = 'bbb' and c3= 'ccc',这样不会使用组合索引,因为第一个索引字段出现了范围查找。

索引下推:
  最左前缀可以用于索引中定位记录,那么不符合最左前缀的部分会怎么处理呢。以上述索引为例,查询表中名字第一个字是张,年龄是10岁的所有人。
  搜索索引树时,会找到满足第一个条件的记录ID3:

  • 在MySQL5.6之前,会从ID3开始一个个回表,到主键索引树上找出数据行再对比字段值,
  • 在MySQL5.6后引入索引下推优化,在索引遍历过程中,对索引中包含的字段先做判断,直接过滤掉不满足条件的记录,减少回表次数

索引排序:
  因为索引树中的节点是有序的,除了按值查找外,还可用于查找中的ORDER BY操作。如果ORDER BY子句满足以上几种查询类型,则这个索引也可以满足对应的排序需求


 InnoDB的索引模型


   在该引擎中,表都是根据主键顺序以索引形式存放,这种方式的表称为索引组织表。InnoDB使用了B+树索引模型,每一个索引在InnoDB里对应一颗B+树。MySQL默认存储引擎InnoDB只显式支持B-Tree( 从技术上来说是B+Tree)索引,对于频繁访问的表,innodb会透明建立自适应hash索引,即在B树索引基础上建立hash索引,可以显著提高查找效率,对于客户端是透明的,不可控制的,隐式的。

以一个主键为ID,表中有字段k并在k上有索引的表为例:

create table T(
id int primary key,
k int not null,
name varchar(16),
index (k))engine=InnoDB;

 InnoDB的索引组织结构如下:

4.MySQL索引_第5张图片

   维护以下值:R1-R5[(100,1)、(200,2)、(300,3)、(500,5)、(600,6)]。主键索引的叶子节点存的是整行数据,非主键索引的叶子节点内容是主键的值。

基于主键索引的查询和普通索引查询的区别:

  • select * from T where ID=500; 该查询只需搜索ID这颗B+树
  • select * from T where k=5;该查询先搜索k索引树,得到ID的值为500,再到ID索引树搜索一次,该过程称为回表。

即基于非主键索引的查询需要多扫描一颗索引树,因此尽量使用主键查询。
  B+树为了维护索引有序性,插入新值时会进行维护,如果插入新值ID为700,则只需要在R5后插入一个新记录,如果插入值ID为400,则需要挪动后面的数据。如果当前R5所在数据页满了,则需要申请一个新的数据页,挪动部分数据,这个过程叫做页分裂。当相邻两个页由于删除数据后,利用率很低时会进行页合并,也叫页分裂的逆过程。
  页分裂除了影响性能外,还影响数据页的利用率,原本一个页的数据,分到了两个月,整体空间利用率降低大约50%。
自增主键的优点:

  • 插入新纪录时可以不指定ID,这种递增的追加不涉及挪动其他记录,也不会触发叶子节点的分裂。
  • 业务逻辑字段做主键,往往不容易保证有序插入,写数据成本相对较高。
  • 主键长度越小,普通索引的叶子节点就越小,普通索引占用的空间也就越小。

适合用业务字段做主键的场景:

  • 只有一个索引。
  • 该索引必须是唯一索引。即典型的Key-Value场景

 高性能的索引策略


 独立的列:

  查询中列不是独立的,则MySQL不会使用索引。独立的列指索引列上不能使用表达式或函数
  如下面两种查询sql,均将索引列作为了表达式,则不会使用索引

SELECT ACTOR_ID FROM TABLE WHERE ACTOR_ID + 1 = 5;
SELECT * FROM TABLE WHERE TO_DATE(START_DAY) - TO_DATE(END_DAY) <= 10;
优化案例:
select..... rom product where to_days(out_date)-to_days(currentdate)<=30 对索引列out_date使用了to_days函数,则不会使用索引
优化后
select...... from product where out_date <= date_add(current_date,interval 30 day)

 前缀索引和索引选择性:

  索引选择性:指索引列中不同值的数目与表中记录数的比。如果一个表中有2000条记录,表索引列有1980个不同的值,那么这个索引的选择性就是1980/2000=0.99。
  选择性越高查询效率越好,选择性高的索引在查询时可以过滤更多的行。唯一索引的选择性是1,性能最好。选择索引时应该选择足够长的前缀以保证较高的选择性。同时不能太长。
  使用索引开始的部分字符,对于BLOB、TEST或很长的VARCHAR类型字段,必须使用前缀索引。
前缀索引优缺点:
  优点:索引更小,更快
  缺点:无法通过该索引做ORDER BY和GROUP BY,也无法覆盖扫描
多列索引:
  在多个列上建立索引,列顺序很重要。对于AND条件导致的索引相交时,最好使用一个包含所有相关列的多列索引,而不是多个独立的单列索引。
选择合适的索引顺序:
  经常被使用到的列优先、选择性高的列优先、宽度小的列优先
聚簇索引:
  聚簇索引是一种数据存储方式,而不是索引类型。InnoDB 的聚簇索引在同一个结构中保存了 B-Tree 索引和数据行。表有聚簇索引时,数据行实际上存放在索引的叶子页中。“聚簇”表示将数据行和相邻的键值存储在一起。因为数据行只能存储在一个地方,所以一个表只能有一个聚簇索引。
优点:

  • 相关数据保存在一起,减少磁盘I/O
  • 数据访问更快,聚簇索引将索引和数据保存在同一个B-Tree,读数据快
  • 使用覆盖索引扫描的查询可直接使用页节点中的主键值

缺点:

  • 聚簇索引提高了 I/O 密集型应用的性能,对于内存型存储引擎用不到。
  • 插入速度严重依赖插入顺序。按主键顺序插入是加载数据到 InnoDB 表中速度最快的方式。
  • 更新聚簇索引列的代价很高。
  • 基于聚簇索引的表在插入新行,或主键被更新导致需要移动行时,可能导致“页分裂”问题。当行的主键值要求必须将这行插入某个已满的页中,存储引擎会将该页分裂成两个页面来容纳该行。
  • 聚簇索引使全表扫描变慢。尤其是行比较稀疏,或页分裂导致数据不连续的时候。
  • 二级索引(非聚簇索引)访问需要两次索引查找,而不是一次。

覆盖索引:
  索引包含(覆盖)所有需要查询的字段的值,覆盖索引必须要存储索引列的值,因此MySQL只用B-Tree来做覆盖索引。
优点:

  • 索引条目通常远小于数据行大小,容易放入内存缓存,且可以减少数据访问量,优化缓存,减少磁盘IO操作
  • 索引按照列值的顺序存储(至少在单个页内如此),对于I/O密集型的范围查找会比随机从磁盘中读取每一行数据的I/O要少得多,减少随机I/O。变随机IO为顺序IO
  • 一些存储引擎如 MyISAM 在内存中只缓存索引,数据需要操作系统缓存,查询数据需要一次系统调用,会造成大开销,覆盖索引可以避免。
  • 由于 InnoDB 的聚簇索引,覆盖索引对 InnoDB 表特别有用。InnoDB 的二级索引在叶子节点中保存了行的主键值,如果二级主键能够覆盖查询,可以避免对主键索引的二次查询。

无法使用覆盖索引的情况:
  存储引擎不支持覆盖索引、查询中使用了太多的列、使用了双%%的like查询
使用索引扫描做排序:
  Mysql生成有序结果的方式:排序操作或按索引顺序扫描。如果EXPLAIN的type值为index则说明MySQL使用了索引扫描来排序。只有当索引列的顺序与ORDER BY子句的顺序完全一致,并且所有列的排序方向都一样时,MySQL才能用索引扫描结果来排序。
  如果查询需要关联张表,只有当ORDER BY子句引用的字段全是第一张表时,才能用索引做排序,需要满足最左前缀原则。只有当前导列为常量时,才可以不满足最左前缀原则。
  例子:表rental中索引(rental_date, inventory_id, customer_id),下面演示ORDER BY 实现索引扫描排序

1、WHERE rental date = '2005-05-25' ORDER BY inventory id DESC;
索引的第一列是查询条件并且是常量,配合索引第二列可作为排序。符合最左前缀
2、WHERE rental date > '2005-05-25' ORDER BY rental_date, inventory_id;
ORDER BY使用的排序字段是索引的两列,并且排序方向一致。满足最左前缀
3、WHERE rental date ='2005-05-25' ORDER BY inventory id DESC, customer id ASC;
ORDER BY使用排序方向不一致,不能使用索引做排序
4、WHERE rental date ='2005-05-25' ORDER BY customer id;
无法组合成最左前缀原则,不能使用索引做排序
5、WHERE rental date > '2005-05-25' ORDER BY inventory_id, customer id
第一列是范围查找,不符合最左前缀原则,不能使用索引做排序
6、WHERE rental date ='2005-05-25' AND inventory_id IN(1,2) ORDER BY customer_id;
在inventory_id列上是范围查找,对排序来说是一种范围查询

 压缩(前缀)索引:

  MyISAM使用前缀压缩来减少索引的大小,从而让更多的索引可以放入内存中。默认只压缩字符串,但通过参数设置也可以对整数做压缩。
MyISAM压缩每个索引块的方法:
  先完全保存索引块中的第一个值,然后将其他值和第一个值进行比较得到相同前缀的宇节数和剩余的不同后缀部分,把这部分存储起来即可。
  例如,索引块中的第一个值是"perform",第二个值是"performance",那么第二个值的前缀压缩后存储的是类似"7,ance"这样的形式。MyISAM对行指针也采用类似的前缀压缩方式。压缩块使用更少的空间,代价是导致某些操作可能更慢。因为每个值的压缩前缀都依赖前面的值,所以MyISAM查找时无法在索引块使用二分查找而只能从头开始扫描。正序的扫描速度还不错,但是如果是倒序扫描---例如ORDER BY DESC就不是很好了。所有在块中查找某一行的操作平均都需要扫描半个索引块。对于CPU密集型应用,扫描需要随机查找,压缩索引使得MyISAM在索引查找上要慢好几倍。CREATE TABLE语句中指定PACK KEYS参数来控制索引压缩的方式。
冗余和重复索引:
  重复索引是指在相同的列上按照相同的顺序创建的相同类型的索引,应该避免。
  冗余索引和重复索引有一些不同。如果创建了索引(A, B),再创建索引(A)就是冗余素引,因为这只是前一个索引的前缀索引。因此索引(A, B)也可以当作索引(A)来使用(这种冗余只是对B-Tree索引来说的),但是如果再创建索引(B, A),则不是冗余索引,索引(B)也不是,因为B不是索引(A, B)的最左前缀列。其他不同类型的索引(例如哈希索引或者全文索引)也不会是B-Tree索引的冗余索引,而无论覆盖的索引列是什么。
  冗余索引通常发生在为表添加新索引时,如已存在索引(A),又新增索引(A,B)而不是扩展,或者扩展为索引(A,ID)ID是主键,对于InnoDB来说主键已经包含在二级索引中,也是冗余的。
未使用的索引:
  一些服务器永远不用的素引,建议删除。可以通过工具来定位。

  1. 在Percona Server或者MariaDB中先打开userstates服务器变量(默认是关闭的),然后让服务器正常运行一段时间,再通过查询INFORMATION SCHEMA. INDEX-STATISTICS就能查到每个索引的使用频率。
  2. 使用Percona Toolkit中的pt-index-usage,该工具可以读取查询日志,并对日志中的每条查询进行EXPLAIN操作,然后打印出关于索引和查询的报告。

索引和锁:
  索引可以让查询锁定更少的行。如果你的查询从不访问那些不需要的行,那么就会锁定更少的行。索引可以加快处理速度,同时也加快了锁的释放
  InnoDB的行锁效率很高,内存使用也很少,但是锁定行的时候仍然会带来额外开销。其次,锁定超过需要的行会增加锁争用并减少并发性,InnoDB只有在访问行的时候才会对其加锁,而索引能够减少InnoDB访问的行数,从而减少锁的数量,但这只有当InnoDB在存储引擎层能够过滤掉所有不需要的行时才有效。如果索引无法过滤掉无效的行,那么在InnoDB检索到数据并返回给服务器层以后,MySQL服务器才能应用WHERE子句性,这时已经无法避免锁定行了,InnoDB已经锁住了这些行,到适当的时候才释放。MySQL5.1后 InnoDB可以在服务器端过滤掉行后就释放锁,但是在早期的MySQL版本中, InnoDB只有在事务提交后才能释放锁。


MyISAM和InnoDB索引相关


 MyISAM和InnoDB实现BTree索引方式:

  MyISAM:
    MyISAM中,B+Tree索引叶子节点的data域存放的是数据记录的物理地址。其主索引和辅助索引在结构上没有区别,只是主索引要求key是唯一的。而辅助索引key可以重复。
    MyISAM索引检索:如果指定key存在则取出其data域的值,然后以该值为地址,读取相应记录
  InnoDB:
    InnoDB不同于MyIASM,在MyISAM中索引文件跟数据文件是分离的,而InnoDB中数据文件本身就是索引文件,表数据文件本身就是一个B+Tree组织的索引结构,叶子节点的data域保存了完整的数据记录。
    索引key是表的主键,在InnoDB中,辅助索引都引用主键作为data域。
MyISAM索引与InnoDB索引的区别:
  MyISAM使用前缀压缩技术使得索引更小,但InnoDB按照原数据格式进行存储
  MyIASM索引通过数据的物理位置引用被索引的行,而InnoDB根据主键引用被索引的行。
  在MyISAM中:.myi后缀文件就是索引文件。在InnoDB中:.ibd后缀文件就是存放索引文件和数据。


 参考文献:

  • 高性能MySQL第三版
  • 极客时间:MySQL45讲
  • 扛得住的MySQL数据库架构:https://coding.imooc.com/class/chapter/49.html#Anchor

你可能感兴趣的:(4.MySQL索引)