Mysql索引问题
- 1.页分裂问题,数据不连续导致也分裂有什么弊端?怎么避免或者有什么机制维护这个连续?
- 2.索引用到文件排序 Using filesort,该怎么优化?
- 3.一个3层的树,为什么要做三次io?为什么一次不能查出所有数据的节点以及相对应数据
- 4.如果一条数据1k,一个页可以放16条数据,如果删除其中两条,这两条硬盘空间会不会被回收?如果回收,会造成页移动(或者merge?),如果不回收,又会造成读取的页存在空洞。怎么解决?
- 5.表没主键,但有非null的列,此列有重复的值,这样也是聚集索引吗?
- 6.辅助索引什么情况下查询需要回表,什么情况下不需要回表?
- 7.如果b+树中出现大量的删除和新增操作的时候,mysql是怎么优化避免这种问题的?
- 8.联合主键也是聚集索引吗?如果是的,排序如何处理呢?
- 9.千万级的表用了索引,IO是在什么时候产生的?第一次查询的时候还是提前把数据读到内存?建了索引的表是不是数据都会放在内存中?
- 10.辅助索引在调用主键索引的时候,会经历多次I/O吗?辅助索引中回表是回到主键索引吗?
- 11.在使用"%zi"的时候,索引下推了,还会使用到索引吗?
- 12.mysql存储中文 使用的编码是Unicode吗?
- 13.辅助索引那个 为什么不直接存数据的地址 ,还要回表 多麻烦 ,主键索引中存放的应该是数据在磁盘上的地址信息么?
- 14.Redo.log 和db文件都是在磁盘上的,为什么写redo.log 是顺序io 写db文件就是随机IO呢?为什么先写入日志文件可以提高效率?
1.页分裂问题,数据不连续导致也分裂有什么弊端?怎么避免或者有什么机制维护这个连续?
首先要明白页跟数据行的关系。 InnoDB在叶子上存储数据。一个节点就是一页。
一个页可以存储多行数据,按照主键的顺序存储。当数据是顺序插入的时候,一页写满了,就申请一个新的页。
如果是随机插入,在指定位置的页已经写满了(或者到达了分裂阈值)的时候,就会发生页结构的调整(即B+Tree的节点的分裂)。
2.索引用到文件排序 Using filesort,该怎么优化?
Using filresort代表:不能使用索引来排序,用到了额外的排序。 例如:查询用到了a字段上的idx_a,但是后面有order by
b。 一些优化方式:
- 建立联合索引idx(a,b)
- 不使用MySQL的排序,改成在代码中排序
3.一个3层的树,为什么要做三次io?为什么一次不能查出所有数据的节点以及相对应数据
页(Page)是 Innodb 存储引擎用于管理数据的最小磁盘单位,也就是InnoDB一次I/O(读写磁盘)的逻辑单位大小是16K(默认)。
InnoDB把B+Tree的节点设置为一个Page,所以,读取一个节点,就会发生一次I/O。
3-1.为什么要固定Page大小,而不是需要多少数据,读取多少数据(按需读取)?
设置页的大小与磁盘的预读取特性有关系。局部性原理认为:当一个数据被用到时,其附近的数据也通常会马上被使用。所以顺序读取附近的数据,可以提升I/O效率。每次都至少读取一页
3-2.为什么不把Page设置得更大?这样一次读取到的数据不就更多了吗?
官网有解释,默认的16KB大小,在涉及表扫描和批量更新的业务场景中更实用,效率已经很高了。
4.如果一条数据1k,一个页可以放16条数据,如果删除其中两条,这两条硬盘空间会不会被回收?如果回收,会造成页移动(或者merge?),如果不回收,又会造成读取的页存在空洞。怎么解决?
删除页中的行数据时,不会物理删除,而是先标记为删除,这时空间可以被其他记录实用。
当页中删除的记录达到MERGE_THRESHOLD(默认页体积的50%),InnoDB会开始寻找最靠近的页(前或后)看看是否可以将两个页合并以优化空间使用。
5.表没主键,但有非null的列,此列有重复的值,这样也是聚集索引吗?
- 如果我们定义了主键(PRIMARY KEY),那么 InnoDB 会选择主键作为聚集索引。
- 如果没有显式定义主键,则 InnoDB 会选择第一个不包含有 NULL 值的唯一索引作为主键索引。
- 如果也没有这样的唯一索引,则 InnoDB 会选择内置 6 字节长的 ROWID 作为隐 藏的聚集索引,它会随着行记录的写入而主键递增。
所以答案:no
6.辅助索引什么情况下查询需要回表,什么情况下不需要回表?
select 的列,包含在了使用的索引中。
就像我们要查看第12章的标题,这个标题已经在目录中了,就不用翻到具体页码查看了。
例如索引是index(a,b,c),select 索引里面的列(包括select a,select b,select c,select a,b select a,c select b,c,select a,b,c),都不需要到主键索引的叶子节点获取完整数据,此时不需要回表。
7.如果b+树中出现大量的删除和新增操作的时候,mysql是怎么优化避免这种问题的?
- 减少对主键索引的修改
- 建议在顺序递增的字段上创建主键索引
8.联合主键也是聚集索引吗?如果是的,排序如何处理呢?
在InnoDB中,主键就是聚集索引。所以不管是单列还是多列,都是聚集索引。
联合索引是一个复合结构,按照第一个字段排序。
聚集索引
主键索引
9.千万级的表用了索引,IO是在什么时候产生的?第一次查询的时候还是提前把数据读到内存?建了索引的表是不是数据都会放在内存中?
并不是所有的数据都放到buffer pool中,它的大小是有限的,默认128M,所以只能存储最常用的,最热的数据(通过LRU淘汰)。
读取一个页,就是一次IO。
10.辅助索引在调用主键索引的时候,会经历多次I/O吗?辅助索引中回表是回到主键索引吗?
加载B+Tree的一个节点就是一次I/O。回表是从辅助索引到主键索引。
11.在使用"%zi"的时候,索引下推了,还会使用到索引吗?
加索引从Server下推到存储引擎,会利用下推的条件,对索引进行过滤。
12.mysql存储中文 使用的编码是Unicode吗?
Unicode是字符集。UTF-8是编码规则。保存中文可以用utf8mb4。
U need this
13.辅助索引那个 为什么不直接存数据的地址 ,还要回表 多麻烦 ,主键索引中存放的应该是数据在磁盘上的地址信息么?
因为页分裂会导致数据的地址发生变动。
主键索引的叶子节点,直接存放完整的数据。
14.Redo.log 和db文件都是在磁盘上的,为什么写redo.log 是顺序io 写db文件就是随机IO呢?为什么先写入日志文件可以提高效率?
当buffer pool中有很多数据等待刷脏的时候,写入redo log是顺序追加写入的。
而这些数据在磁盘中的位置不一定是连续的(比如操作id=1 id=9,插入 name =‘a’ name = ‘s’),每次都要重新寻址,所以是随机I/O。
数据写入到redo log里面就有了保障,刷盘就不需要那么频繁了,提升了系统的吞吐量。