MySQL中SQL优化

SQL优化涉及到多个方面,我们接下来主要从以下几个方面介绍:

  • 插入数据时的优化。
  • 主键优化。
  • order by 排序的优化。
  • group by 分组的优化。
  • limit 分页的优化。
  • count 统计的优化。
  • update更新数据的优化。
  1.  插入数据的优化

即insert优化,我们可以从批量插入数据、手动事务提交,以及主键顺序插入等实现。

1)批量插入

# 注意此批量插入一次最多不超过1000条数据insert into tb_user values (1"Tom"), (2"Cat"), (3"Jerry"),...;

2)手动事务提交

start transaction;insert into tb_user values (1, "Tom"), (2, "Cat"), (3, "Jerry");insert into tb_user values (4"Tom"), (5"Cat"), (6"Jerry");insert into tb_user values (7"Tom"), (8"Cat"), (9"Jerry");commit;

3)主键顺序插入

# 主键乱序插入8,1,9,10,22,81,2,4,15,89,5,7,3# 主键顺序插入,基于MySQL的组织结构,顺序插入性能更高1,2,3,4,5,7,8,9,10,15,22,81,89

4)大批量插入数据

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

例如,将文件a.text中的数据,通过load转为数据库存储:

# a.text1, sdfgh, qwert, qwert, 2011-01-01, 02, sdfgh, qwert, qwert, 2011-11-01, 03, sdfgh, qwert, qwert, 2011-10-01, 14, sdfgh, qwert, qwert, 2011-01-11, 25, sdfgh, qwert, qwert, 2011-09-01, 06, sdfgh, qwert, qwert, 2011-01-01, 07, sdfgh, qwert, qwert, 2011-11-01, 08, sdfgh, qwert, qwert, 2011-10-01, 19, sdfgh, qwert, qwert, 2011-01-11, 210, sdfgh, qwert, qwert, 2011-09-01, 0
# 数据库存储结构id, name, password, message, date, status

具体实现语法如下:

# 客户端连接服务器时,加上参数 --local-infilemysql --local-infile -u root -p# 创建一个数据库create database ithero;# 查看是否参加成功show databases;# 进入ithero数据库use ithero;# 查看当前数据库名称select database();
# 查看参数 local_infile的值select @@local_infile;# 设置全局参数 local_infile = 1, 开启从本地加载文件导入数据的开关set global local_infile=1;# 创建测试表 # 注意,MySQL中,为了区分MySQL关键字与普通字符,MySQL引入了反引号CREATE TABLE `tb_user` (  `id` INT(11) NOT NULL AUTO_INCREMENT COMMENT "主键",  `username` VARCHAR(50) NOT NULL COMMENT "用户名",  `password` VARCHAR(50) NOT NULL COMMENT "密码",  `name` VARCHAR(20) NOT NULL COMMENT "姓名",  `birthday` DATE DEFAULT NULL COMMENT "生日",  `sex` CHAR(1) DEFAULT NULL COMMENT "性别",  PRIMARY KEY (`id`),  UNIQUE KEY `unique_user_username` (`username`)ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT="测试表";
# 执行load指令将准备好的数据,加载到表结构中load data local infile "/root/sql.log" into table "tb_user" fields terminated by ", " lines terminated by "\n"# 注意,主键顺序插入的性能高于乱序插入

2. 主键的优化

1)数据的组织方式

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

2)页分裂

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

当主键乱序插入时,会出现页分裂的现象。

即当已经存在2页(页a, 页b)数据填充满的情况下,又出现了一个中间主键(key);那么第一页(页a)将从中间断开,后1/2数据与该中间主键(key)组合成第3个页(c),然后指针变向:由a<->b,改成 a <-> c <-> b。

3)页合并

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

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

注意:MERGE_THRESHOLD即合并页的阈值,可以自己设置,在创建表或者创建索引时指定。

4)主键的设计原则

  • 满足业务需求的情况下,尽量降低主键的长度;
  • 插入数据时,尽量选择顺序插入,选择使用 AUTO_INCREMENT 自增主键;
  • 尽量不要使用UUID做主键,或者其他自然主键,如身份证号。(因为其大部分是无序的,且较长);
  • 业务操作时,避免对主键的修改。(修改主键代价大)

3. order by 优化

1)Using filesort: 通过表的索引或全表扫描,读取满足条件的数据行,然后在排序缓冲区sort buffer中完成排序操作;所有不是通过索引直接返回排序结果的排序都叫 Filesort 排序。

2)Using index: 通过有序索引顺序扫描直接返回有序数据,这种情况叫 using index,不需要额外排序,操作效率高。

# 1. 没有创建索引时,根据age,phone进行排序explain select id, age, phone from tb_user order by age, phone;# 此时,由于没有索引,extra内展示的,即为Using filesort
# 2. 创建索引create index idx_user_age_phone on tb_user(age, phone);# 根据age, phone 升序排explain select id, age, phone from tb_user order by age asc, phone asc;# 根据age, phone 将序排explain select id, age, phone from tb_user order by age desc, phone desc;# 上述2种排序,都能使用索引完成,extra内展示的,即为Using index
# 3. 若根据age 升序, phone 将序排explain select id, age, phone from tb_user order by age asc, phone desc;# 此时,extra内展示的,既有Using index,也有Using filesort# 表示即使用了索引,也使用了全表扫描
# 4. 我们创建age 升序 + phone 将序的索引create index idx_user_age_pho_ad on tb_user(age asc, phone desc);# 此时再次根据age 升序, phone 将序排explain select id, age, phone from tb_user order by age asc, phone desc;# 则extra内展示的,只有Using index,表示只使用了索引。

使用order by 优化的原则:

  • 根据排序字段建立合适的索引,多字段排序时,也遵循最左前缀法则;
  • 尽量使用覆盖索引
  • 多字段排序,一个升序、一个降序,此时需要注意联合索引在创建时的规则(ASC/DESC)。
  • 如果不可避免的出现 filesort,大数据量排序时,可以适当增大排序缓冲区大小 sort_buffer_size(默认256k)。
# 查看filesort排序时的,缓冲区大小show variables like "sort_buffer_size";

后续的优化内容,我们在下一篇中继续学习。

原创文章,作者:guozi,如若转载,请注明出处:https://www.sudun.com/ask/90803.html

(0)
guozi's avatarguozi
上一篇 2024年6月7日 上午11:09
下一篇 2024年6月7日 上午11:10

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注