第十六章 SQL优化(一)

目录

一、插入数据优化

1.1. insert

1.2. 大批量插入数据

二、主键优化

2.1. 数据组织方式

2.2. 页分裂

2.2.1. 主键顺序插入效果

2.2.2. 主键乱序插入效果 

2.3. 页合并

2.4. 主键设计及数据插入原则


一、插入数据优化

1.1. insert

如果我们需要一次性往数据库表中插入多条记录,可以从以下三个方面进行优化。

insert into tb_test values(1,'tom');
insert into tb_test values(2,'cat');
insert into tb_test values(3,'jerry');
.....

优化方案一:批量插入数据

Insert into tb_test values(1,'Tom'),(2,'Cat'),(3,'Jerry');
优化方案二:手动控制事务
start transaction;
insert into tb_test values(1,'Tom'),(2,'Cat'),(3,'Jerry');
insert into tb_test values(4,'Tom'),(5,'Cat'),(6,'Jerry');
insert into tb_test values(7,'Tom'),(8,'Cat'),(9,'Jerry');
commit;
优化方案三: 主键顺序插入,性能要高于乱序插入。
主键乱序插入 : 8 1 9 21 88 2 4 15 89 5 7 3
主键顺序插入 : 1 2 3 4 5 7 8 9 15 21 88 89

1.2. 大批量插入数据

如果一次性需要插入大批量数据(比如: 几百万的记录),使用insert语句插入性能较低,此时可以使 用MySQL数据库提供的load指令进行插入。操作如下:

可以执行如下指令,将数据脚本文件中的数据加载到表结构中:

-- 客户端连接服务端时,加上参数 -–local-infile
mysql –-local-infile -u root -p

-- 设置全局参数local_infile为1,开启从本地加载文件导入数据的开关
set global local_infile = 1;

-- 执行load指令将准备好的数据,加载到表结构中
load data local infile '/root/sql1.log' into table tb_user fields terminated by ',' lines terminated by '\n';

我们看到,插入100w的记录,17s就完成了,性能很好。

注意:在load时,主键顺序插入性能高于乱序插入

二、主键优化

前面我们提到,主键顺序插入的性能是要高于乱序插入的。 现在我们就来讲解一下具体的原因,然后再分析一下主键又该如何设计。

2.1. 数据组织方式

InnoDB存储引擎中,表数据都是根据主键顺序组织存放的,这种存储方式的表称为索引组织表 (index organized table IOT)。

行数据,都是存储在聚集索引的叶子节点上的。而我们之前也讲解过InnoDB的逻辑结构图:

InnoDB引擎中,数据行是记录在逻辑结构 page 页中的,而每一个页的大小是固定的,默认16K。那也就意味着, 一个页中所存储的行也是有限的,如果插入的数据行row在该页存储不小,将会存储到下一个页中,页与页之间会通过指针连接。

2.2. 页分裂

页可以为空,也可以填充一半,也可以填充100%。每个页包含了2-N行数据(如果一行数据过大,会行溢出),根据主键排列。

2.2.1. 主键顺序插入效果

1. 从磁盘中申请页, 主键顺序插入

2. 第一个页没有满,继续往第一页插入

3. 当第一个也写满之后,再写入第二个页,页与页之间会通过指针连接 

4. 当第二页写满了,再往第三页写入

2.2.2. 主键乱序插入效果 

1. 假如1#,2# 页都已经写满了,存放了如图所示的数据

2. 此时再插入id50的记录,我们来看看会发生什么现象,会再次开启一个页,写入新的页中吗? 

3. 不会。因为,索引结构的叶子节点是有顺序的。按照顺序,应该存储在47之后。 

4. 但是47所在的1#页,已经写满了,存储不了50对应的数据了。 那么此时会开辟一个新的页3# 

5. 但是并不会直接将 50 存入 3# 页,而是会将 1# 页后一半的数据,移动到 3# 页,然后在 3# 页,插入 50

6. 移动数据,并插入id50的数据之后,那么此时,这三个页之间的数据顺序是有问题的。1#的下一个页,应该是3#3#的下一个页是2#。 所以,此时,需要重新设置链表指针。

注意:上述的这种现象,称之为 "页分裂",是比较耗费性能的操作。

2.3. 页合并

目前表中已有数据的索引结构(叶子节点)如下:

1. 当我们对已有数据进行删除时,具体的效果如下:

当删除一行记录时,实际上记录并没有被物理删除,只是记录被标记(flaged)为删除并且它的空间变得允许被其他记录声明使用。

2. 当我们继续删除2#的数据记录

3. 当页中删除的记录达到 MERGE_THRESHOLD(默认为页的50%),InnoDB会开始寻找最靠近的页(前或后)看看是否可以将两个页合并以优化空间使用。

4. 删除数据,并将页合并之后,再次插入新的数据 21 ,则直接插入 3#

MERGE_THRESHOLD:合并页的阈值,可以自己设置,在创建表或者创建索引时指定。
注:这个里面所发生的合并页的这个现象,就称之为 "页合并"。

2.4. 主键设计及数据插入原则

1. 满足业务需求的情况下,尽量降低主键的长度。

2. 插入数据时,尽量选择顺序插入,选择使用AUTO_INCREMENT自增主键。

3. 尽量不要使用UUID做主键或者是其他自然主键,如身份证号。

4. 业务操作时,避免对主键的修改。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值