MySQL 索引

Posted yujiaershao

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MySQL 索引相关的知识,希望对你有一定的参考价值。

 

什么是索引

  相当于书目录,用于快速检索

  优点

    提高数据检索效率

    提高表间的JOIN效率

    利用唯一性索引,保证数据的唯一性

    提高排序和分组效率

  缺点

    消耗更多物理存储

    数据变更时,索引也需要更新,降低更新效率

  哪种情况下应该创建索引

    经常检索的列

    经常用于表连接的列

    经常排序/分组的列

  索引不使用建议

    基数很低的列

    更新频繁但检索不频繁的列

    BLOB/TEXT 等长内容列

    很少用于检索的列

 

二分查找

  折半查找,binary search

  一种在有序数组中查找某一特定元素的搜索算法

  二分查找发的优点是比较次数少,查找速度快,平均性能好,其缺点是要求待查表为有序表,且插入删除困难,因此,二分查找法适用于不经常变动而查询频繁的有序列表

 

二叉树,binary tree

  二叉树是每个节点至多只有二颗子树(不存在度大于2的节点),二叉树的子树有左右有序之分,次序不能颠倒。

  

平衡树,平衡二叉树, self-balancing binary search tree

  改进的二叉查询树。一般的二叉查找树的查询复杂度是跟目标节点到树根的距离(即深度)有关,因此当节点的深度普遍较大时,查询的均摊复杂度会上升,为了更高效的查询,有了平衡树

  平衡二叉树的特点

    它是一棵空树或其左右两个字数的高度差的绝对值不超过1, 且左右两个子树也是平衡二叉树

    不平衡树会通过自旋,变成平衡树

    平衡树和二叉查找树最大的区别:前者是平衡的,后者未必

 

B树, balanced tree

  又称 B-树,B_树

  B树,一个节点可以拥有多于2个子节点的多叉查找树

  适合大量数据的读写操作,普遍运用在数据库和文件系统

  一颗m阶(比如m=4阶)的B树满足下列条件:

    树中每个节点至多有m个(4个)子节点

    除了根节点和叶子节点外,其它每个节点至少有m/2个(2个)子节点

    若根节点不说叶子节点,则至少有2个字节带你

    所有叶子节点都出现在同一层,叶子节点不包含任何键值信息

    有k个字节的的非叶子节点恰好包含有k-1个键值(索引节点)

 

B+树, B+TREE

  B+树是B树的变体,也是多路搜索树,其定义基本与B树相同,除了:

    有n颗子树的节点中含有n-1个关键字(key) ,每个key不保存数据,只用来索引,所有数据都保存在叶子节点

    所有的叶子节点中包含了全部关键字的信息,及指向含这些关键字记录的指针,且叶子节点本身依赖关键字的大小自小而大顺序链接

    所有的非叶子节点可以看成是索引部分,节点中仅含其子树(根节点)中的最大(或最小)关键字

    在mysql中,为了方便,直接携程BTREE

  假如有个表,只有一个int列,且设置为主键,无其他更多列

    B+树中,每个非叶子节点开销:6B(row header固定开销) +4B(主键为INT类型) +4B(指向叶子节点的指针开销)

    每行数据开销: 14B + 6B (DB_TRX_ID) + 7B (DB_ROLL_PTR)= 27B

    每个非叶子节点 page 存储约 (16 * 1024-128page header)/ 27 = 600 行记录

    因此,一个三层高的B+树,约可存储记录 1161*1161*600 = 8 亿记录

    

哈希索引,Hash Index

  建立在哈希表的基础上,它只对使用了索引中的每个值的精确查找有用

  对于每一行,存储引擎计算出了被索引的哈希码(Hash Code),它是一个较小的值,并且有可能和其他行的哈希码相同

  把哈希码保存在索引中,并且保存了一个指向哈希表中的每一行的指针

  也叫散列索引

 

 

B+树索引 VS  哈希索引

  大量唯一值的等值查询,HASH索引效率通常比 B+TREE高

  HASH 索引不支持模糊查找

  HASH 索引不支持联合索引中的最左匹配规则

  HASH 索引不支持排序

  HASH 索引不支持范围查询

  HASH 索引只能显式应用于 HEAP/MEMORY, NDB表

 

聚集索引,clustered index

  聚集索引是一种索引,该索引中键值的逻辑顺序决定了表数据行的物理顺序

  每张表只能建一个聚集索引,除了TokuDB引擎

  InnoDB中,聚集索引即表,表即聚集索引

  myISAM 没有聚集索引的概念

  聚集索引优先选择列

    int/bigint  

    数据连续(单调顺序)递增/自增

  不建议的聚集索引

    修改频繁的列

    新增数据太过离散随机

 

主键索引,primary key

  主键由表中的一个或多个列组成,用于唯一地标识表中的某一条记录

  在表引用中,主键在一个表中引用来自于另外一个表中的特定记录(外键 foreign key应用)

  保证数据的完整性

  加快数据的操作速度

  主键值不能重复,也不能包含NULL

  主键选择建议

    对业务透明,无意义,免受业务变化的影响

    很少修改和删除

    最好是自增的

    不要具有动态属性,例如随机值

  InnoDB聚集索引选择次序原则

    显式声明的主键

    第一个NOT NULLABLE的唯一的索引

    DB_ROW_ID (实例级,6 bytes)

  主键索引一定是聚集索引

  但聚集索引不一定是主键索引

  InnoDB表一定有聚集索引

  InnoDB主键特点

    索引定义时,不管有无显式包含主键,实际都会存储主键值

    在5.6.9后,优化器已能自动识别索引末尾的主键值,在这之前则需要显示加上主键列才可以被识别。

 

唯一索引 unique key

  不允许具有索引值相同的行,从而禁止重复的索引或键值

  严格意义上讲,应该叫做唯一约束

  在唯一约束上,和主键一样 (以MyISAM引擎为代表)

  其他不同方面

    唯一索引允许有空值(NULL)

    一个表只能有一个主键,但可以有多个唯一索引

    InnoDB表中主键必须是聚集索引,但聚集索引可能不是主键

    唯一索引约束可临时禁用,但主键不行

 

联合索引 combined indexes, multiple-column indexes

  多列组成,所以也叫多列索引

  适合where 条件中的多列组合

  有时候,还可以用于避免回表(覆盖索引)

  MySQL还不支持多列不同排序规则(MySQL8.0起支持)

  联合索引建议

    where条件中,经常同时出现的列放在联合索引中

    把选择性(过滤性/基数)大的列放在联合索引的最左边

 

覆盖索引 covering indexes

  通过索引数据结构,即可之间返回数据,不需要回表

  执行计划中,extra列会显示关键字 using index

     回表: 读取的列不在索引中,需要“回到表找到整条记录取出相应的列”

 

前缀索引  prefix indexes

  部分索引的原因  

    char/varchar 太长全部做索引的话,效率太差,存在浪费

    或者 blob/text类型不能整列作为索引列,因此需要使用前缀索引

  部分索引选择建议

    统计平均值

    满足80%-90%覆盖度就够

  缺点:无法利用前缀索引完成排序

 

InnoDB索引长度

  索引最大长度767bytes

  启用innodb_large_prefix,增加到3072bytes,只针对dynamic,compressed格式管用。(8.0默认3072,不需要启用)

  对于 redundant,compact格式,最大索引长度还是767bytes

  MyISAM表索引最大长度是1000bytes

  最大排序长度默认是1024 (max_sort_length)

 

倒序索引

  8.0开始支持倒序索引

  联合索引可以使用倒序索引

 

不可见索引

  优化器不可见。想删除索引时,可以先隐藏索引

 

函数索引、表达式索引

  8.0.13开始,支持函数索引,表达式索引

  本质上是 generated column

 

跳跃索引 index skip scan

  8.0.13开始,支持skip index scan

  执行计划的extra会显示 using index for skip scan

  针对单表,不能是多表join

  sql中不能有group by 或 distinct

  多列联合索引中,第一列的唯一值很少,且在where条件中未被用到

  set optimizer_switch=‘skip_scan=off‘; 关闭跳跃索引

 

索引并行读

  从8.0.14开始,支持主键索引的并行读

  不支持辅助索引上的并行读

  使得check table的速度更快

  新增选项 innodb_parallel_read_threads

  innodb_parallel_read_threads=4 (默认),check table耗时减少20%

 

索引管理

  创建/删除索引

    alter table t add index idx_c1(c1) using btree;

    create index idx_c1 on (c1) using btree;

    create table 时候直接创建

    alter table t drop index idx_c1;

    drop index idx_c1 on t;    

  冗余索引

    根据最左匹配原则,一个索引是另一个索引的子集

    可以使用工具pt-dumplicate-key-checker检查/schema_redundant_indexex

    重复索引也是冗余的一种,可以直接放心删除

    index k1(a,b,c) , k2 (a,b)  一般认为k2是k1的冗余索引,但是下面sql只有k2才能被使用: where a = ? and b = ? and pk = ?; / where a = ? and b = ? order by pk;

    查看冗余索引: select * from schema_redundant_indexes where table_schema = ‘world‘ \G

  无用索引

    几乎从未使用过的索引

    pt-index-usage检查低利用率的所有,提供删除建议/schema_unused_indexes

    查看无用索引: select * from schema_unused_indexes where object_schema = ‘world‘; \G

  查看每个索引利用率

    select index_name,rows_selected,rows_inserted,rows_updated,rows_deleted from schema_index_statistics where table_schema=‘world‘ and tbale_name = ‘city‘;

 

以上是关于MySQL 索引的主要内容,如果未能解决你的问题,请参考以下文章

mysql索引类型解释

mysql 索引

mysql索引(九)索引合并

mysql覆盖索引和联合索引的区别

mysql---索引优化

MySQL索引