• 本篇博文记录学习mysql的一些笔记(学习数据库+准备面试
  • 较为抽象的地方不会有很细地记录,可能存在理解不是很精确的地方
  • 然后之前虽然用过数据库但是sql语句也不太会,还是必须要学的(

索引

索引(是Mysql中也叫做键)是存储引擎中用于快速找到记录的一种数据结构

1
SELECT first_name FROM sakila.actor WHERE actor_id = 5;

该语句用于在actor_id列上建立的索引查找值为5的行,然后返回所有包含该值的数据行

索引分为单索引组合索引,单列索引中一个索引只包含一个列,而组合索引中一个索引可以包含多个列(在多个列中创建的单索引并不能提高查询性能)

索引提高了查询速度,但是会降低更新表的速度,因为在更新表的时候也需要对索引文件进行更新

在创建了索引之后,查询会根据语句情况选择使用索引以提高查询效率,快速定位数据,不用扫描表中给定查询的每一行

B-Tree

M阶的B树,每个节点最多有M个子节点,非叶子节点具有至少$ceil(m/2)$个子节点

B树的根节点拥有的子节点数量和上限的内部节点相同,如果根节点不是唯一节点,至少有两个子节点

于是有B树的节点特征:

  • $2\le Count_{root}\le M$
  • $ceil(M/2) \le Count_{internal} \le M$
  • $1\le Count_{Ele_{root}} \le M-1$
  • $(ceil(M/2) - 1) \le Count_{Ele_{noroot}} \le M -1$

B树在进行数据插入、删除的过程中依次检查是否满足条件,自动调整指向子页的指针和指向下一个叶子页的指针来实现树的平衡

B树索引存在的限制:

  • 如果不是按照索引的最左列查找,则无法使用索引
  • 不能跳过索引中的列
  • 如果查询中有某个列的范围查询,则右边所有列都无法使用索引优化查找

哈希索引

哈希索引基于哈希表来实现,只有精确匹配索引中所有列的查询才有效,对于每行数据记录一个哈希码

哈希索引的查找方式比较快,但是存在限制:

  • 哈希索引只包含哈希值和行指针,不存储字段值,不能使用索引中的值来避免读取行
  • 哈希索引数据并不是按照索引值顺序存储的,所以无法用于排序
  • 不支持索引匹配查找
  • 只能支持等值比较查找

创建自定义哈希索引:在B树的基础上创建一个伪哈希索引,使用哈希值而不是键本身来进行索引查找,需要在WHERE子句中使用哈希函数得到对应的哈希值

索引策略

独立的列

在查询的列不是独立的列的情况下,Mysql就不会使用索引来进行查询,其次索引列不能是表达式的一部分或函数的参数

Leetcode-0595 大的国家

在这里,对于单列来说,使用OR没有任何的问题,但在涉及到多个列的情况下,如果选择了某个列属性之后,就会对另外一个进行全扫描。简单来说,在InnoDB中使用OR会导致索引失效。

而索引列不能是表达式的一部分,如下的sql语句无法正常解析

1
SELECT actor_id FROM sakila.actor WHERE actor_id + 1 = 5;

在使用中应该养成简化WHERE条件的习惯:将索引列单独放在比较符号的一侧

前缀索引和索引选择性

需要索引过长的字符串的情况下,会让索引变得大且慢

在这一情况下可以索引开始的一部分字符,大大节约索引空间,但是也会降低索引的选择性(不重复的索引值和数据表的记录总数比值)

而对于BLOB、TEXT、VARCHAR类型的列必须使用前缀索引,Mysql不允许索引这些列的完整长度

前缀索引的诀窍在于要选择足够长的前缀以保证较高的选择性,但是又不能太长(便于节省空间),前缀应该保证选择性接近索引整个列

决定最适合的前缀长度的方法:

找到最常见的值的列表,然后和最常见的前缀列表进行比较

逐渐增加前缀的长度,使得前缀的选择性接近完整列的选择性

假设通过查找得到了最适合的前缀长度,可以添加前缀索引

1
ALTER TABLE TABLE_NAME ADD KEY (COLUMN_NAME(PRE_LENGTH));

ps. mysql无法使用前缀索引做ORDER BYGROUP BY,也无法做业务覆盖扫描

多列索引

在Mysql5.0和更新版本中引入了”索引合并“的策略,一定程度上可以使用表上的多个单列索引来定位指定的行

1
SELECT col1, col2 FROM table Where col1 = "test1" OR col2 = "test2"; 

该条语句会使用全表查询,而不会使用索引,需要改写为UNION的形式

1
2
3
4
SELECT col1, col2 FROM table WHERE col1 = "test1" 
UNION ALL
SELECT col1, col2 FROM table WHERE col2 = "test2"
AND col2 <> 1;

而在Mysql5.0和更新版本中,可以同时使用两个单列索引进行扫描,并且将结果进行合并,其算法有三个变种:OR条件的联合,AND条件的相交以及结合两种情况的联合及相交