1.索引
索引是一种数据结构,如果没有索引,查找一个数据就需要从第一页开始全局检索直至找到需要的数据,有了索引可以先在目录中根据拼音查找到该数据所在的页数,因此通过索引可以大大减少了查询时间。
索引有两种存储类型:B树(BTREE)索引和哈希(HASH)索引,InnoDB和MyISAM存储引擎支持BTREE索引,INNODB支持自适应HASH,MEMORY默认HASH索引。
1.1 B+索引
1)因为二叉树每个节点只存储一条记录,数据量大会导致深度过深,查询会增加磁盘【MySQL数据存在磁盘,默认页根节点即第一页的数据存储在内存,每次读取数据都是从磁盘加载到内存的】IO次数;2)所以变种了B树:N叉节点【高度降低,查询速度变快】,且每个节点都可存储数据一页16KB(=磁盘块),通过中序遍历去查找;3)再升级为B+树,只叶子节点存数据,其余节点存关键字,层级更小,且叶子节点带有双向链表,可通过next快速访问,查询速度更快,更适合做存储引擎索引。
其设计逻辑是这样的:1)内存读写快,磁盘读写慢,而且慢很多
2)磁盘预读:磁盘读写并不是按需读取,而是按页预读,一次会读一页的数据,每次加载一些看起来是冗余的数据,如果未来要读取的数据就在这一页中,可以避免未来的磁盘读写,提高效率(通常,一页数据是4KB),innodb是16KB
3)局部性原理:软件设计要尽量遵循“数据读取集中”与“使用到一个数据,大概率会使用其附近的数据”,这样磁盘预读能充分提高磁盘IO效能。
B树特征:
- 根节点至少包含两个孩子
- 树中每个结点最多含有m个孩子(m >= 2)
- 除了根节点和叶结点外,其他每个结点至少含有ceil(m/2)个孩子,ceil为向上取整
- 所有叶子结点位于同一层(高度相同)
1.1.1二叉查找树
节点中存储了键(key)和数据(data)。键对应 user 表中的 id,数据对应 user 表中的行数据,通常意味着所有的值按照顺序存储,二叉查找树的特点就是任何节点的左子节点的键值都小于当前节点的键值,右子节点的键值都大于当前节点的键值。顶端的节点我们称为根节点,没有子节点的节点我们称之为叶节点。利用二叉查找树我们只需要 3 次即可找到匹配的数据。如果在表中一条条的查找的话,我们需要 6 次才能找到。
1.1.2平衡二叉树(AVL)
二叉树如果高度过高,会变得不平衡,查找也会变慢,所以需要平衡二叉树,在满足二叉查找树的前提下,要求每个节点左右子树的高度不超过1。平衡二叉树保证了树的构造是平衡的,当我们插入或删除数据导致不满足平衡二叉树不平衡时,平衡二叉树会进行调整树上的节点来保持平衡。
1.1.3 B-树
以下为3阶树,节点个数>=3,就会生成新的节点。
以下节点的形成说明,使用自增ID,然后追加数据的时候移动范围小,减少索引的维护成本!!!
因为内存的易失性。一般情况下,我们都会选择将 user 表中的数据和索引存储在磁盘这种外围设备中,但和内存相比,从磁盘中读取数据的速度会慢上百倍千倍甚至万倍,所以应当尽量减少从磁盘中读取数据的次数。另外,从磁盘中读取数据时,都是按照磁盘块来读取的,并不是一条一条的读。如果我们能把尽量多的数据放进磁盘块中,那一次磁盘读取操作就会读取更多数据,那我们查找数据的时间也会大幅度降低。如果我们用树这种数据结构作为索引的数据结构,那每查找一次数据就需从磁盘中读取一个节点,也就是我们说的一个磁盘块。
我们都知道平衡二叉树是每个节点只存储一个键值和数据的,那如果我们要存储海量的数据呢?我们应该寻找一种单个节点可以存储多个键值和数据的平衡树。也就是我们接下来要说的 B 树。B 树(Balance Tree)即为平衡树的意思:
p 节点为指向子节点的指针,二叉查找树和平衡二叉树其实也有,因为图的美观性,被省略了,每个节点称为页,页就是我们上面说的磁盘块,在 MySQL 中数据读取的基本单位都是页,所以我们这里叫做页更符合 MySQL 中索引的底层数据结构。B 树相对于平衡二叉树,每个节点存储了更多的键值(key)和数据(data),并且每个节点拥有更多的子节点,子节点的个数一般称为阶上述图中的 B 树为 3 阶 B 树,高度也会很低。
基于这个特性,B 树查找数据读取磁盘的次数将会很少,数据的查找效率也会比平衡二叉树高很多,假如我们要查找 id=28 的用户信息,那么我们在上图 B 树中查找的流程如下:
- 先找到根节点也就是页 1,判断 28 在键值 17 和 35 之间,那么我们根据页 1 中的指针 p2 找到页 3。
- 将 28 和页 3 中的键值相比较,28 在 26 和 30 之间,我们根据页 3 中的指针 p2 找到页 8。
- 将 28 和页 8 中的键值相比较,发现有匹配的键值 28,键值 28 对应的用户信息为(28,bv)。
1.1.4 B+树
B+ 树是对 B 树的进一步优化, B+ 树中各个页之间是通过双向链表连接的,叶子节点中的数据是通过单向链表连接的。B树和B+树的区别:
①B+ 树非叶子节点上是不存储数据的,仅存储键值【如果不存储数据,那么就会存储更多的键值,相应的树的阶数(节点的子节点树)就会更大,树就会更矮更胖,如此一来我们查找数据进行磁盘的 IO 次数又会再次减少,数据查询的效率也会更快】,而 B 树节点中不仅存储键值,也会存储数据。
②因为 B+ 树索引的所有数据均存储在叶子节点,而且数据是按照顺序排列的。
那么 B+ 树使得范围查找,排序查找,分组查找以及去重查找变得异常简单。而 B 树因为数据分散在各个节点,要实现这一点是很不容易的。
1.2 Hash索引
Memeory默认Hash索引。普通的哈希算法是取余,即对每个数&&00001111,大抵情况下来只是低位发生了变化;所以可以使其高位向低位移动,使数据散列更加均匀放置,hash的数据会放入内存,且大多数查询不只是=查询,不支持范围查询,所以不合适。
1.3 聚集索引、非聚集索引:数据和索引是否聚集存储的
①聚集索引(聚簇索引):是基于主键创建的索引,
叶子节点中,索引关键字和数据是在一起存放的,在磁盘存储上,InnoDB聚集索引存在两个文件:student.frm(存储表的结构)||student.ibd(存放索引和数据)。聚集索引并不是仅仅是一种索引类型,还代表的一种数据存储方式。并且表必须有一个主键,如果没有主键InnoDB会默认选择一个隐藏列(rowid),作为主键索引来存储表的数据,一般情况是建议自增id作为主键。有连续性的在磁盘下入性能和检索性能上都会很高。如果使用uuid这种随机id的话,频繁插入会导致磁盘随机io,从而性能下降。并且一个表只能存在一个聚集索引,如果有多个就会有多套副本,浪费磁盘空间,并且当操作的时候会让数据维护更困难。
②非聚集索引(非聚簇索引):索引文件和数据文件是分离的。MyISAM引擎索引结构的叶子节点的data域存放的并不是实际的数据记录,而是数据记录的地址。student.frm(存储表的结构)||student.MYD(存储表的数据) ||student.MYI(存放表的索引数据)。非聚集索引子节点存放的不是实际数据,而是指向实际数据的指针,一个表中可以拥有多个非聚集索引。
利用聚集索引查找数据:表中的数据存储在其中
利用非聚集索引查找数据:
我们最终会找到主键值 47,找到主键后我们需要再到聚集索引中查找具体对应的数据信息,此时又回到了聚集索引的查找流程。
明白了聚集索引和非聚集索引的定义,我们应该明白这样一句话:数据即索引,索引即数据。
1.3.1 为什么不用红黑树?
答:红黑树多用于内部排序,即全放在内存中;B+树多用于外存上时,B+也被成为一个磁盘友好的数据结构;红黑树和平衡二叉树有相同缺点,每个节点存储一个关键词,数据量大时,导致红黑树的深度很深,mysql每次读取时消耗大量io。
1.3.2 为什么建议使用连续id?
答:有连续性的在磁盘写入性能
和检索性能
上都会很高。如果使用uuid这种随机id的话,频繁插入会导致磁盘随机io,从而性能下降。
1.3.3 为什么一个表只有一个聚集索引?
答:如果有多个就会有多套副本
,浪费磁盘空间,并且当操作的时候会让数据维护更困难。
1.3.4 mysql的索引一般有几层?
答:一般情况下,3到4层足以支撑千万级别的查询
1.3.5 创建索引的字段是长了好还是短了好?
答:短了好,因为短的花,一个页datapage可以存储更多的数据。
1.3.6 创建表的时候用代理主键还是自然主键?
答:尽可能使用代理主键【 自然主键 事物属性中的自然唯一标识,常见的例子有:身份证号、手机号、学号等;代理主键(推荐使用) 与业务无关、无意义的数字序列值,例如数据库当中的表主键】
1.3.7 主键设置好之后,要不要自增?
答:在满足业务的情况下尽可能自增【B+树的移动范围最小】,不自增会增加索引的维护成本。
1.3.8 分布式场景下,自增id无效,该如何处理?
答:雪花算法,snowflake,自定义id生成器有很多,原理:使用一个 64 bit 的 long 型的数字作为全局唯一 ID。在分布式系统中的应用十分广泛,且 ID 引入了时间戳,基本上保持自增的;是 64 位 的二进制,1位是符号位,也就是最高位,始终是0,没有任何意义,因为要是唯一计算机二进制补码中就是负数,0才是正数。41位是时间戳,具体到毫秒,41位的二进制可以使用69年,因为时间理论上永恒递增,所以根据这个排序是可以的。
- 依赖服务器时间,服务器时钟回拨时可能会生成重复 id。算法中可通过记录最后一个生成 id 时的时间戳来解决,每次生成 id 之前比较当前服务器时钟是否被回拨,避免生成重复 id。
1.3.9 mysql的回表?
创建联合索引就不会回表了!!!
ID直接查出结果
因为是根据主键的查询方式,则只需要搜索 ID 这棵 B+ 树,树上的叶子节点存储了行记录,根据这个唯一的索引,MySQL 就能确定搜索的记录
* EXPLAIN SELECT * FROM t_back_to_table WHERE id = 3;
需要回表:
普通索引也叫二级索引,除聚簇索引外【存值】的索引都是普通索引,即非聚簇索引【存储了指针地址】
因为通过 drinker_id 这个普通索引查询方式,则需要先搜索 drinker_id 索引树(该索引树上记录着主键ID的值),然后得到主键 ID 的值为 3,再到 ID 索引树搜索一次。这个过程虽然用了索引,但实际上底层进行了两次索引查询,这个过程就称为回表。
* SELECT * FROM t_back_to_table WHERE drinker_id = 3;
1.3.10 覆盖索引?
1.3.11 最左索引?
答;最左前缀原则,顾名思义,就是最左边的优先。。指的是联合索引中【联合索引中的字段(name,age)都应该出现在索引树上的】,优先走最左边列的索引。如 index(a,b,c) 联合索引,则相当于创建了 a 单列索引,(a,b)联合索引,和(a,b,c)联合索引
参考:最左索引问题?_冬子一定要努力的博客-CSDN博客_最左索引
1.3.13 索引下推?
答:索引下推在非主键索引上的优化,可以有效减少回表的次数,大大提升了查询的效率,可设置参数关闭:set optimizer_switch='index_condition_pushdown=off';
5.6之后:
1.3.14 explain个参数详解:
id | SELECT识别符。这是SELECT的查询序列号 |
select_type | SELECT类型,可以为以下任何一种:
|
table | 输出的行所引用的表 |
type | 联接类型。下面给出各种联接类型,按照从最佳类型到最坏类型(由上到下性能逐渐变差)进行排序:
|
possible_keys | 指出MySQL能使用哪个索引在该表中找到行,表示查询时可能使用的索引。 |
key | 显示MySQL实际决定使用的键(索引)。如果没有选择索引,键是NULL。 |
key_len | 显示MySQL决定使用的键长度。如果键是NULL,则长度为NULL。 |
ref | 显示使用哪个列或常数与key一起从表中选择行。 |
rows | 显示MySQL认为它执行查询时必须检查的行数。多行之间的数据相乘可以估算要处理的行数。 |
filtered | 显示了通过条件过滤出的行数的百分比估计值。 |
Extra | 该列包含MySQL解决查询的详细信息:
|
参考:
MySQL索引-B+树(看完你就明白了)_拿钢叉的闰土的博客-CSDN博客
2.词法分析器
mysql里的全文索引不怎么用,类似于ES。