InnoDB存储引擎索引 InnoDB支持B+树索引、全文索引和哈希索引。
B+树索引就是传统意义上的索引,是目前关系型数据库中查找最为常用和最为有效的索引。 InnoDB存储引擎会根据表的使用情况自动为表生成哈希索引,不能人为敢于是否在一张表中生成哈希索引。
数据结构与算法 二分查找法 也叫折半查找,必须是一组有序的记录数组。具体详见《二分查找法》。
二叉查找树与平衡二叉树 二叉查找树中,左子树的键值总是小于根的键值,右子树的键值总是大于根的键值。
前序遍历:根 -> 左 -> 右 中序遍历: 左 -> 根 -> 右 后序遍历: 左 -> 右 -> 根
当一个二叉查找树的每个结点只有左子树或者只有右子树时,该数据结构退化成了链表,查找性能会变低,时间复杂度变成O(n).
平衡二叉树:在二叉树的基础上,必须满足任何结点的两个子树高度最大差1. 平衡二叉树的查询速度极快,但是维护一颗平衡二叉树的代价非常大。 需要经过1次或者多次左旋和右旋来得到插入或者更新后的平衡树。
B+树 B+树由B树和索引顺序访问方法演化而来,为磁盘或者其他直接存取辅助设备设计的一种平衡查找树。 在B+树中,所有记录结点都是按照键值的大小顺序存放在同一层的叶子结点上,由各个叶子结点指针进行连接。
B+树的插入 B+树的插入必须保证插入后叶子结点中的记录依然排序,同时要考虑插入到B+树的三种情况,每种情况都可能会导致不同的插入算法。
1)叶子页未满,索引页未满:直接将记录插入到叶子结点。 2)叶子页已满,索引页未满: 2.1)拆分LeafPage 2.2) 将中间的结点放入到IndexPage中 2.3)小于中间结点的记录放在左边 2.4) 大于或者等于中间结点的记录放在右边 3)叶子页已满,索引页已满: 3.1)拆分LeafPage 3.2) 小于中间结点的记录放左边 3.3) 大于或者等于中间结点的记录放右边 3.4) 拆分索引页IndexPage 4.5) 小于中间结点的记录放左边 4.6) 大于中间结点的记录放右边 4.7) 中间结点放入上一层IndexPage
无论如何变化,B+树总会保持平衡。但是为了保持平衡对于新插入的键值可能需要做大量的拆分页操作。 因为B+树结构主要用于磁盘,页的拆分意味着磁盘的额操作,所以在可能的情况下尽量减少页的拆分。 B+树提供了类似于平衡二叉树的旋转功能。 旋转发生在LeafPage已满,但是其左右兄弟结点没有满的情况下。这时B+树并不会急于去做拆分页的操作,而是将记录转移到所在页的兄弟结点上。在通常情况下,左兄弟回被首先检查用来做旋转操作。
B+树的删除 B+树删除时根据填充因子的变化来衡量(最小填充因子的值为50%)。 删除操作同样必须保证删除后叶子结点中的记录已俨然排序。
叶子结点大于填充因子, 中间结点大于填充因子:直接将记录从叶子结点删除,如果该结点还是IndexPage的结点,用该结点的右结点代替。 叶子结点小于填充因子,中间结点大于填充因子:合并叶子结点和它的兄弟结点,同时更新IndexPage 叶子结点小于填充因子,中间结点小于填充因子:合并叶子结点和它的兄弟结点,更新IndexPage,合并IndexPage和它的兄弟结点。
B+树索引 聚集索引 按照每张表的主键构造一颗B+树,同时叶子结点中存放的是张张表的行记录数据,聚集索引的叶子结点称为数据页。 由于实际的树叶也只能按照一颗B+树进行排序,因此每张表只能拥有一个聚集索引。大多数情况下,查询优化器倾向于采用聚集索引。因为聚集索引能够在B+树索引的叶子结点上直接找到数据。此外定义了数据的逻辑顺序,聚集索引能够特别快地访问针对范围的查询。
数据页存放的是完整的每行的数据,索引页存放的是键值和指向数据页的偏移量Offset。 聚集索引是按照主键逻辑顺序在磁盘存储。
辅助索引 对于辅助索引,叶子结点除了包含键值意外,每个结点中的索引行中包含了聚集索引键。 每张表中可以有多个辅助索引,当通过辅助索引来寻找数据时,InnoDB存储引擎会遍历并通过叶子级别的指针获得指向主键索引的主键,然后再通过主键索引来找到一个完整的行记录。
B+树索引的分裂 InnoDB存储引擎的PageHeader中包含了Page_Last_Insert、Page_Direction、Page_N_Direction,通过这几个参数来决定向左分裂或者向右分裂。
如果插入是随机的,则取页的中间记录作为分裂点的记录。 如果向同一方向进行插入的记录数量是5,并且目前已经定位到的记录之后还有3条记录,则分裂点的记录为定位到的记录后的第三条记录,否则分裂点记录就是待插入的记录。
B+树索引的管理 只对表中b字段的前100个字符创建索引。
1 alter table t add key idx_b(b(100));
查看t表中的所有索引。
在非高峰时期执行以下语句,更新索引Cardinality信息,使得优化器和索引可以更好的工作。
生产环境创建索引时遇到的问题:
临时表方式创建索引 先创建临时表,导入数据,创建索引然后修改临时表名称。
Fast Index Creation FIC在辅助索引创建的过程中对表加了S锁,因此在创建的过程中之能对该表进行读操作,如果有大量的食物需要对目标表进行写操作,那么数据库的服务同样不可用。 FIC方式只限于辅助索引,对于主键的创建和删除需要重建一张表。
Online Schema Change PHP脚本维护,且在进行OSC过程中,允许SET sql_bin_log=0, 因此所做的操作不会同步到slave服务器,可能导致主从不一致的情况。
Online DDL 允许辅助索引创建的同时,还允许Insert、UPdate、Delete等DML操作,极大地提高了Mysql数据库在生产环境的可用性。 还可以在线的操作以下命令:
1 2 3 4 辅助索引的创建与删除 改变自增长值 添加或者删除外键约束 列的重命名
1 2 alter table table_name add index index_name algorithm={default |INPLACE|COPY}lock ={default |none |shared |exclusive}
algorithm: copy: 临时表方式创建索引 inplace:不需要创建临时表(默认) default:根据参数old_alter_table判断通过copy或者inplace算法。 lock: 创建索引或者删除索引时对表解锁的情况。 none: 不加锁,任意读写操作都不会收到阻塞。 share: 与FIC类似,执行索引创建或者删除操作时,对目标加S锁。可以并发读,阻塞写事务。 exclusive:执行索引创建或者删除时,对表增加一个X锁,阻塞所有的读写事务。 default:通过判断事物的最大并发性来判断执行DDL模式。none -> share-> exclusive.
远离:在执行创建或者删除操作时,将INsert、UPDATE、DELETE等DML操作日志写入缓冲中,等待索引创建完成后,再将重做应用到表上,达到数据一致性。因此索引在创建过程中SQL优化器不会选择正在创建中的索引。 缓存大小由innodb_online_alter_log_max_size=128MB控制。
Cardinality值 表示索引中不重复记录数量的预估值。InnoDB根据Cardinality来决定是否使用该索引。 Cardinality的值是通过采样的方法来完成的。
当insert、update的数据占有表中数据的1/16时。 每一行的更新次数:stat_modified_counter > 2 000 000 000时 就会更新Cardinality值。
当执行以下命令时会导致InnoDB存储引擎重新计算Cardinality值:
1 2 3 4 analyze table show table status show index 访问information_schema 下的表tables和表statistics
B+树索引的使用 不同应用中B+树索引的使用 OLTP应用和OLAP应用中索引的使用。
联合索引 覆盖索引 从辅助索引就可以查询到想要的数据,而不需要再查一次聚集索引中的记录。
优化器选择不使用索引的情况 当优化器发现辅助索引不能进行索引覆盖时,并且查找的数据量比较大时会放弃辅助索引,转向全表扫描。
使用force index();
Multi-range Read优化 为了减少磁盘的随机访问,并且将随机访问转化为较顺序的数据访问。
MRR的好处:
MRR 使得数据访问变得较为顺序,在查询辅助索引时,首先根据得到的查询结果,按照主键进行排序,并按照主键排序的顺序进行书签查找。
减少缓冲池中页被替换的次数
批量处理对键值的查询操作
对于InnoDB和MyISAM存储引擎的范围查询和JOIN查询操作,MRR的工作方式如下:
将查询得到的辅助索引键值存放在一个缓存中,这时缓存中的数据时根据辅助索引键值排序的。
将缓存中的键值根据rowID进行排序
根据rowID的排序顺序来访问实际的数据文件。
如果InnoDB或者MyISAM存储引擎的缓冲池不是足够大,不能存放下一张表中的所有数据,此时频繁的离散读操作还是会导致缓存中的页被替换出缓冲池,然后又不断地被读入缓冲池。如果按照住建顺序进行访问,就可以将重复行为降到最低。 可以通过optimizer_swith中的flag来控制,当mrr为on时表示启用mrr优化。 mrr_cost_based标记表示是否通过cost_based方式选择是否启用mrr。 如果mrr = 0n , mrr_cost_based=off , 表示总启用mrr。
SET @@optimizer_switch=’mrr=on,mrr_cost_based=off’;
IndexConditionPushDown优化 IndexConditionPushDown 会在读取索引的同时,判断是否可以进行WHERE条件的过滤从而提升性能。
HASH算法 Hash表 InnoDB存储引擎中的哈希算法 自适应哈希索引 全文检索 倒排索引 InnoDB全文索引 全文检索