MySQL索引设计

一.一张2亿条记录的表,假设一条记录有200字节,查询一条记录使用索引和不使用索引的性能计算

  • 1.假设硬盘的IOPS为100
  • 2.索引长度为:10字节(4字节索引+6字节指针长度)
  • 3.每个页大小为16KB,一个页上可存储索引个数为16k*1024/(6+4)=1638.4
  • 4.一个页可存储的数据大小为16k*1024/200=81,即81行数据
  • 5.找到页就可以找到数据
  • 6.需要页的个数为1638.4*1638.4=2683044
  • 8.页个数乘以页内行数为表大小:2683044*81=217326564,约2亿条记录
  • 9.如果在一棵高为3的树上,只需要3次就能找到需要的记录,需要3/100s,没有索引的话需要400s?

二.binary search-二分查找法

  • 1.对一个有序的集合进行查找
  • 12.取中间值,与需要查找的值比较,如果相等,则查找结束
  • 13.如果查找值比中间值大,则从右边再进行递归二分查找,直到找到
  • 14.如果查找值比中间小,则从左边再进行递归二分查找,直到找到
  • 15.查找时间复杂度为log2(n)

二分查找耗时:最深节点需要4,最快节点需要1,超找每个节点的成本除以节点个数

三.binary search tree - 二叉查找树

1.左边的节点永远比右边节点要小

2.右边的节点永远比左边的节点要大

3.左边和右边的子节点也是一棵二叉查找树

四.balanced binary tree - 平衡二叉树

1.首先得是一棵二叉树

2.左右两边节点的高度差要么为0,要么为1,层级差不会超过1,当层高超过1时,需要旋转保持平衡

3.平衡二叉树插入数字3

五.b-tree - 一个节点可以拥有多于2个节点的平衡多叉树

1.p为指针,每个节点由keys+1指针

2.所有关键字在整棵树中出现,在非叶子节点也可以存储值

3.叶子节点之间没有链表

4.对于m阶b树,每个节点至多拥有m棵子树

5.根节点至少拥有2棵子树

6.除根节点外,其余每个分支节点至少拥有m/2棵子树

7.所有叶子节点都在同一层上

8.有k棵子树的分支节点存储k-1个key,key按照递增顺序进行排列

9.key的数量需要满足ceil(m/2)-1 <= n <= m-1

10.树越高,磁盘IO的也就需要更多,高度与磁盘存取次数成正比

5.1 新节点插入,高度为h的m阶B树操作

1.被插入节点key没有达到m-1的情况,直接插入

2.插入节点key达到m-1,而父节点没有达到m-1的情况,插入key,插入节点分裂,中间key提升到父节点

3.入节点key达到m-1,而父节点也达到m-1的情况,插入key,插入节点分裂 ,中间key提升到父节点,父节点分裂,中间key提升到父父节点

如果一直到根节点都达到了m-1个,那么整棵树增加一层

5.2 删除节点

1.删除节点后还是一棵B-树,直接删除

2.删除节点后,不是一棵B-树,向兄弟节点借key,且兄弟节点有得借的情况,删除key,兄弟节点上移,父节点下移保持平衡

3.如果兄弟节点没得借的情况下,删除,父节点下移,删除空余的叶节点,新节点整体上移

六.b+tree

1.B+树的优势在于存储数据,以便在block-块级别上进行高效的检索,比如说文件系统

2.B-树的非叶子节点和叶子节点都可以存储数据,但是B+树的节点只存储键值(索引)不存储数据,叶子节点才是真正存储数据

3.B+树有非常高的fanout-扇出,即指向其他节点,通常超过100个,因而在查找元素的时候能有效减少I/O操作次数

4.叶子节点之间有链表关系

6.1 B+树操作

1.与B-树类似

2.如果增加值的时候节点满员的情况,则将节点中的值作为新的索引

3.删除的时候,索引的key不会被删除,也不会存在父节点关键字下层的情况

4.叶子节点和父节点未满情况,直接插入

5.叶子结点满员,父节点未满员情况

分裂子节点

将key中间值作为新索引,比如60,提升到父节点

叶子节点的左边为原叶子节点的中间值左边的值,如50,55

叶子节点的右边为,带中间值的索引和原叶子节点的值,加上新插入的值

6.叶子节点满员,父节点满员的情况

在叶子节点合适位置插入新的值

叶子结点分裂,叶子节点中间值上移,右边是新值+原叶子节点分裂后的右边的值

父节点满员,插入叶子节点的中间值

父节点分裂,父节点中间值上移,右边是父节点中间值+原父节点分裂后的右边的值

整棵树增加一层,直到能保持平衡

七.B树与B+树的区别?

不同 B+ B-

关键字数量不同 分支节点有m个关键字,叶子节点也有m个,关键字只是起到索引作用 分支节点有m个子节点但是只有m-1个关键字

存储位置不同 数据存储在叶子节点上所有叶子节点的数据链接起来就是一个有序的完整的数据集 数据存储在每一个节点上,根节点+分支节点+叶子节点

分支节点构造不同 分支节点只存储关键字信息和分支节点指针,也就是索引信息 分支节点不仅存储索引,还存储数据

查询不同 通过所有节点的索引到才能到达叶子节点的数据存储位置,每个数据耗时一致 只要在任何节点上找到数据就可以返回

八.MySQL中HASH索引和B+树索引的区别?

采用哈希算法,将键值转换成哈希值,检索时不需要类似B+树那样从根节点到叶子节点检索数据,只需要一次hash算法就可以定位到数据存储位置

不同 hash B+

查询过程不同 根据hash后的key值一定定位到数据存储位置 每次查找不同数据都需要经过所有节点

查询条件不同 只能满足=/in/<=>查询 还能使用范围查询

排序操作不同 hash后的排序和原始键值排序不一致 索引顺序就是数据顺序

索引列利用不同 组合列之后再计算hash值,因此不能使用部分列进行查找 组合索引可以用上部分列进行查找

全表扫描避免不同 hash值和对应的行指针保存在hash表中,当存在相同hash值时,无法获取数据,需要全表扫描 某些情况也会发生全表扫描

效率 大量hash值相等的情况下,选择率太低效率可能不如B树效率高 每次效率都一样

九.聚簇索引与辅助索引的区别?

Type 聚簇索引 辅助索引

存储数据 每个节点存储行的所有列信息 结点存储列字段key+pk

数据查找 找到pk也就是找到了对应列的所有列信息 书签查找:先查找列key字段,再找到pk,通过pk找到一行数据进而查找到其他列值

数据量存储 每个节点存储数据行不多 每个节点存储更多索引信息

效率 更适合排序场景,因为已经排序范围查询效率更高 需要回表,可能需要消耗性能进行排序

个数 一张表只能有一个聚簇索引 可以有多个辅助索引

十.MySQL的索引类型

10.1 B+树索引

1.Cluster index 聚簇索引

存放了整条记录信息,

在oracle里面成为索引组织表IOT,数据和索引都放在一张表里面,数据是索引,索引也是数据

2.Secondary inex,二级索引,辅助索引,Non clustered index 非聚簇索引

只要存放辅助索引的字段和主键,就是键值+主键

3.B+ Tree index

聚簇索引和辅助索引数据存放,假设主键是int类型

Type Clustered Secondary

索引主键长度 4 bytes 4 bytes

索引指针长度 6 bytes 6 bytes

平均一行记录长度 假设300 bytes 假设300 bytes

一个页大小 16k bytes =16384bytes 16k bytes=16384bytes

平均每个页使用率 70% 70%

扇出指针数目(一个页的大小使用了70%除以索引主键长度,索引长度=主键+指针) 16384 * 70% / (4+6)=1000个指针 16384 * 70% /(4+6)=100个指针

平均每个页能存储的记录数 存放的是一整行数据1638470%/300=35行数据 只存放主键+指针1638470%/(4+6)=1000行数据

层高为2时记录数 100035 条记录 10001000个索引

层高为3时的记录数 1000100035条记录 100010001000个索引

层高为4时的记录数 10001000100035条记录 1000100010001000个索引

10.2表中聚簇索引和辅助索引表现

create table userinfo(

userid int not null auto_increment,

username varchar(30),

registdate datetime,

email varchar(50),

primary key(userid),

unique key idx_username(username),

key idx_registdate(registdate)

);

三个索引分别是主键 userid,唯一键idx_username,普通索引idx_registdate

三个索引可以理解为逻辑上创建了3张表,分别是

1.带有所有字段信息的主键索引表

create table userinfo(

userid int not null auto_increment,

username varchar(30),

registdate datetime,

email varchar(50),

primary key(userid)

);

2.只有usernmae字段+pk的idx_username索引表

create table idx_username(

userid int not null,

username varchar(30),

primary key(username,userid)

);

3.只有registdate字段+pk的idx_registdate索引表

create table idx_registdate(

userid int not null,

registdate datetime,

primary key (registdate,userid)

);

4.唯一索引还可以理解为只有一个列的表,当没有主键的情况下,唯一索引作为主键使用

create table idx_username_constraint(

username varchar(30),

primary key(username)

);

10.3 插入数据时索引的表现

start transaction;

insert into userinfo values (aaa,bbb,ccc);

insert into idx_username_constraint(bbb);

insert into idx_username(bbb,aaa);

insert into idx_registdate(ccc,aaa);

commit;

这就是为什么索引越多,反而引起DML操作变慢的原因

10.4 如何使用B+Tree索引

1.Cardinality 基数

不包含唯一记录的记录数

高选择率的列作为索引

使用B+树索引是为了访问更少的数据

2.Not use B+ Tree index situation 不适用B+树索引的情况

前提是一个辅助索引

需要大量的随机读

访问超过所有行的20%

优化器可能会选择顺序遍历代替索引查找,因而可能会使用主键全表扫描而放弃使用辅助索引

比如要查找10000条记录,每条记录花费0.00003s,则需要30s才能全部找出来

整表有500000条记录,根据主键顺序读每次花费0.00003s,只需要15s全部找出来

3.Compound index 联合索引

多列字段组成的索引,index on(column A,column B)

A列所有排序的,B列没有

能使用索引的情况,只要a条件写在前面

select * from t where a=?

select * from t where a=? and b=?

不能使用索引的情况,把b写在了前面

select * from t where b=?

同时使用a,b列,b列作为排序情况下,直接在索引里排列,不需要再filesort

select * from t where a=? order by b

4.Covering index 覆盖索引

三星索引

第一星:where谓词里的列都在索引中包含,并且作为索引的最开头的列

第二星:order by里有索引的列,与where的列不重复

第三星:select中的列都是剩余的列

select cno,fname

from cust

where lanme=‘xxx‘

and

city=‘cityname‘

order by fname;

(lname,city,fname,cno)或者(city,lname,fname,cno)

不需要通过书签查找法,也即是回表

所有需要的数据都在索引包含的列上了

使用了(A,B)中的B也能用索引的情况:单纯统计记录数不找记录的情况

select count(1) from t where b>=? and b<=?

5.Index with included column 包含列的索引(SQLSERVER)

select email from userinfo where username=‘joe‘

不需要回表,因为索引中含有email这一列

mysql不行,可以通过多创建一张表,该表含有email这一列

以空间换时间,需要同时更新两张表

十一.索引规范

1.单张表索引数量不超过5个

2.单个索引中的字段数不超过5个

3.索引名称全部小写

4.非唯一索引命名:idx_字段名_字段名,idx_age_name

5.唯一索引命名:uniq_字段名_字段名,uniq_age_name

6.组合索引建议包含所有字段名,过长字段名缩写,idx_age_name_add

7.表必须有主键,推荐使用unsigned自增列作为主键

8.唯一键由3个以下字段组成,可使用唯一键作为主键,其他情况使用自增列或者发号器做主键

9.禁止冗余索引,如(a,b,c),(a,b)

10.禁止重复索引,如primary key a, uniq index a,将会占用磁盘空间,增加维护负担

11.禁止使用外键

12.join表查询时,join列的数据类型必须一致,并且要建立索引

13.不在低基数的列上键索引,如性别

14.读选择率高的列建索引,组合索引中,选择率高的列放在最前

15.对字符串使用前缀索引,前缀索引长度不超过8个字符

16.不多过长的varchar字段列键索引,优先考虑前缀索引,CRC32/MD5作为索引

17.合理创建联合索引,(a,b,c)相当于(a),(a,b),(a,b,c)

18.合理使用覆盖索引减少IO,避免排序

十二.总结

12.1 索引的有点

1.加快数据检索效率

2.创建唯一性约束索引,保证表的每一行数据的唯一性

3.加速表和表的连接效率

4.使用分组和排序字句记性数据检索时,可以显著减少查询中的分组和排序的事件

12.2 索引的缺点

1.占用更多的物理存储空间

2.对表中数据进行增加、删除、修改时,索引也需要维护更新,降低了数据的维护效率

12.3 那些情况建议创建索引

1.作为主键的列,有唯一约束的索引列

2.经常被用在select/where的列

3.经常用在表连接的列

4.经常用在order by,group by的列

12.4 覆盖索引,通过索引数据结构,找到所需数据,不需要回表

12.5 联合索引,把过滤性号的字段放在前面

12.6 主键的特点,一个表只能有一个主键,用显示声明的主键,最好用自增长的主键

12.7 不能用索引的情况

1.不经常被搜索的列

2.基数值很低的列

3.长文本字段类型列

12.8 不支持函数索引/表达索引,索引列上使用了函数后,无法使用索引,将会导致全表扫描

https://www.cnblogs.com/hanybblog/p/6485419.html

https://www.cnblogs.com/George1994/p/7008732.html

https://www.cnblogs.com/eudiwffe/p/6207196.html

原文地址:https://www.cnblogs.com/jenvid/p/9022469.html

时间: 2024-08-29 13:24:00

MySQL索引设计的相关文章

深入浅出分析MySQL索引设计背后的数据结构

在我们公司的DB规范中,明确规定: 1.建表语句必须明确指定主键 2.无特殊情况,主键必须单调递增 对于这项规定,很多研发小伙伴不理解.本文就来深入简出地分析MySQL索引设计背后的数据结构和算法,从而可以帮你释疑如下问题: 1.为什么innodb表需要主键? 2.为什么建议innodb表主键是单调递增? 3.为什么不建议innodb表主键设置过长? B-tree(多路搜索树,并不是二叉的)是一种常见的数据结构.使用B-tree结构可以显著减少定位记录时所经历的中间过程,从而加快存取速度.B通常

MySQL 索引设计概要

在关系型数据库中设计索引其实并不是复杂的事情,很多开发者都觉得设计索引能够提升数据库的性能,相关的知识一定非常复杂. 然而这种想法是不正确的,索引其实并不是一个多么高深莫测的东西,只要我们掌握一定的方法,理解索引的实现就能在不需要 DBA 的情况下设计出高效的索引. 本文会介绍 数据库索引设计与优化 中设计索引的一些方法,让各位读者能够快速的在现有的工程中设计出合适的索引. 磁盘 IO 一个数据库必须保证其中存储的所有数据都是可以随时读写的,同时因为 MySQL 中所有的数据其实都是以文件的形式

MySQL索引设计需要考虑哪些因素?

索引小知识 篇幅有限,索引的基本知识我们就不赘述了,在此,我们尝试说明其中的一个小点-----B+树与B树的区别到底是什么. InnoDB是使用B+树来实现其索引功能的.在B+树中,内节点(非叶子节点)存储了行数据的键,而叶子节点存储了所有的行数据,而B树的每个节点都存储了真实的数据.这种数据结构,决定了两者有以下不同点: (1)非叶子节点能存放指针的数据量.因为B树的非叶子节点存放的是整行的数据,占用了较多的空间,所以能存放指针就相对较少,因此整个B树的层数就变高.当数据量比较大时,插入更新会

mysql索引设计原则

索引设计原则 选择唯?一性索引 唯?一性索引的值是唯?一的,可以更更快速的通过该索引来确定某条记录 为常作为查询条件的字段建?立索引 如果某个字段经常?用来做查询条件,那么该字段的查询速度会影响整个表的查询速度.因 此,为这样的字段建?立索引,可以提?高整个表的查询速度 限制索引的数?目 索引的数?目不不是越多越好 每个索引都需要占?用磁盘空间,索引越多,需要的磁盘空间就越?大 修改表时,对索引的重构和更更新很麻烦 越多的索引,会使更更新表变得很浪费时间 尽量量使?用数据量量少的索引 如果索引的

MySQL索引设计一些策略

前言 索引加快了检索的速度,但是却降低了数据列里插入.删除以及修改数值的速度.也就是说,索引降低了许多涉及写入的操作速度.之所以出现这种情况,是由于写入一条数据不仅仅是要写入到数据行,还需要所有的索引都作出相应的改变如更新或是重新编排.MySQL在为检索生成一个执行方案时候,要仔细对索引进行计算,创建过多的索引对查询优化程序就加上了更多的工作,而且当你有太多的索引的时候,MySQL还有可能无法选出最好的索引来使用.于是在选择索引的时候,需要采取一些策略. 策略1 在选择索引列的时候,尽量为用搜索

MySQL索引及Explain及常见优化

MySQL索引设计的原则 1. 搜索的索引列,不一定是所要选择的列.换句话说,最适合索引的列是出现在WHERE 子句中的列,或连接子句中指定的列,而不是出现在SELECT 关键字后的选择列表中的列. 2. 使用惟一索引.考虑某列中值的分布.对于惟一值的列,索引的效果最好,而具有多个重复值的列,其索引效果最差.例如,存放年龄的列具有不同值,很容易区分各行.而用来记录性别的列,只含有" M"和"F",则对此列进行索引没有多大用处(不管搜索哪个值,都会得出大约一半的行)

MySQL 索引性能分析概要

上一篇文章 MySQL 索引设计概要 介绍了影响索引设计的几大因素,包括过滤因子.索引片的宽窄与大小以及匹配列和过滤列.在文章的后半部分介绍了 数据库索引设计与优化 一书中,理想的三星索引的设计流程和套路,到目前为止虽然我们掌握了单表索引的设计方法,但是却没有分析预估索引耗时的能力. 在本文中,我们将介绍书中提到的两种分析索引性能的方法:基本问题法(BQ)和快速估算上限法(QUBE),这两种方法能够帮助我们快速分析.估算索引的性能,及时发现问题. 基本问题法 当我们需要考虑对现有的 SELECT

MySQL 索引与查询优化

本文介绍一些优化 MySQL 索引设计和查询的建议.在进行优化工作前,请务必了解MySQL EXPLAIN命令: 查看执行计划 索引 索引在逻辑上是指从索引列(关键字)到数据的映射,通过索引可以快速的由关键字查找到数据记录.顺序查找复杂度为O(n), 树状索引查找复杂度为O(logn), 哈希索引为O(1). MySQL中的索引一般是指BTree索引, InnoDB存储引擎使用B+树来实现BTree索引. BTree索引保持数据之间的顺序,可以极大的加快精确搜索(=, in).范围搜索(<,>

MySQL索引的设计、使用和优化

原文:http://bbs.landingbj.com/t-0-243071-1.html MySQL索引概述 所有MySQL列类型可以被索引.对相关列使用索引是提高SELECT操作性能的最佳途径.根据存储引擎定义每个表的最大索引数和最大索引长度.所有存储引擎支持每个表至少16个索引,总索引长度至少为256字节.大多数存储引擎有更高的限制. 在MySQL 5.1中,对于MyISAM和InnoDB表,前缀可以达到1000字节长.请注意前缀的限制应以字节为单位进行测量,而CREATE TABLE语句