索引概述

Ⅰ、什么是索引

索引是一种提升数据库查询效率的数据结构(咱们说的通常都是B+ tree索引)html

(root@localhost) [test]> show create table l \G
*************************** 1. row ***************************
       Table: l
Create Table: CREATE TABLE `l` (
  `a` int(11) NOT NULL,
  `b` int(11) DEFAULT NULL,
  `c` int(11) DEFAULT NULL,
  `d` int(11) DEFAULT NULL,
  PRIMARY KEY (`a`),        -- 主键
  UNIQUE KEY `c` (`c`),     -- 惟一索引
  KEY `b` (`b`)             -- 普通索引
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
1 row in set (0.08 sec)

一张表能够有多个索引,索引就是对建立索引的这些列进行排序
优势:
使查询速度变得很是快,且这个快基本上和数据量不要紧
缺点:
不少索引都要排序则要对这些索引列进行维护,直接插入原本很快,可是有了索引作ddl操做则代价比较大,虽然说不能太多索引列,可是大场景下很难作到mysql

tips:
主键和惟一索引的区别:sql

  • 一张表只能有一个主键,惟一索引能够有多个
  • 主键不能够为NULL,惟一索引能够

MySQL一张表的大小是多少?

不少人说一张表不能太大,太大要拆表?这么说的两个缘由(oracle没这个说法):
a.MySQL以前的DDL操做,比较麻烦,建立了索引,再作这些会表锁(全局读锁),数据量太大会锁时间太长,也就是以前不支持online ddl嘛。之前都是先在slave上搞,搞好作个主从的切换
b.以前MySQL的索引源代码的实现上有一把大锁,致使性能比较通常,不过没有淘宝这个业务量基本上影响不大,可是5.7也解决了这个问题数据库

综上:MySQL5.7这时候,索引自己已经实现地很完整了(管理和性能两个方面),一亿不是什么问题数据结构

tips:并发

  • 大锁:索引排序的时候作一个split的操做(也不会一直作split),拆分,原本把拆分的两个页锁住便可,可是那时候是整个B+ tree锁住了,并发性就受到影响比较大了,
  • 用MySQL就得上SSD,单表能承受1亿根本不是什么大问题,一个亿和一千万,查询和维护代价基本上都是同样的,五年前五百万分表或许是适合的,如今就算了吧
  • sas盘的iops再怎么优化也只有一千,拆了最可能是管理操做方便点,但也有问题,某个时间点数据不必定一致,好比某个时间点,这个表比另外一个表多一个列,sas五百万或者一千万差很少了,能够作个raid10,ssd作raid5或者不作均可以
  • 电商平台,快递行业,一个月前的订单,归档,用分区表来作,和性能不要紧,只是一个管理操做,也就是说分区表不是用来提高性能的,反而会降低,除非都走分区字段,可是线上查询条件太多太多

再强调:
1.MySQL用SSDoracle

2.拆表不会提高性能工具

3.如今不存在最多多少记录的问题性能

Ⅱ、B+ tree概述

2.1 B+ tree的定义

B+ tree是一种基于块(page)设备的存储中来有效的存取,检索数据的数据结构优化

show variables like 'innodb_page_size';
+------------------+-------+
| Variable_name    | Value |
+------------------+-------+
| innodb_page_size | 16384 |
+------------------+-------+
默认16k,oracle默认8k
看数据库中.ibd文件,大小都是16k的倍数

tips:
文件系统都是基于块的

db                          16k
-----------------------------------
filesystem(xfs)             4k 八个扇区 ,能够调大提高性能
-----------------------------------
disk                        512字节

2.2 B+ tree的构成

  • root leaf
  • none leaf
    非叶子节点存放指针和键值
  • leaf
    叶子节点,用来排序的,存放每一行的完整记录(页子节点之间是有序的,页子里面记录也是有序的)
  • fan out
    扇出,多少个指针,一个块设备能存不少记录,这时候扇出很是大,性能也很是好
    B+ tree基于块设备存储,一个页能存很是多记录,扇出很是高
  • 指针
    指向下一个层级,先找,找不到返回空

该B+ tree高度为2,每一个叶子节点存放4条记录,扇出数为5,叶子节点由小到大有序

tips:
上面说的有序指的是逻辑有序,不是物理的,在磁盘上作不到有序,每一个页之间有指针告诉他下一个页和前一个页,可是物理上可能跨了好几个页

Ⅲ、 B+ tree的维护

插入数据操做

如何插入28这条记录?

先找28所在的页,经过二分查找,找到指针指到的页,若是页中还有空闲就直接插

可是想插70,发现70所在的页已经满了,这时候就会作一个split操做(代价蛮大的),把这个页拆成两个页,最经常使用的是把这个页的中间值(这里是60)提取出来放到上面,两边往下拆

插95呢,发现也满了,想拆,可是发现上一层节点也满了,因此要作两次split

MySQL5.7以前split代价很是大,会把整棵树都锁住,这时候其余记录插入和更新就不方便了,可是一般分页自己也仍是蛮快的额,也不会一直分页,只是页满了的状况才会分,因此问题也不是很大,5.7不会一会儿锁住,会尽可能用小的锁控制并发
插入95以后B+ tree的高度从2变成了3

删数据操做
若是一个页里面的数据不多了则会尝试和它左边或者右边的页进行合并

Ⅳ、索引实践

alter table x add index unique idx_b (b);        -- 在b上建立一个惟一索引
alter table x add index index_a (a);             -- 在a上建立一个普通索引
alter table x drop index index_a;                -- 删除a上面的索引

在线上就不同咯

还记得online ddl表嘛?

5.6以前建立索引并非online的,会对这个表加一个读锁(S lock)只能select不能insert,会阻塞

5.6开始原生支持了在线索引添加,在添加索引过程当中,应用程序对表依然可读可写

online ddl的这段时间内,对表作的操做会先记录到alter table的日志里,这个日志是内存的,若是内存大小过小记不下来就会报错

(root@localhost) [(none)]> show variables like 'innodb_online_alter_log_max_size';
+----------------------------------+-----------+
| Variable_name                    | Value     |
+----------------------------------+-----------+
| innodb_online_alter_log_max_size | 134217728 |
+----------------------------------+-----------+
1 row in set (0.00 sec)

若是线上更新操做比较多,调大这个值set global innodb_online_alter_log_max_size = 128M,这是个全局变量,在my.cnf中也配上

在线索引添加存在的一个问题——主从延时(MySQL逻辑复制,oracle物理复制不存在这个问题)

alter table是执行完以后才告诉从机要执行(事务),从库也顺序执行,当执行到这个在线ddl,其余并行的dml语句,也要等待这个ddl执行完毕后才能并行

同步的是二进制日志,要等事务执行完以后才提交过去,并非物理日志

真正在线上不多用alter table这种方式去执行ddl操做,即便5.7如今对愈来愈多的ddl操做读写不阻塞了,就是由于主从延时

如今就要percona toolkit出场了(备注,除了下面介绍的这个工具,里面的其余工具不建议使用,尽可能使用官方的)

这里面最有用的就是pt-online-schema-change,其余工具官方工具包utlities里面都有了,官方也在作前面那个工具了

这个工具作在线ddl,主从延迟很是小,不是直接操做的,是经过触发器的机制来慢慢加,还有控制延时的参数呢

关于online ddl和pt-osc详见这里

相关文章
相关标签/搜索