索引组织表的主键构造一颗 B+树
B+树索引的本质就是B+树在数据库中的实现。B+树在数据库中有一个特点就是高扇出性,在数据库中B+树一般都在2-4层,因此查找某一键值记录时最多只需要2-4次IO。
在数据库中B+树索引可分为聚集索引(clustered index)和辅助索引(secondary index)。不管是辅助索引还是聚集索引,其在数据库内部都是B+树。聚集索引与辅助索引不同的是聚集索引在叶子节点存放着记录一整行的信息。
1、聚集索引:聚集索引就是按照每张表的主键构造一颗B+树,同时叶子节点中存放着的即为整张表的行记录数据。一般情况下,查询优化器更倾向于采用聚集索引,因为其叶子节点中存放着整个表的记录。由于每张表都只有一个主键(无论是用户指定还是数据库自动创建的),所以每张表都会生成一个B+数聚集索引,而且只有一个。相反,我们可以为一张表指定多个辅助索引。
建立如下数据库:
create table t (
a int not null,
b int,
c int,
primary key (a)
)engine=innodb;
在书库库t中我们指定主键为a,则数据库会自动按照a的值构建B+树索引。B+树索引的一个好处就是它对于主键的排序查找和范围查找非常快。我们在表t中插入如下数据:
INSERT INTO t SELECT 4,1,8;
INSERT INTO t SELECT 5,4,7;
INSERT INTO t SELECT 2,3,4;
INSERT INTO t SELECT 8,4,9;
INSERT INTO t SELECT 7,2,3;
INSERT INTO t SELECT 1,3,3;
INSERT INTO t SELECT 3,6,5;
INSERT INTO t SELECT 10,8,6;
INSERT INTO t SELECT 9,9,1;
INSERT INTO t SELECT 6,7,2;
INSERT INTO t SELECT 14,1,8;
INSERT INTO t SELECT 15,4,7;
INSERT INTO t SELECT 12,3,4;
INSERT INTO t SELECT 18,4,9;
INSERT INTO t SELECT 17,2,3;
INSERT INTO t SELECT 11,3,3;
INSERT INTO t SELECT 13,6,5;
INSERT INTO t SELECT 20,8,6;
INSERT INTO t SELECT 19,9,1;
INSERT INTO t SELECT 16,7,2;
INSERT INTO t SELECT 24,1,8;
INSERT INTO t SELECT 25,4,7;
INSERT INTO t SELECT 22,3,4;
INSERT INTO t SELECT 28,4,9;
INSERT INTO t SELECT 27,2,3;
INSERT INTO t SELECT 21,3,3;
INSERT INTO t SELECT 23,6,5;
INSERT INTO t SELECT 30,8,6;
INSERT INTO t SELECT 29,9,1;
INSERT INTO t SELECT 26,7,2;
对其进行查找和排序:
SELECT * FROM t ORDER BY a;
SELECT * FROM t ORDER BY b;
虽然在sqlyog查询的时候没有明显感觉到查询效率的快慢,但是主键按照索引查询在慢查询当中肯定是更进一步的
误区:隐式转换全表扫描
发生隐式转换时,如果是把数字类型的字段写成字符串影响不是特别大,但是如果把字符类型的字段写成数字会扫描全部索引
B+Tree索引
聚集索引(clustered index)
B+Tree示例图在数据库中的实现即为聚集索引,聚集索引的B+Tree中的叶子节点存放的是整张表的行记录数据。
MySQL InnoDB 类型的表必须明确声明一个主键。
辅助索引(secondary index)
辅助索引的叶子节点并不包含行记录的全部数据,而是存储相应行数据的聚集索引键,即主键。
当通过辅助索引来查询数据时,InnoDB存储引擎会遍历辅助索引找到主键,然后再通过主键在聚集索引中找到完整的行记录数据。
mysql的四种索引类型
主键索引:主键是一种唯一性索引,但它必须指定为PRIMARY KEY,每个表只能有一个主键。
alert table tablename add primary key(`字段名`)
唯一索引:索引列的所有值都只能出现一次,即必须唯一,值可以为空。
alter table table_name add unique index(`字段名`);
#alter table table_name drop index `字段名` , add unique index(`字段名`);#删除旧索引再添加
普通索引 :基本的索引类型,值可以为空,没有唯一性的限制。
alter table table_name add index(`字段名`);
全文索引:全文索引的索引类型为FULLTEXT。全文索引可以在varchar、char、text类型的列上创建。可以通过ALTER TABLE或CREATE INDEX命令创建。对于大规模的数据集,通过ALTER TABLE(或者CREATE INDEX)命令创建全文索引要比把记录插入带有全文索引的空表更快。MyISAM支持全文索引,InnoDB在mysql5.6之后支持了全文索引。
alter table 表名 add FULLTEXT(`字段名`);
查看表的所有索引和删除
#查看:
show indexes from `表名`;
show keys from `表名`;
#删除
alter table `表名` drop index 索引名;
索引的机制
为什么我们添加完索引后查询速度为变快?
传统的查询方法,是按照表的顺序遍历的,不论查询几条数据,mysql需要将表的数据从头到尾遍历一遍
在我们添加完索引之后,mysql一般通过BTREE算法生成一个索引文件,在查询数据库时,找到索引文件进行遍历(折半查找大幅查询效率),找到相应的键从而获取数据
索引的代价
创建索引是为产生索引文件的,占用磁盘空间
索引文件是一个二叉树类型的文件,可想而知我们的dml操作同样也会对索引文件进行修改,所以性能会下降
在哪些column上使用索引?
较频繁的作为查询条件字段应该创建索引
唯一性太差的字段不适合创建索引,尽管频繁作为查询条件,例如gender性别字段
更新非常频繁的字段不适合作为索引
不会出现在where子句中的字段不该创建索引
总结: 满足以下条件的字段,才应该创建索引.
a: 肯定在where条经常使用 b: 该字段的内容不是唯一的几个值 c: 字段内容不是频繁变化。
查看索引的使用情况
show status like '%Handler_read%' ;
handler_read_key:这个值越高越好,越高表示使用索引查询到的次数。
handler_read_rnd_next:这个值越高,说明查询低效。
调优方案
- 一般不用 select*,它会更多消耗 CPU 丶内存丶 IO、网络带宽。先向数据库请求所 有列,然后丢掉不需要的列,另取需要的数据列。
- 覆盖索引(covering index)指一个查询语句的执行只用从索引中就能够取得,不必从数据表中读取。也可以称之为实现了索引覆盖。 当一条查询语句符合覆盖索引条件时,MySQL只需要通过索引就可以返回查询所需要的数据,这样避免了查到索引后再返回表操作,减少I/O提高效率。 如,表covering_index_sample中有一个普通索引 idx_key1_key2(key1,key2)。当我们通过SQL语句:select key2 from covering_index_sample where key1 = ‘keytest’;的时候,就可以通过覆盖索引查询,无需回表 回表-使用非聚簇索引进行查找数据时,需要根据主键值去聚簇索引中再查找一遍完整的用户记录,这个过程叫做回表. 基于多个字段创建的索引我们称为联合索引,创建索引create index idx on table(A,B,C) 称在字段A,B,C上创建了一个联合索引
- 当BLOB和TEXT值太大时,InnoDB会使用专门的“外部”存储区域来进行存储,此时每个值在行内需要1 ~ 4个字节存储一个指针,然后在外部存储区域存储实际的值。在存储时使用了“外部”存储区,会使用磁盘临时表存储。磁盘临时表会导致严重的性能开销,所以要避免使用BLOB和TEXT类型;所有用到Blob类型的地方使用SUBSTRING(column,length)将列值转换为字符串,使用内存临时表;有时候出现mysql出现慢查询但是数据量又不是特别大,并且使用了BLOB和TEXT类型类型的时候查看了执行计划也没有什么头绪的时候可以从这方面考虑一下。dolphinshcduler2.0以前使用大json存储工作流内容的时候明显有这个问题,2.0以后进行了sql拆分
- 在应用优化方面,应避免负向查询和%前缀模糊查询;避免负向查询 NOT、!=、<>、! <、!>、NOT EXISTS、NOT IN、NOT LIKE 等;避免%前缀模糊查询。因为 B+Tree 无 法使用索引,导致全表扫描
- MySQL 子查询大部分情况优化较差,所以禁止未经 DBA 确认的子查询。尤其是 WHERE 中使用 IN id 的子查询,一般可用 JOIN 改写,将小结果集驱动大结果集。
- 在 IN()方面,需要注意控制 IN 的中值的个数,建议 n 小于 200,(参数 eq_range_index_dive_limit)。
- 在大事物和小事物上要尽量避免大事物,因为一条 SQL 只能在一个 CPU 上运算。 如果对于类似高并发的场景,一条大 SQL 并发量特别大占用通道一秒,导致后续的 一直在等,最后雪崩。 所以,尽量拆解成多条简单 SQL。因为简单 SQL 缓存命中率更高,可以减少锁表时 间,用上多 CPU。
- 分页查询一般推荐使用延迟关联解决,性能可以得到有效的提升。因为低效分页速 度过慢,它往往通过使用覆盖索引查询返回需要的主键,再根据主键关联原表获得 需要的数据,大大降低了分页查询的速度。
分页查询常用手法
select 字段名 from 数据表名 limit 初始位置,记录条数
-- 分页查询(offset /fetch next)
select * from 数据表
order by 字段id
offset ((@pageIndex-1)*@pageSize) rows
fetch next @pageSize rows only;
-- 分页查询第2页,每页有10条记录
select * from 数据表
order by 字段id
offset 10 rows
fetch next 10 rows only ;
MySQL 数据复制
MySQL 主备复制基于 Binlog 日志(AliSQL Redo),Dump Thread(主)为每个 Slave 的 I/O Thread 启动一个 Dump 线程,用于向其发送 Binary Log Events。然后,I/O Thread 向 Master 请求二进制日志事件,并保存于中继日志中。最后,SQL Thread 从中继日志中读取日志事件,在本地完成重放。
MySQL 的复制架构主要有主从架构和级联架构。 在主从架构中,主节点将数据同步到多个从节点,上图中显示的一主多从的架构, 也可以利用 MySQL 的多源复制的特性,实现多主一从架构。 在级联架构中,主节点将数据同步到一个从节点,其他的从节点向从节点复制数据。
MySQL 的复制模式主要有异步同步、半同步、加密传输。经常使用的是异步同步和 加密传输。
MySQL 高可用及进阶
MySQL 高可用原理主要包括两个模块。即服务冗余和故障转移。其中,服务冗余是 把服务部署多份,当某个节点不可用时,切换到其他节点。服务冗余对于无状态的 服务是相对容易的。故障转移是当服务冗余之后,当某个节点不可用时,要做到快 速切换。
脑裂指在一个高可用(HA)系统中,当联系着的两个节点断开联系时,本来为一个整体的系统,分裂为两个独立节点,这时两个节点开始争抢共享资源,结果会导致系统混乱,数据损坏。
写一个while循环,每轮ping网关,累计连续失败的次数,当连续失败达到一定次数则运行service keepalived stop关闭keepalived服务。如果发现又能够ping通网关,再重启keepalived服务。最后在脚本开头再加上脚本是否已经运行的判断逻辑,将该脚本加到crontab里面。
MySQL 性能调优负载问题
数据库自治服务简称 DAS
DAS 已拥有 6 大核心自治特性:7 x 24 实时异常检测、故障自愈、 自动优化、智能调参、自动弹性、智能压测。
数据表明,目前约 80%的数据库性能问题,可通过 SQL 优化手段解决,SQL 诊断优 化是提供数据,提高数据库性能和稳定性的关键技术之一。 单 SQL 优化诊断本质是创造条件,发现可以提升的点。比如 SQL 改写、创造 SQL 索引等
MySQL Serverless
MySQL Serverless 以 RCU 为维度对客户资源进行动态弹性,1RCU 约为 2GB 内存和 对应的系统资源。 MySQL Serverless 的实例资源跟随客户负载升高、降低,做秒级弹升和弹降,保障 客户业务稳定。实例弹升弹降过程平滑,客户请求无需中断。实例的存储资源按照 客户使用情况动态扩容。
Group Replication
复制一共有三种形态,即异步复制、半同步复制、组复制。
异步复制保证事务持久化到本地存,异步复制的 RPO>0,当 HA 切换后,会发生主
备数据不一致。
半同步复制保证事务持久化到本地和至少一个副本上,有限 RPO=0,当 HA 切换后,
会发生主备数据不一致。
组复制通过 Paxos 传输 Binlog Events,保证事务持久化到本地和复制到多数个副本 上,有限 RPO=0,当 HA 切换后,主备数据一致。
原理
Group Replication 基于论文《The Database State Machine Approach》实现的, 它主要有四个部分,即状态机复制、原子广博、延迟更新复制以及是冲突检测。 状态机复制,将所有的服务器初始化成同样状态。在所有的节点上,按同样的顺序, 执行同样的操作,每次执行后,其状态都是一致的。 原子广播机制,任何服务器上的消息会广播到其他的服务器上,并且是全局排序的, 所有服务器按同样的顺序收到所有的消息。 延迟更新复制,事务先在本地节点执行,当提交时,将整个事务的 Redo Log 复制 到其他节点。 Reordering Certification Test 基于 Read Set/Write Set 的冲突检测,先到者赢,基 于 Read Set/Write Set 的井发 Apply。