自增ID
1、一张表,里面有 ID 自增主键,当 insert 了 17 条记录之后,删除了第 15,16,17 条记录,再把 Mysql 重启,再 insert 一条记录,这条记录的 ID 是 18 还是 15 ?
(1) 如果表的类型是 MyISAM,那么是 18
因为 MyISAM 表会把自增主键的最大 ID 记录到数据文件里,重启 MySQL 自增主键的最大ID 也不会丢失
(2)如果表的类型是 InnoDB,那么是 15
InnoDB 表只是把自增主键的最大 ID 记录到内存中,所以重启数据库或者是对表进OPTIMIZE 操作,都会导致最大 ID 丢失
字符串索引
还有没有其他方式帮助字符串建立索引
比如能够给确定业务需求里面只有按照身份证等值查询的需求,需要给身份证加索引,有没有什么办法,占用更小空间,也能达到相同的查询效率。
第一种方式是使用倒序存储
【基础假设】存储的字符串后半部分的区分度相对更高
身份证最后 6 位,没有重复逻辑,因此最后 6 位可能提供了足够的区分度。
先倒序存储,然后再创建前缀索引。
如果存储身份证的时候倒过来存,每次查询的时候,可以这样:
select field list from t where id card reverse(‘input id card string);
第二种方式使用 hash 字段
可以使用表上再创建一个整数字段,来保持身份证的校验码,同时在这个字段创建索引。
alter table t add id card crc int unsigned, add index(id_card_crc);
每次插入新记录的时候,都同时使用 crc32 这个函数 得到校验码填到这个新字段,校验码可能存在冲突,也就是两个不同的身份证通过 crc32() 函数得到的结果可能是相同的,查询要查询语句 where 部分判断 id_card 的值是精确相同的。
排序
全字段排序 VS row_id排序
全字段排序与row_id排序的区别在于:sortbuffer中存放了啥; 回表查询的次数不一致
对于全字段排序,sortbuffer会存放所有数据,然后在sortbuffer中排序,
对于 InnoDB 表来说,在内存足够的情况下,会优先选择全字段排序的方式。在内存不足的情况下,可能会借用外部文件进行排序。
但如果单行内容较大时,会导致拆分的外部文件过多,进行归并排序时,效率变低。此时会采用 Row_id 的排序方式。
对于 Memory 表来说,会优先选择 Row_id 的排序方式。
MySQL 的一个设计思想:如果内存够,就要多利用内存,尽量减少磁盘访问。 对于 InnoDB 表来说,rowid 排序会要求回表多造成磁盘读,因此不会被优先选择。
如果数据量很大,内存中无法存下这么多,就会使用磁盘临时文件来辅助排序,称为外部排序;
外部排序,MySQL会分为好几份单独的临时文件来存放排序后的数据,一般是磁盘文件中进行归并,然后将这些文件合并成一个大文件;
orderby 排序内部原理
全字段排序
为避免全表扫描,我们需要在 相关字段 字段加上索引。创建索引之后,我们用 explain 命令查看排序语句的执行计划。
Extra 这个字段中存在“Using filesort”表示的就是需要文件排序,MySQL 会给每个线程分配一块内存用于排序,称为 sort_buffer。
sort_buffer_size,就是 MySQL 为排序开辟的内存(sort_buffer)的大小。如果要排序的数据量小于 sort_buffer_size,排序就在内存中完成。但如果排序数据量太大,内存放不下,则不得不利用磁盘临时文件辅助排序。
number_of_tmp_files 表示的是,排序过程中使用的临时文件数。你一定奇怪,为什么需要 12 个文件?内存放不下时,就需要使用外部排序,外部排序一般使用归并排序算法。可以这么简单理解,MySQL 将需要排序的数据分成 12 份,每一份单独排序后存在这些临时文件中。然后把这 12 个有序文件再合并成一个有序的大文件。
如果 sort_buffer_size 超过了需要排序的数据量的大小,number_of_tmp_files 就是 0,表示排序可以直接在内存中完成。
否则就需要放在临时文件中排序。sort_buffer_size 越小,需要分成的份数越多,number_of_tmp_files 的值就越大。
rowid排序
全字段排序方法缺点:单行大的话占用内存空间。通过修改MySQL中专门控制用于排序的行数据的长度的一个参数。意思是,如果单行的长度超过这个值,就会换一种算法
rowid 方式和全字段方式一样,需要先把查询到的结果全部放在内存或硬盘中,再使用相关算法进行排序。而排序后由于没有保存所需的字段,需要按顺序使用主键再从索引树上查询,查到一个就返回一个,而不用把所有内容查完放到内存上再一并返回。
全字段排序 VS rowid 排序
如果 MySQL 实在是担心排序内存太小,会影响排序效率,才会采用 rowid 排序算法,这样排序过程中一次可以排序更多行,但是需要再回到原表去取数据。
如果 MySQL 认为内存足够大,会优先选择全字段排序,把需要的字段都放到 sort_buffer 中,这样排序后就会直接从内存里面返回查询结果了,不用再回到原表去取数据。
这也就体现了 MySQL 的一个设计思想:如果内存够,就要多利用内存,尽量减少磁盘访问。
对于 InnoDB 表来说,rowid 排序会要求回表多造成磁盘读,因此不会被优先选择。
小结
其实,并不是所有的 order by 语句,都需要排序操作的。从上面分析的执行过程,我们可以看到,MySQL 之所以需要生成临时表,并且在临时表上做排序操作,其原因是原来的数据都是无序的。创建联合索引等可以使其选择出来的就是按照索引字段排序的。但是,不能为了每个查询能用上覆盖索引,就要把语句中涉及的字段都建上联合索引,毕竟索引还是有维护代价的,这是一个需要权衡的决定
参考:
https://blog.csdn.net/qq_29066329/article/details/90036836