132.【MySQL_进阶】(四)

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 高可用系列,价值2615元额度,1个月
简介: 132.【MySQL_进阶】

(三)、SQL优化

1.SQL优化_插入数据

(1).建议批量插入

相对于单条SQL语句地插入,我们每次添加地时候都需要连接初始化等操作,这些操作也是消耗时间的。所以我们建议使用批量插入的语句可以降低这些消耗,建议批量插入的数据不超过1000条。

(2).建议手动提交事务

因为相对于自动提交事务而言,我们每次编写一个数据库语句都要进行数据的提交,这样来回的事务提交也是消耗时间的,所以我们建议手动提交事务。

start transaction';
insert into tb_user values(1,'Tom');
...
commit;
(3).建议主键顺序插入

相对于主键乱序插入,主键顺序插入我们进行遍历的时候顺序查找效率更高。

(4).大批量插入数据(三部曲)

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

将磁盘文件的信息加载到我们的MySQL中,每个字段用逗号分割且每行的最后一个字段不用加逗号但要换行。

  1. 第一步: 客户端连接服务端时

加上参数: --local-linfile

mysql --local-linfile -u root -p
  1. 第二部:设置全局local_linfile为1

设置全局参数开启从本地加载文件都如数据的开关

set global local_infile=1;
  1. 执行load指令将准备号的数据,加载到表结构中

linux系统下需要使用 '/'。window下需要使用 '//' 指向路径

load data local infile '路径/文件名.log' into table 表名 fields terminated by ';' lines terminated by '\n';
(5).测试大批量插入数据

1.表的框架结构

create table tb_user(
  id int(4) not null auto_increment,
  username varchar(50) not null,
  password varchar(50) not null,
  name varchar(20) not null,
  birthday date default null,
  sex char(1) default null,
  primary key(id),
  unique key `unique_user_username` (username)
);
# 1. 服务端连接
mysql --local-infile -u root -p
# 2. 查看我们是否自动开启
select @@local_infile;
+----------------+
| @@local_infile |
+----------------+
|              1 |
+----------------+
-- 3.加载test_load.sql文件的数据,每个字段,分割,每一条用换行
load data local infile '/home/test_load.sql' into table tb_user fields terminated by ',' lines terminated by '\n';
-- 4.查询是否插入成功 ⭐
select *from tb_user;
+----+-------------+-------------+----------+------------+------+
| id | username    | password    | name     | birthday   | sex  |
+----+-------------+-------------+----------+------------+------+
|  1 | sdsdsdsdsd  | sddsdsdsds  | sdsdsds  | 2001-12-17 |      |
|  2 | sdsdsdsdsd2 | sddsdsdsd2s | sdsdsds2 | 2001-12-17 |      |
+----+-------------+-------------+----------+------------+------+

中文插入不进去:

2.SQL优化_主键优化

(1).数据组织方式

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

(2).页分裂_乱序插入

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

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

(3).叶合并_顺序插入

当删除一行记录时,实际上记录并没有被物理删除,只是记录被标记(flaged)为删除并且它的空间变得允许被其他记录声明使用。(比如说我们常见的主键递增的时候,删除某一行之后,主键不会替换原来的主键值,而是继续累加)。

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

(4).主键设计原则
  1. 满足业务需求的情况下,尽量降低主键的长度。
  2. 插入数据时,尽量选择顺序插入,选择使用Auto_increment自增主键。
  3. 尽量不要使用UUID做主键或者其他自然主键,如身份证号等。

3.SQL优化_order by优化

(1). order by优化
  1. using filesort: 通过表的索引或全表扫描,读取满足条件的数据行,然后再排序缓冲区 sort buffer中完成排序操作,所有不是通过索引直接返回排序结果的排序都叫FileSort排序
  2. using index:通过有序索引顺序扫描直接返回有序数据,这种情况即为 using index,不需要额外排序,操作效率高
create index idx_user_age_phone on tb_user(age,phone);
-- 1.符合最左前缀法则: 两面都升序:Using index  ⭐(除了这个效率高)
explain select id,age,phone from tb_user order by age,phone;
-- 2.符合最左前缀法则: 前面升序,后面降序->Using index; Using filesor
explain select id,age,phone from tb_user order by age ,phone desc;
-- 3.符合最左前缀法则: 前面降序后面升序 ->Using index; Using filesor
explain select id,age,phone from tb_user order by age desc,phone;
-- 4.符合最左前缀法则: 前面和后面都降序->Using index; Using filesor
explain select id,age,phone from tb_user order by age desc,phone desc;
-- 违背最左前缀法则4种情况全是 :Using index; Using file
explain select id,age,phone from tb_user order by phone,age;
-- 再次创建排序索引
create index idx_user_age_phone_ad on tb_user(age asc,phone desc);
-- 假如再次查询,那么发现变成  Using index
explain select id,age,phone from tb_user order by age ,phone desc;

(2).order by 优化总结
  1. 根据排序字段建立合适的索引,多字段排序时,也遵循最左前缀法则。
  2. 尽量使用覆盖索引。
  3. 多字段排序,一个升序一个降序,此时需要注意联合索引再创建时的规则(asc/desc)
  4. 如果不可避免的出现filesort,大数据量排序时,可以适当增大排序缓冲区大小 sort_buffer_size (默认256k)。

4.SQL优化_group by优化

(1).group by介绍
  1. 在分组操作时,可以通过索引来提高效率。
  2. 在分组操作时,索引的使用也是满足最左前缀法则的。
(2).group by示列
-- 1.先把所有的索引全部删除,留一个主键索引
+---------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table   | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+---------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| tb_user |          0 | PRIMARY  |            1 | id          | A         |          24 |     NULL | NULL   |      | BTREE      |         |               |
+---------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
-- 2.查看无索引状态下 执行计划  (效率偏低Using temporary)
explain select profession,count(*) from tb_user group by profession;
+----+-------------+---------+------------+------+---------------+------+---------+------+------+----------+---------------------------------+
| id | select_type | table   | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra                           |
+----+-------------+---------+------------+------+---------------+------+---------+------+------+----------+---------------------------------+
|  1 | SIMPLE      | tb_user | NULL       | ALL  | NULL          | NULL | NULL    | NULL |   24 |   100.00 | Using temporary; Using filesort |
+----+-------------+---------+------------+------+---------------+------+---------+------+------+----------+---------------------------------+
-- 3.创建联合索引 执行计划  (效率偏高⭐)
create index idx_user_pro_age_sta on tb_user(profession,age,status);
explain select profession,count(*) from tb_user group by profession;
+----+-------------+---------+------------+-------+----------------------+----------------------+---------+------+------+----------+-------------+
| id | select_type | table   | partitions | type  | possible_keys        | key                  | key_len | ref  | rows | filtered | Extra       |
+----+-------------+---------+------------+-------+----------------------+----------------------+---------+------+------+----------+-------------+
|  1 | SIMPLE      | tb_user | NULL       | index | idx_user_pro_age_sta | idx_user_pro_age_sta | 54      | NULL |   24 |   100.00 | Using index |
+----+-------------+---------+------------+-------+----------------------+----------------------+---------+------+------+----------+-------------+
-- 4.未使用最左前缀法则(执行计划效率偏低)
explain select age,count(*) from tb_user group by age;
+----+-------------+---------+------------+-------+----------------------+----------------------+---------+------+------+----------+----------------------------------------------+
| id | select_type | table   | partitions | type  | possible_keys        | key                  | key_len | ref  | rows | filtered | Extra                                        |
+----+-------------+---------+------------+-------+----------------------+----------------------+---------+------+------+----------+----------------------------------------------+
|  1 | SIMPLE      | tb_user | NULL       | index | idx_user_pro_age_sta | idx_user_pro_age_sta | 54      | NULL |   24 |   100.00 | Using index; Using temporary; Using filesort |
+----+-------------+---------+------------+-------+----------------------+----------------------+---------+------+------+----------+----------------------------------------------+
-- 5. 使用最左前缀法则 (执行效率偏高⭐)
explain select age,count(*) from tb_user where profession ='软件工程' group by age;
+----+-------------+---------+------------+------+----------------------+----------------------+---------+-------+------+----------+--------------------------+
| id | select_type | table   | partitions | type | possible_keys        | key                  | key_len | ref   | rows | filtered | Extra                    |
+----+-------------+---------+------------+------+----------------------+----------------------+---------+-------+------+----------+--------------------------+
|  1 | SIMPLE      | tb_user | NULL       | ref  | idx_user_pro_age_sta | idx_user_pro_age_sta | 47      | const |    4 |   100.00 | Using where; Using index |
+----+-------------+---------+------------+------+----------------------+----------------------+---------+-------+------+----------+--------------------------+

5.SQL优化_limit 优化

(1).limit介绍

首页=(页码-1)*10。

一个常见又非常头疼的问题就是 limit 200000,10; 此时需要MySQL排序前2000010记录,仅仅返回 2000000-2000010的记录,其他记录丢弃,查询排序的代价非常大。

优化方案: 主键排序索引+子查询

(2).具体优化
--1.当查询大数据的时候,排序会占用很长的时间 耗时: 19.86s
 select *from tb_user limit 100000,10;
优化方案: 子查询+索引
(1)首先查询出id,根据我们的主键索引,
select id from tb_user order by id limit 10000,10;
(2).然后进行子查询的操作
select t_u.* from tb_user t_u,(select id from tb_user order by id limit 10000,10) t2_u2 where t_u.id=t2_u2.id;

6.SQL优化_count 优化

(1).count介绍
  1. MyISAM 引擎把一个表的总行数存在了磁盘上,因此执行count(*)的时候会直接返回这个数,效率很高。
  2. InnoDB 引擎就麻烦了,它执行count(*)的时候,需要把数据一行一行地从引擎里面读出来,然后累计计数。

优化思路: redis计数器。

(2).count地几种用法
  1. count()是一个聚合函数,对于返回地结果集,一行行地判断,如果count函数地参数不是NULL,累计值就加1,否则不加,最后返回累计值。
  2. count(*): innodb引擎并不会把全部字段取出来,而是专门做了优化,不取值,服务层直接按行进行累加
  3. count(主键):innodb引擎会遍历整张表,把每一行的主键id值都取出来,返回给服务层。服务层拿到主键后,直接按行进行累加
  4. count(字段):
  • 没有not null约束:innodb引擎会遍历整张表把每一行字段都取出来,返回给服务层,服务层判断是否为null,不为null,计数累加。
  • 有not null约束:innodb引擎会遍历整张表把每一行的字段都取出来,返回给服务层,直接按行进行累加
  1. count(1): innodb引擎遍历整张表,但不取值。服务层对于返回的每一行,放一个数字“1”进去,直接按行进行累加。

效率排序: count(字段)<count(主键 id)<count(1)≈count(*),所以尽量使用count(*)。

7.SQL优化_update优化

(1).update优化_介绍

当我们更新的时候,where后面的判断条件不是索引字段,那么innodb会转变为表锁。如果判断条件是索引字段那么innodb会转化为行锁

suoy

(2).update优化_示列
  1. innodb支持行锁,所以能够同时对一张表的不同行进行修改。
  2. 假如我们更新的时候的判断条件是非索引字段,那么会变成表锁,锁整张表。只要当这个表锁释放后其他数据才能继续改变。

注意:我们在更新数据的时候,所以条件一定要是索引字段,并且该索引字段不能失效,如果失效行锁就会升级为表锁。


相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
4月前
|
存储 SQL 关系型数据库
MySQL语句详解:从基础到进阶的全面指南
MySQL语句详解:从基础到进阶的全面指南
|
5月前
|
存储 关系型数据库 MySQL
MySQL数据库进阶第三篇(MySQL性能优化)
MySQL数据库进阶第三篇(MySQL性能优化)
|
5月前
|
存储 关系型数据库 MySQL
MySQL数据库进阶第六篇(InnoDB引擎架构,事务原理,MVCC)
MySQL数据库进阶第六篇(InnoDB引擎架构,事务原理,MVCC)
|
5月前
|
SQL 关系型数据库 MySQL
MySQL数据库进阶第五篇(锁)
MySQL数据库进阶第五篇(锁)
|
5月前
|
存储 SQL 关系型数据库
MySQL 进阶使用【函数、索引、视图、存储过程、存储函数、触发器】(2)
MySQL 进阶使用【函数、索引、视图、存储过程、存储函数、触发器】
|
5月前
|
存储 SQL 关系型数据库
MySQL 进阶使用【函数、索引、视图、存储过程、存储函数、触发器】(1)
MySQL 进阶使用【函数、索引、视图、存储过程、存储函数、触发器】
|
4月前
|
存储 关系型数据库 MySQL
MySQL数据库开发进阶:精通数据库表的创建与管理22
【7月更文挑战第22天】数据库的创建与删除,数据表的创建与管理
48 1
|
5月前
|
JSON 关系型数据库 MySQL
MySQL常用函数解读:从基础到进阶的全方位指南
MySQL常用函数解读:从基础到进阶的全方位指南
|
5月前
|
SQL 关系型数据库 MySQL
Python进阶第二篇(Python与MySQL数据库)
Python进阶第二篇(Python与MySQL数据库)
|
5月前
|
存储 SQL 关系型数据库
MySQL数据库进阶第四篇(视图/存储过程/触发器)
MySQL数据库进阶第四篇(视图/存储过程/触发器)