Skip to content

Commit 188c45f

Browse files
committed
MySQL索引
1 parent f6af48a commit 188c45f

3 files changed

Lines changed: 149 additions & 6 deletions

File tree

Interview/sad/MySQL索引.md

Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
> 这一块,最好能知道怎么优化
2+
3+
面试官:索引介绍一下
4+
5+
我:ok,先说一下**索引类型**
6+
7+
- FULLTEXT:即为全文索引,目前只有MyISAM引擎支持。其可以在CREATE TABLE ,ALTER TABLE ,CREATE INDEX 使用,不过目前只有 CHAR、VARCHAR ,TEXT 列上可以创建全文索引。
8+
- HASH:由于HASH的唯一及类似键值对的形式,很适合作为索引。 HASH索引可以一次定位,不需要像树形索引那样逐层查找,因此具有极高的效率。但是,这种高效是有条件的,即只在“=”和“in”条件下高效,对于范围查询、排序及组合索引仍然效率不高。
9+
- BTREE:BTREE索引就是一种将索引值按一定的算法,存入一个树形的数据结构中(二叉树),每次查询都是从树的入口root开始,依次遍历node,获取leaf。这是MySQL里默认和最常用的索引类型。
10+
- RTREE:RTREE在MySQL很少使用,仅支持geometry数据类型,支持该类型的存储引擎只有MyISAM、BDb、InnoDb、NDb、Archive几种。 相对于BTREE,RTREE的优势在于范围查找。
11+
12+
再说一下**索引种类**
13+
14+
- 普通索引:仅加速查询
15+
- 唯一索引:加速查询 + 列值唯一(可以有null)
16+
- 主键索引:加速查询 + 列值唯一(不可以有null)+ 表中只有一个
17+
- 组合索引:多列值组成一个索引,专门用于组合搜索,其效率大于索引合并
18+
- 全文索引:对文本的内容进行分词,进行搜索
19+
- 索引合并:使用多个单列索引组合搜索
20+
- 覆盖索引:select的数据列只用从索引中就能够取得,不必读取数据行,换句话说查询列要被所建的索引覆盖
21+
- 聚簇索引:表数据是和主键一起存储的,主键索引的叶结点存储行数据(包含了主键值),二级索引的叶结点存储行的主键值。使用的是B+树作为索引的存储结构,非叶子节点都是索引关键字,但非叶子节点中的关键字中不存储对应记录的具体内容或内容地址。叶子节点上的数据是主键与具体记录(数据内容)
22+
23+
其次说**索引结构**
24+
25+
**MyISAM**
26+
1. MyISAM索引文件和数据文件是分离的,索引文件仅保存数据记录的地址,同样使用B+Tree作为索引结构,叶节点的data域存放的是数据记录的地址
27+
2. 在MyISAM中,主索引和辅助索引(Secondary key)在结构上没有任何区别,只是主索引要求key是唯一的,而辅助索引的key可以重复
28+
3. MyISAM中索引检索的算法为首先按照B+Tree搜索算法搜索索引,如果指定的Key存在,则取出其data域的值,然后以data域的值为地址,读取相应数据记录
29+
30+
**InnoDB**
31+
1. InnoDB的数据文件本身就是索引文件,这棵树的叶节点data域保存了完整的数据记录(聚集索引)
32+
2. InnoDB的辅助索引data域存储相应记录主键的值而不是地址
33+
3. 聚集索引这种实现方式使得按主键的搜索十分高效,但是辅助索引搜索需要检索两遍索引:首先检索辅助索引获得主键,然后用主键到主索引中检索获得记录。
34+
35+
补充一下**为什么InnoDB索引是B+**
36+
37+
- Hash索引:Hash索引底层是哈希表,哈希表是一种以key-value存储数据的结构,所以多个数据在存储关系上是完全没有任何顺序关系的,所以,对于区间查询是无法直接通过索引查询的,就需要全表扫描。所以,哈希索引只适用于等值查询的场景。而B+ 树是一种多路平衡查询树,所以他的节点是天然有序的(左子节点小于父节点、父节点小于右子节点),所以对于范围查询的时候不需要做全表扫描
38+
- 二叉查找树:解决了排序的基本问题,但是由于无法保证平衡,可能退化为链表。
39+
- 平衡二叉树:通过旋转解决了平衡的问题,但是旋转操作效率太低。
40+
- 红黑树:通过舍弃严格的平衡和引入红黑节点,解决了 AVL旋转效率过低的问题,但是在磁盘等场景下,树仍然太高,IO次数太多。
41+
- B+树:在B树的基础上,**B+树相对于B树能够有更多的分支,使得这棵树更加矮胖,查询时做的IO操作次数也更少**;此外将叶节点使用指针连接成链表,范围查询更加高效。B+树的**非叶子节点不保存数据**,只保存**子树的临界值**(最大或者最小),所以同样大小的节点,
42+
43+
补充B树:
44+
45+
B树(英语: B-tree)是一种自平衡的树,能够保持数据有序。这种数据结构能够让**查找数据、顺序访问、插入数据及删除的动作,都在对数时间内完成**。B树,概括来说是一个**一般化的二叉查找树**(binary search tree),可以拥有最多2个子节点。与自平衡二叉查找树不同,B树适用于读写相对大的数据块的存储系统,例如磁盘。
46+
47+
- 关键字集合分布在整颗树中;
48+
- 任何一个关键字出现且只出现在一个结点中;
49+
- 搜索有可能在非叶子结点结束;
50+
- 其搜索性能等价于在关键字全集内做一次二分查找;
51+
52+
查询什么时候不走**索引**
53+
54+
1. **模糊查询 %like**
55+
2. **索引列参与计算,使用了函数**
56+
3. **非最左前缀顺序**
57+
4. **where对null判断**
58+
5. **where不等于**
59+
6. or操作有至少一个字段没有索引
60+
7. 需要回表的查询结果集过大(超过配置的范围)
61+
8. **将打算加索引的列设置为NOT NULL,否则将导致引擎放弃使用索引而进行全表扫描**
62+
63+
**索引最左原则:**
64+
65+
**举例子**
66+
如果索引列分别为A,B,C,顺序也是A,B,C:
67+
68+
- 那么查询的时候,如果查询【A】【A,B】 【A,B,C】,那么可以通过索引查询
69+
- 如果查询的时候,采用【A,C】,那么C这个虽然是索引,但是由于中间缺失了B,因此C这个索引是用不到的,只能用到A索引
70+
- 如果查询的时候,采用【B】 【B,C】 【C】,由于没有用到第一列索引,不是最左前缀,那么后面的索引也是用不到了
71+
- 如果查询的时候,采用范围查询,并且是最左前缀,也就是第一列索引,那么可以用到索引,但是范围后面的列无法用到索引(比如,a>= 3 and b = 4 and c = 5; A走索引,bc不走)(比如,a = 3 and b >= 4 and c = 5; a和b走,c不走)
72+
73+
**组合索引的底层其实按照第一个索引排序,从排序里面查第二个索引,以此类推。如果第一个索引失效,或者没有经过第一个索引,后面没发在前面的基础上查询。**
74+
75+
**为什么使用索引?**
76+
77+
- 通过创建唯一性索引,可以保证数据库表中每一行数据的**唯一性**
78+
- 可以大大加快数据的**检索速度**,这也是创建索引的最主要的原因。
79+
- 帮助服务器**避免排序和临时表**
80+
-**随机IO变为顺序IO**
81+
- 可以**加速表和表之间的连接**,特别是在实现数据的参考完整性方面特别有意义。
82+
83+
但是使用索引要看一条准则--- 那就是读写比例,我们知道索引的缺点:
84+
85+
- 当对表中的数据进行增加、删除和修改的时候,**索引也要动态的维护**,这样就降低了数据的维护速度。
86+
- 索引需要**占物理空间**,除了数据表占数据空间之外,每一个索引还要占一定的物理空间,如果要建立簇索引,那么需要的空间就会更大。
87+
- **创建索引和维护索引要耗费时间**,这种时间随着数据量的增加而增加
88+
89+
**你想,如果某个场景,发送10条请求,9条写,1条读。 加索引岂不是在浪费效率和空间?**
90+
91+
面试官:聊聊**explain**
92+
93+
我:好的,不过这一块内容好多,我只说几个关键的吧
94+
95+
1. id : 表示SQL执行的顺序的标识,SQL从大到小的执行
96+
2. select_type:表示查询中每个select子句的类型
97+
3. table:显示这一行的数据是关于哪张表的,有时不是真实的表名字
98+
4. type:表示MySQL在表中找到所需行的方式,又称“访问类型”。常用的类型有: ALL, index, range, ref, eq_ref, const, system, NULL(从左到右,性能从差到好)
99+
5. possible_keys:指出MySQL能使用哪个索引在表中找到记录,查询涉及到的字段上若存在索引,则该索引将被列出,但不一定被查询使用
100+
6. Key:key列显示MySQL实际决定使用的键(索引),如果没有选择索引,键是NULL。
101+
7. key_len:表示索引中使用的字节数,可通过该列计算查询中使用的索引的长度(key_len显示的值为索引字段的最大可能长度,并非实际使用长度,即key_len是根据表定义计算而得,不是通过表内检索出的)
102+
8. ref:表示上述表的连接匹配条件,即哪些列或常量被用于查找索引列上的值
103+
9. rows: 表示MySQL根据表统计信息及索引选用情况,估算的找到所需的记录所需要读取的行数,理论上行数越少,查询性能越好
104+
10. Extra:该列包含MySQL解决查询的详细信息
105+
106+
面试官:慢查询优化
107+
108+
我:我试试
109+
110+
打开慢查询日志
111+
112+
1. 先运行看看是否真的很慢,注意设置SQL_NO_CACHE
113+
2. where条件单表查,锁定最小返回记录表。这句话的意思是把查询语句的where都应用到表中返回的记录数最小的表开始查起,单表每个字段分别查询,看哪个字段的区分度最高
114+
3. explain查看执行计划,是否与1预期一致(从锁定记录较少的表开始查询)
115+
4. order by limit 形式的sql语句让排序的表优先查(这里要注意如果数据量大,要注意了)
116+
5. 了解业务方使用场景
117+
6. 加索引时参照建索引的几大原则
118+
7. 观察结果,不符合预期继续从0分析
119+
120+
121+
122+
咱们知道,使用limit分页查询,offset越大,性能越差,比如:
123+
124+
```sql
125+
-- 以真实的生产环境的6万条数据的一张表为例,比较一下优化前后的查询耗时:
126+
-- 传统limit,文件扫描
127+
select * from table order by id limit 50000,2;
128+
受影响的行: 0
129+
时间: 0.171s
130+
131+
-- 子查询方式,索引扫描
132+
select * from table
133+
where id >= (select id from table order by id limit 50000 , 1)
134+
limit 2;
135+
受影响的行: 0
136+
时间: 0.035s
137+
138+
-- JOIN分页方式
139+
select * from table as t1
140+
join (select id from table order by id limit 50000, 1) as t2
141+
where t1.id <= t2.id order by t1.id limit 2;
142+
受影响的行: 0
143+
时间: 0.036s
144+
```
145+
146+
原因:因为 MySQL 并非是跳过偏移量直接去取后面的数据,而是先把偏移量+要取的条数,然后再把前面偏移量这一段的数据抛弃掉再返回的。比如上面的(50000,2),每次取2条,还要经过回表,发现不是想要的,舍弃。那肯定非常耗时间,而通过子查询通过id索引,只查询id,使用到了innodb的索引覆盖, 在内存缓冲区中进行检索,没有回表查询. 然后再用id >= 条件,进一步的缩小查询范围.这样就大大提高了效率。
147+
148+
而MyISAM,是直接索引是分离的,通过索引文件查到的数据记录地址,不需要回表,直接对应数据记录,效率也很高。

Interview/src/Main.java

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,4 @@
11

2-
public class Main {
3-
4-
public static void main(String[] args) {
5-
final int a = 3;
6-
}
7-
}
82

93

104
class TreeNode {

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@
7575
- [InnoDB和MyISAM](/Interview/sad/InnoDB和MyISAM.md)
7676
- [MySQL的ACID和隔离级别](/Interview/sad/MySQL的ACID和隔离级别.md)
7777
- [MVCC,redolog,undolog,binlog](/Interview/sad/MVCC,redolog,undolog,binlog.md)
78+
- [MySQL索引](/Interview/sad/MySQL索引.md)
7879

7980
## 刷题系列
8081
- [推荐:CS-Notes](https://cyc2018.github.io/CS-Notes/#/?id=✏️-算法)

0 commit comments

Comments
 (0)