关于MySQL优化的思考二【性能分析工具、优化原则】

在实际的工作中,我们不免需要对SQL预计进行分析和优化,今天我们就来一起看下相关内容:

  • SQL性能分析

  • SQL优化原则

1 SQL性能分析

对SQL进行性能分析,主要有:

  • 查看慢SQL

  • 通过profile详情查看

  • explain执行计划

1.1 查看慢SQL

SQL执行频率

-- 查看系统的状态,7个_
show global status like 'Com_______';

慢查询日志

慢查询日志记录了所有执行时间超过指定参数(long_query_time,单位:秒,默认是10秒)的所有的SQL语句的日志。MySQL的慢查询日志默认没有开启,需要在配置文件中加入。

-- 查看慢查询日志是否开启
show variables like 'show_query_log';

开启慢查询的配置,在配置文件中增加:

# 开启慢SQL的开关
slow_query_log=1

# 设置慢日志的时间为2秒,SQL语句执行时间超过2秒,就会被记录
long_query_time=2

慢查询日志记录的信息在/var/lib/mysql/localhost-slow.log。我用docker启动的MySQL的地址和上边不一样:

图片

运行SQL,制造慢SQL

select sleep(5);

查看慢SQL的日志:

[root@VM-24-10-centos data]# cat a5cbd50ec8f4-slow.log 
/usr/sbin/mysqld, Version: 8.0.27 (MySQL Community Server - GPL). started with:
Tcp port: 3306  Unix socket: /var/run/mysqld/mysqld.sock
Time                 Id Command    Argument
# Time: 2023-07-27T09:03:10.516956Z
# User@Host: root[root] @  [114.242.22.4]  Id:     9
# Query_time: 5.000289  Lock_time: 0.000000 Rows_sent: 1  Rows_examined: 1
use test;
SET timestamp=1690448585;
/* ApplicationName=DataGrip 2018.1.3 */ select sleep(5);

1.2 通过profile详情查看

通过profile查看最近执行的SQL情况

-- 查看profile是否支持
select @@have_profiling;

-- 查看profile是否开启
select @@profiling;


-- 设置开启
set profiling = 1;

-- 查询
select *
from test.user;

-- 查询
select *
from test.user where name ='张三';

select count(*) from user;

-- profiling_history_size的最大取值范围为[0,100]
set profiling_history_size = 100;

-- 查看当前所有执行的SQL
show profiles;

-- 通过Query_ID查询SQL执行详情
show profile for query 455;

1.3 explain执行计划查看

explain或者desc命令获取MySQL如何执行select语句的信息,包括select语句执行过程中表如何连接和连接的顺序。

explain select * from test.user where name ='张三';

图片

各个字段含义

  • id,查看该查询各个子句的执行顺序

    • select查询的序列号,表示查询中执行select子句或者操作表的顺序(id相同,执行顺序从上到下;id不同,id越大,越先执行)。

  • select_type,查看查询类型,一般不用关注

    • 表示select的类型,simple(简单表,即不使用表连接或者子查询)、primary(主查询,即外层的查询)、union(union中的第二个或者后边的查询语句)、subquery(select/where之后包含了子查询)

  • type,连接类型,需要重点关注

    • 表示连接类型,性能由好到差的连接类型为null、system、const、eq_ref、ref、range、index、all。

  • possible_key

    • 显示可能应用在这张表上的索引,一个或者多个

  • Key,实际用到的索引,需要重点关注

    • 实际使用的所有,如果为null,则没有使用索引

  • key_len,实际使用所有的字节数,需要重点关注

    • 表示索引中使用的字节数,该值为索引字段最大可能的长度,并非实际使用长度,在不损失精确性的前提下,长度越短越好

  • rows

    • MySQL认为必须要执行的查询的行数,在InnoDB中是一个估计值,该值越小越好

  • filtered,需要重点关注

    • 表示返回结果的行数占需读取行数的百分比,该值越大越好

  • Extra,执行计划的额外说明,包含重要信息

id

type value

Meaning

1

const row not found

所要查询的表为空

2

Distinct

mysql正在查询distinct值,因此当它每查到一个distinct值之后就会停止当前组的搜索,去查询下一个值

3

Impossible WHERE

where条件总为false,表里没有满足条件的记录

4

Impossible WHERE noticed after reading const tables

在优化器评估了const表之后,发现where条件均不满足

5

no matching row in const table

当前join的表为const表,不能匹配

6

Not exists

优化器发现内表记录不可能满足where条件

7

Select tables optimized away

在没有group by子句时,对于MyISAM的select count(*)操作,或者当对于min(),max()的操作可以利用索引优化,优化器发现只会返回一行。

8

Using filesort

使用filesort来进行order by操作

9

Using index

覆盖索引

10

Using index for group-by

对于group by列或者distinct列,可以利用索引检索出数据,而不需要去表里查数据、分组、排序、去重等等

11

Using join buffer

之前的表连接在nested loop之后放进join buffer,再来和本表进行join。适用于本表的访问type为range,index或all

12

Using sort_union,using union,using intersect

index_merge的三种情况

13

Using temporary

使用了临时表来存储中间结果集,适用于group by,distinct,或order by列为不同表的列。

14

Using where

在存储引擎层检索出记录后,在server利用where条件进行过滤,并返回给客户端

2 SQL优化原则

2.1 插入数据

2.1.1 insert 优化

  • 批量插入,减少建立连接。不建议批量插入超过1000条

  • 手动提交事务,在执行insert之前,开启事务,insert数据之后,手动commit

  • 主键顺序插入

insert into user values(1,'小米'),(2,'小孩'),(3,'小红');

-- 开启事务
-- 也可以使用begin
start transaction;

-- 插入操作
insert into user values(1,'小米'),(2,'小孩'),(3,'小红');
insert into user values(4,'小米1'),(5,'小孩1'),(6,'小红1');

-- 提交
commit;

2.1.2 大批量插入数据

如果一次性需要插入大批量数据,使用load指令进行插入

图片

新建数据库表,准备给该表出入数据

drop table if exists user;
create table user (
  id   int primary key auto_increment,
  name varchar(20) not null,
  age  int         not null,
  city varchar(20) default null
);

使用Java代码生成需要导入的批量数据文件

package com.wmding;

import java.io.*;
import java.util.ArrayList;
import java.util.Random;

/**
 * @author 明月
 * @version 1.0
 * @date 7/29/23 9:50 AM
 * @description:
 */
public class WriteFile {
    public static void main(String[] args) throws IOException {

        ArrayList cityList = new ArrayList();
        cityList.add("北京");
        cityList.add("上海");
        cityList.add("广州");
        cityList.add("郑州");

        File file = new File("/Users/wmding/WorkSpaces/My/ThreadDemo/src/main/java/com/wmding/data.log");

        if (!file.exists()) {
            file.createNewFile();
        } else {
            file.delete();
            file.createNewFile();
        }

        FileWriter fileWriter = new FileWriter(file);

        int num = 1000000;
//        int num = 10;
        // 1,sexe,10,sexeee
        for (int i = 1; i <= num; i++) {
            StringBuffer sb = new StringBuffer();
            sb.append(i);
            sb.append(',');

            String randomStr1 = createRandomStr1(6);
            sb.append(randomStr1);
            sb.append(',');

            int age = creatRandom();
            sb.append(age);
            sb.append(',');

            int index = i % 2;
            sb.append(cityList.get(index));

            System.out.println(sb.toString());

            fileWriter.write(sb.toString());

            // Add a new line after writing the content
            fileWriter.write("\n");

        }
        fileWriter.close();


    }


    /**
     * 生成的字符串每个位置都有可能是str中的一个字母或数字
     */
    private static String createRandomStr1(int length) {
        String str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
        Random random = new Random();
        StringBuffer stringBuffer = new StringBuffer();
        for (int i = 0; i < length; i++) {
            int number = random.nextInt(62);
            stringBuffer.append(str.charAt(number));
        }
        return stringBuffer.toString();
    }

    private static int creatRandom() {
        Random random = new Random();
        // 生成大于1小于100的随机数
        int randomNumber = random.nextInt(98) + 2;
        return randomNumber;
    }
}

将数据文件上传到服务器

复制数据文件到MySQL容器内部的/test目录下
docker cp data.log a5cbd50ec8f4:/test/data.log

进入MySQL容器内部
docker exec -it 5d5ab079a223 bash

导入数据,导入100万条数据,耗时5.64秒

-- 使用--local-infile模式进入数据库
mysql -uroot -p --local-infile

-- 设置local_infile为1
mysql> set global local_infile = 1;

-- 导入数据
mysql> load data local infile '/test/data.log' into table user fields terminated by ',' lines terminated by '\n';
Query OK, 1000000 rows affected (5.64 sec)
Records: 1000000  Deleted: 0  Skipped: 0  Warnings: 0

2.2 主键优化

2.2.1 数据的组织方式

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

  • 非叶子节点存放的是索引

  • 叶子节点存放的是索引和数据

图片

2.2.2 页分裂

不同的插入方式导致效率不同

  • 主键顺序插入时,主键按照顺序放入页(page)中

  • 主键乱序插入时,由于顺序不确定,所以会使在插入过程中,先找到合适的位置,然后插入。原来插入的数据进行页分裂

2.2.3 页合并

当删除一行数据时,实际上记录并没有被物理删除,只是被标记为删除并且它的空间变成允许被使用。

当页中的删除记录达到merge_threshold(默认为页的50%),InnoDB会进行页合并以优化空间使用。

2.4 主键的设计原则

  • 满足业务需求的情况下,尽量降低主键的长度,减少查询时磁盘IO

  • 插入数据时,尽量选择顺序插入,选择使用 auto_increment自增主键,避免页分裂

  • 尽量不要使用UUID做主键或者使用其他自然主键,如身份号码

  • 业务操作时,避免对主键的修改。修改主键后,索引结构就需要发生改变

2.3 order by优化

2.3.1 排序的方式

order by排序中有2种排序方式:Using index > Using filesort

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

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

#没有创建索引时,根据age,phone进行排序
explain select id,age,phone from tb_user order by age, phone;

#创建索引

create index idx_user_age_phone_aa on tb_user(age, phone);

#创建索引后,根据age,phone进行升序排序
explain select id,age,phone from tb_user order by age, phone;

#创建索引后,根据age,phone进行降序排序
explain select id,age,phone from tb_user order by age desc, phone desc;


-- 一个升序、一个降序时联合索引不起作用
#根据age,phone进行降序一个升序,一个降序
explain select id,age,phone from tb_user order by age asc,phone desc;

-- 解决办法是,重新创建索引,一个升序、一个降序
#创建索引
create index idx_ user_age_phone_ad on tb_user(age asc ,phone desc);

#根据age,phone进行降序一个升序,一个降序
explain select id,age,phone from tb_user order by age asc, phone desc;

3.2 排序优化

  • 根据排序字段建立合适的索引,多字段排序时,也要遵循最左前缀法则

  • 尽量使用覆盖索引

  • 多字段排序,一个升序、一个降序,这时需要注意联合索引在创建的规则(asc\desc)

  • 如果不可避免的出现filesort,大数据量排序时,可以适当增大排序缓冲区,如果超过256K时,可能会涉及磁盘文件

-- 查看排序缓冲取大小,默认为256K
show variablees like 'sort_buffer_size';

2.4 group by优化

create index index_age_city on user(age,city);

-- Extra:Using index
explain select age,count(*) from test.user group by age;

-- Extra:Using index; Using temporary
explain select city,count(*) from test.user group by city;

优化原则:

  • 分组操作时,可以通过索引来提高效率

  • 分组操作时,索引的使用也是满足最左前缀法则的

2.5 limit优化

-- 当user表中数据量较大时。limit从0开始和limit从990900的速度差别很大。
select * from test.user limit 0, 10;

select * from test.user limit 990900, 10;

-- 可使用子查询来进行优化
select s.* from test.user as s, (select id from test.user order by id limit 909000,10) as a  where s.id = a.id;

一般分页查询时,优化思路:

  • 通过创建 覆盖索引 提高执行效率

  • 覆盖索引+子查询的方式进行优化

2.6 count优化

count是一个聚合函数,对于返回的结果集,一行一样的判断是否为null,如果不为null就累计加1,最后返回累计值。

用法有:

  • count(*)

  • count(主键)

  • count(字段)

  • count(1)

图片

使用近似计数:如果你对精确的行数没有严格要求,可以使用近似计数方法。MySQL提供了一个叫做SHOW TABLE STATUS的命令,它可以返回表的元数据信息,包括数据行数的近似值

show table status like 'user';

2.7 update优化

InnoDB使用的是行锁,是针对索引加的锁,该索引不能失效,失效后行锁会升级为表锁。


关注我,我们一起学习。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/140541.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

大语言模型可以学习规则11.13

大型语言模型可以学习规则 摘要1 引言2 准备3 从假设到理论3.1 诱导阶段&#xff1a;规则生成和验证3.2 演绎阶段&#xff1a;使用规则库进行显式推理 4 实验评估实验装置4.2 数字推理 5 相关工作 摘要 当提示一些例子和中间步骤时&#xff0c;大型语言模型&#xff08;LLM&am…

Kotlin之控制语句和表达式

原文链接 Kotlin Controls and Expressions 有结果返回的是表达式&#xff0c;没有返回的称之为语句&#xff0c;语句最大的问题是它没有返回值&#xff0c;那么想要保存结果就必然会产生副作用&#xff0c;比如改变变量。很多时候这是不够方便的&#xff0c;并且在多线程条件…

基于springboot实现社区疫情防控平台管理系统项目【项目源码】

基于springboot实现社区疫情防控平台管理系统演示 SpringBoot框架 SpringBoot是一个全新开源的轻量级框架。基于Spring4.0设计&#xff0c;其不仅继承了Spring框架原来有的优秀特性&#xff0c;而且还通过简化配置文件来进一步简化了Spring应用的整个搭建以及开发过程。另外在…

语言大模型的预训练过程——从无尽数据到海量知识

从目前研究结果看&#xff0c;Transformer是足够强大的特征抽取器&#xff0c;通过预训练过程&#xff0c;Transformer学到了什么&#xff1f;知识是如何存取的&#xff1f;我们又如何修正错误知识&#xff1f;本文讲述这方面的研究进展。 1、求知&#xff1a;LLM学到了什么知…

【代码随想录】算法训练计划20

1、654. 最大二叉树 题目&#xff1a; 给定一个不重复的整数数组 nums 。 最大二叉树 可以用下面的算法从 nums 递归地构建: 创建一个根节点&#xff0c;其值为 nums 中的最大值。 递归地在最大值 左边 的 子数组前缀上 构建左子树。 递归地在最大值 右边 的 子数组后缀上 构建…

YOLO目标检测——番茄数据集下载分享【含对应voc、coco和yolo三种格式标签】

实际项目应用&#xff1a;番茄检测数据集说明&#xff1a;番茄目标检测数据集&#xff0c;真实场景的高质量图片数据&#xff0c;数据场景丰富标签说明&#xff1a;使用lableimg标注软件标注&#xff0c;标注框质量高&#xff0c;含voc(xml)、coco(json)和yolo(txt)三种格式标签…

CMake中的字符串操作

如果使用set进行字符串拼接&#xff0c;对应的命令格式如下&#xff1a; set(变量名1 ${变量名1} ${变量名2} ...) 关于上面的命令其实就是将从第二个参数开始往后所有的字符串进行拼接&#xff0c;最后将结果存储到第一个参数中&#xff0c;如果第一个参数中原来有数据会对原…

机器自主程度越高人机融合可能会越难

智能算法是指利用人工智能技术来处理和解决问题的算法。这些算法通过模仿人类的思维和学习过程&#xff0c;可以自动从数据中提取知识、推断和决策。尽管智能算法的智能程度可能存在不同的层次&#xff0c;但它们都具有一定的智能特征&#xff0c;并能够完成一些复杂的任务。如…

如何应对网站攻击?F5聚焦网站安全防护

有关数据表明&#xff0c;2023以来全球累计超过1400多万个网站遭受了超过10亿次的网络攻击&#xff0c;几乎每个网站都面临风险。无论是电商、论坛还是官方的平台都不可避免遭遇攻击&#xff0c;黑客则利用网络服务的中断期间从事窃取信息等非法活动。在多种攻击手段中&#xf…

计算机基础知识50

数据的增删改查(insert update delete select) # 用户列表的展示&#xff1a; # 把数据表中得用户数据都给查询出来展示在页面上 1. 查询 from app01 import models models.UserInfo.objects.all() # 查询所有的字段信息和数据 resmodels.UserInfo.objects.first() # 查询…

Arcgis打开报错error code=-15

Provide your license server administrator with the following information: Error Code -15 问题描述 原因 长时间闲置后&#xff0c;license server administrator会关闭服务。再次打开之后会出现这个报错 解决方案 重启或者按下述做法&#xff1a; 打开任务管理器&am…

一文2000字从0到1使用压测神器JMeter进行压力测试!

概 述 Apache JMeter 是 Apache组织开发的基于 Java的压力测试工具。用于对软件做压力测试&#xff0c;它最初被设计用于 Web应用测试但后来扩展到其他测试领域。它可以用于测试静态和动态资源例如静态文件、Java 小服务程序、CGI 脚本、Java 对象、数据库&#xff0c; FTP 服…

CC1310F128RSMR Sub-1GHz超低功耗无线微控制器芯片

CC1310F128RSMR QFN-32 Sub-1GHz超低功耗无线微控制器 CC1310F128RSMR是一款低成本、 超低功耗、Sub-1 GHz射频器件&#xff0c;它是Simplel ink微控制器(MCU)平台的一部分。该平台由Wi- Fi组成、蓝牙低功耗&#xff0c;Sub-1 GHz&#xff0c;以太网&#xff0c;Zigbee线程和主…

【诺依管理系统-vue3】组件没有重新请求问题

解决方法&#xff1a;destroy-on-close&#xff0c;如图

消息队列中的事务是什么呢?

消息队列中的事务是什么呢&#xff1f; 说到事务&#xff0c;肯定会优先想到数据库中的事务。在数据库中需要事务&#xff0c;是为了保证数据的一致性、完整性、持久性和隔离性。它可以将数据库中的一组操作合并为一个不可分割的工作单元&#xff0c;要么全部执行成功&#xf…

No191.精选前端面试题,享受每天的挑战和学习

🤍 前端开发工程师(主业)、技术博主(副业)、已过CET6 🍨 阿珊和她的猫_CSDN个人主页 🕠 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 🍚 蓝桥云课签约作者、已在蓝桥云课上架的前后端实战课程《Vue.js 和 Egg.js 开发企业级健康管理项目》、《带你从入…

千年密码新解读,DeepMind 开发 Ithaca 破译希腊铭文

铭文、碑刻是过去文明的思想、文化和语言的体现。金石学家破译千年前的密码&#xff0c;需要完成文本修复、时间归因和地域归因三大任务。 主流的研究方式是「字符串匹配」&#xff0c;即凭借记忆或查询语料库匹配字型相似的铭文&#xff0c;这导致了结果的混淆和误判。 为此…

酷柚易汛ERP - 其他出库单操作指南

1、应用场景 处理其他非销售类型的出库单据&#xff0c;比如内部领用福利、赔偿、借出、领用材料、以货抵债等不参与销售管理的出库类业务。 2、主要操作 2.1 新增其他出库单 打开【仓库】-【其他出库单】&#xff0c;新增单据 出库单位成本及出库成本不能录入&#xff1b;…

msvcr71.dll丢失多种解决方法解析,全方位解读msvcr71.dll文件

在日常使用电脑时&#xff0c;你是否曾遇到过“msvcr71.dll文件丢失”的错误提示&#xff1f;别着急&#xff0c;本文将为你详细介绍msvcr71.dll丢失的解决方法&#xff0c;让你迅速解决这一烦恼。 一.多种msvcr71.dll丢失解决方法 修复方法一:重新安装相应软件 首先&#xf…

推荐一份适合所有人做的副业,尤其是程序员。

我建议每个人都去尝试一下网上接单&#xff0c;这是一个门槛低、类型多样的方式&#xff0c;尤其适合程序员&#xff01; 在接单平台上&#xff0c;你可以看到各种类型的兼职。以freelancer为例&#xff0c;你可以在这里找到技术、设计、写作等类型的兼职&#xff0c;只要发挥…