MYSQL八、MYSQL的SQL优化

一、SQL优化

  • sql优化是指:通过对sql语句和数据库结构的调整,来提高数据库查询、插入、更新和删除等操作的性能和效率。

1、插入数据优化

  1. 要一次性往数据库表中插入多条记录:
sql 复制代码
insert  into  tb_test  values(1,'tom');
insert  into  tb_test  values(2,'cat');
insert  into  tb_test  values(3,'jerry');
 .....

1.1、优化方案一(批量插入数据)

sql 复制代码
 Insert  into  tb_test  values(1,'Tom'),(2,'Cat'),(3,'Jerry');

1.2、优化方案二(手动控制事务)

sql 复制代码
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;

1.3、优化方案三(主键顺序插入)

  1. 主键顺序插入,性能要高于乱序插入。

1.4、大批量插入数据

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

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

sql 复制代码
-- 客户端连接服务端时,加上参数  ---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' ;

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

2、主键优化

2.1、数据的组织方式

  1. 在InnoDB存储引擎中,表数据都是根据主键顺序组织存放的,这种存储方式的表称为索引组织表。
    • 行数据都是存储在聚集索引的叶子节点上的。
  2. 在InnoDB引擎中,数据行是记录在逻辑结构 page 页中的,而每一个页的大小是固定的,默认16K。
    • 那也就意味着一个页中所存储的行也是有限的,如果插入的数据行row在该页存储不小,将会存储到下一个页中,页与页之间会通过指针连接。

2.2、页分裂

  1. 页可以为空,也可以填充一半,也可以填充100%。每个页包含了2-N行数据(如果一行数据过大,会行溢出),根据主键排列。
  2. MySQL中的页分裂是指:当B+tree索引中的一个页已经满了,再插入新的记录时,该页会被分裂成两个页。其中,一些记录会被留在原来的页中,而其余记录则会被移到一个新的页中。
    • 页分裂是为了避免数据过度集中在一个页上而引起的性能问题。通过将记录分散到更多的页中,可以减少索引的深度,从而提高查询效率。
    • 在MySQL中,当一个页满了之后,会触发页分裂。具体来说,MySQL会将该页中的记录按照顺序依次遍历,找到一个位置将其分为两个部分,并将后面的记录移到一个新的页中。同时,为了保证索引有序性,MySQL还会将新页中的第一条记录的键值插入到父节点中,并调整父节点中的指针。如果父节点也满了,则递归进行分裂操作。
  3. 页分裂通常会发生在以下情况:
    • 顺序插入:当数据按索引顺序插入,且最后一页已满,会创建一个新的页并在其上继续插入。
    • 乱序插入:如果数据插入到中间的某个索引位置,导致中间的页溢出,那么会把一部分数据移动到新页中,以便为新数据腾出空间。(可能还需要重新设置链表指针)

2.3、页合并

  1. 当删除一行记录时,实际上记录并没有被物理删除,只是记录被标记(flaged)为删除并且它的空间变得允许被其他记录声明使用。
  2. 当页中删除的记录达到 MERGE_THRESHOLD(默认为页的50%),InnoDB会开始寻找最靠近的页(前或后)看看是否可以将两个页合并以优化空间使用。
  • 参数MERGE_THRESHOLD:是合并页的阈值,可以自己设置,在创建表或者创建索引时指定。

2.4、主键的设计原则

  1. 满足业务需求的情况下,尽量降低主键的长度。
  2. 插入数据时,尽量选择顺序插入,选择使用AUTO_INCREMENT自增主键。
  3. 尽量不要使用UUID做主键或者是其他自然主键,如身份证号。
  4. 业务操作时,避免对主键的修改。

3、order by优化

  1. MySQL的排序,有两种方式:

    • Using filesort : 通过表的索引或全表扫描,读取到满足条件的数据行,然后在排序缓冲区sort
      buffer中完成排序操作,所有不是通过索引直接返回排序结果的排序都叫 FileSort 排序
    • Using index : 通过有序索引顺序扫描直接返回有序数据,这种情况即为 using index,不需要额外排序,操作效率高。
    • Using index的性能,而Using filesort的性能
  2. order by优化原则:

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

4、group by优化

  1. 在分组操作中通过以下两点进行优化,以提升性能:
    • A. 在分组操作时,可以通过索引来提高效率。(没有使用索引进行分组Extra下会出现Using temporate(使用临时表),这个性能很低的)
    • B. 分组操作时,索引的使用也是满足最左前缀法则的

5、limit优化

  1. 在数据量比较大时,如果进行limit分页查询,在查询时越往后的数据,分页查询效率越低。
    • 优化思路: 一般分页查询时,通过创建 覆盖索引 能够比较好地提高性能,可以通过覆盖索引加子查询形式进行优化。

6、count优化

  1. 如果数据量很大,在执行count操作时,是非常耗时的。
    • MyISAM 引擎把一个表的总行数存在了磁盘上,因此执行 count(*) 的时候会直接返回这个数,效率很高; 但是如果是带条件的count,MyISAM也慢。
    • InnoDB 引擎就麻烦了,它执行 count(*) 的时候,需要把数据一行一行地从引擎里面读出来,然后累积计数
      • 要大幅度提升InnoDB表的count效率,主要的优化思路:自己计数(可以借助于redis这样的数据库进行,但是如果是带条件的count又比较麻烦了)

6.1、count函数的用法

  1. count() 是一个聚合函数,对于返回的结果集,一行行地判断,如果 count 函数的参数不是NULL,累计值就加 1,否则不加,最后返回累计值。
    • 用法:count(*)、count(主键)、count(字段)、count(数字)
  • 按照效率排序的话,count(字段) < count(主键 id) < count(1) ≈ count(*),所以尽量使用 count(*)。

7、update优化

  1. 主要需要注意一下update语句执行时的注意事项:
    • 在更新数据时,最好根据索引字段进行更新 (否则会出现行锁升级为表锁的问题,就是锁住整张表,导致并发性能降低)
sql 复制代码
-- id是主键索引
update  course  set  name = 'javaEE'  where  id  =  1 ;

-- 此时执行上面的update语句只会出现行锁
  • InnoDB的行锁是针对索引加的锁,不是针对数据记录加的锁 ,并且该索引不能失效,否则会从行锁升级为表锁 。
相关推荐
计算机毕设源码qq-38365310411 小时前
(附项目源码)Java开发语言,215 springboot 大学生爱心互助代购网站,计算机毕设程序开发+文案(LW+PPT)
java·开发语言·spring boot·mysql·课程设计
袁庭新1 小时前
Cannal实现MySQL主从同步环境搭建
java·数据库·mysql·计算机·java程序员·袁庭新
爱学习的白杨树1 小时前
MySQL中有哪几种锁?
数据库·mysql
王ASC3 小时前
ORA-01461: 仅能绑定要插入 LONG 列的 LONG 值。ojdbc8版本23.2.0.0驱动BUG【已解决】
数据库·sql·oracle
Stara05114 小时前
Git推送+拉去+uwsgi+Nginx服务器部署项目
git·python·mysql·nginx·gitee·github·uwsgi
不爱学习的啊Biao5 小时前
初识mysql数据库
数据库·mysql·oracle
执键行天涯5 小时前
【日常经验】修改大数据量的表字段类型,怎么修改更快
sql
sevevty-seven6 小时前
幻读是什么?用什么隔离级别可以防止幻读
大数据·sql
是桃萌萌鸭~7 小时前
mysqldbcompare 使用及参数详解
数据库·mysql
小草儿7997 小时前
gbase8s之mysql的show命令实现
数据库·mysql