MySQL 性能优化详解

news2025/1/10 20:49:20

MySQL 性能优化详解

  • 硬件升级
  • 系统配置优化
    • 调整buffer_pool
    • 数据预热
    • 降低日志的磁盘落盘
  • 表结构设计优化
  • SQL语句及索引优化
  • SQL优化实战案例

MySQL性能优化我们可以从以下四个维度考虑:硬件升级、系统配置、表结构设计、SQL语句和索引。

从成本上来说:硬件升级>系统配置>表结构设计>SQL语句及索引,然而效果却是由低到高。所以我们在优化的时候还是尽量从SQL语句和索引开始入手。
在这里插入图片描述

硬件升级

硬件升级这里不在过多赘述,升级更好配置的机器、机械硬盘更换为SSD等等。

系统配置优化

调整buffer_pool

通过调整buffer_pool使数据尽量从内存中读取,最大限度的降低磁盘操作,这样可以提升性能。查看buffer_pool数据的方法:

SHOW GLOBAL STATUS LIKE 'innodb_buffer_pool_page_%'

在这里插入图片描述
可以看出总页数8192,空闲页数1024。

//查看buffer_pool大小 
SELECT @@innodb_buffer_pool_size/1024/1024

innodb_buffer_pool_size默认为128M,理论上可以扩大到内存的3/4或4/5。我们修改mysql配置文件my.cnf,增加如下配置:

innodb_buffer_pool_size = 750M

然后重启MySQL。

数据预热

默认情况下,某条数据被读取过一次才会被缓存在innodb_buffer_pool里。所以数据库刚刚启动,可以进行一次数据预热,将磁盘上的数据缓存到内存中去。 预热脚本:

SELECT DISTINCT CONCAT('SELECT ',ndxcollist,' FROM ',db,'.',tb, ' ORDER BY ',ndxcollist,';') SelectQueryToLoadCache FROM ( SELECT engine,table_schema db,table_name tb, index_name,GROUP_CONCAT(column_name ORDER BY seq_in_index) ndxcollist FROM ( SELECT B.engine,A.table_schema,A.table_name, A.index_name,A.column_name,A.seq_in_index FROM information_schema.statistics A INNER JOIN ( SELECT engine,table_schema,table_name FROM information_schema.tables WHERE engine='InnoDB' ) B USING (table_schema,table_name) WHERE B.table_schema NOT IN ('information_schema','mysql') ORDER BY table_schema,table_name,index_name,seq_in_index ) A GROUP BY table_schema,table_name,index_name ) AA ORDER BY db,tb;

将脚本保存为:loadtomem.sql,执行命令:

mysql -uroot -p -AN < /root/loadtomem.sql > /root/loadtomem.sql

在需要进行数据预热时就执行下面的命令:

mysql -uroot < /root/loadtomem.sql > /dev/null 2>&1

降低日志的磁盘落盘

  • 增大redolog,减少落盘次数,innodb_log_file_size设置为0.25 * innodb_buffer_pool_size
  • 通用查询日志、慢查询日志可以不开,bin-log要开,慢日志查询可以遇到性能问题再开
  • 写redolog策略 调整innodb_flush_log_at_trx_commit参数为0或2。当然涉及安全性非常高的系统(金融等)还是保持默认的就行。

在配置文件里加上 innodb_flush_log_at_trx_commit =2 即可。

SHOW VARIABLES LIKE 'innodb_flush_log_at_trx_commit'

表结构设计优化

  • 设计中间表
    • 设计中间表,一般针对于统计分析功能
  • 设计冗余字段
    • 为减少关联查询,创建合理的冗余字段
  • 拆表
    • 对于字段太多的大表,考虑拆表;对于表中经常不被使用的字段或存储数据比较多的字段,考虑拆表
  • 主键优化
    • 主键类型最好是int类型,建议自增主键(分布式系统下用雪花算法)
  • 字段的设计
    • 字段的宽度设得尽可能的小。
    • 尽量把字段设置为NOT NULL
    • 对于某些文本字段,如省份、性别等,我们可以把他们定义为enum类型。在mysql里enum类型被当作数值类型数据来处理,而数值型数据处理起来比文本类型快得多。

SQL语句及索引优化

  1. 学会用explain分析
  2. SQL语句中IN包含的值不应太多
    • MySQL对IN做了一些优化,将IN中的常量去不存在一个数组里,而且会进行排序。如果数值较多,这些步骤消耗也是比较大的。
  3. SELECT 语句务必指明字段名称
    • SELECT * 增加了很多不必要的消耗(CPU、IO、内存、网络带宽)
  4. 当只需要一条数据时,使用limit
  5. 排序字段加索引
  6. 如果查询条件中其他字段没有索引,少用or
    • or两边的字段中,如果有一个不是索引字段,则会造成该查询都不会走索引的情况。
    • select * from tbiguser where nickname='zy1' or loginname='zhaoyun3';
    • 如nickname是索引字段,loginname不是索引字段,则整体不会走索引。可以用union all代替
  7. 尽量用union all代替union
    • union和union all的区别是,union需要将结果集合并再进行唯一性过滤操作,这就会涉及到排序,增加了大量的CPU运算。当然,使用union all的前提条件是两个结果集没有重复数据。
  8. 区分in和exists、not in和not exists
    • exists:以外表为驱动表,先被访问。适合外表小而内表大的情况
    • in:先执行子查询。适合外表大而内表小的情况

关于not in和not exists,推荐使用not exists,不仅仅是效率问题,not in可能存在逻辑问题。如何高效的写出一个替代not exists的SQL语句?

原语句:

select colname … from A表 where a.id not in (select b.id from B表)

优化后的语句:

select colname … from A表 Left join B表 on where a.id = b.id where b.id is null
  1. 不建议使用%前缀模糊查询,不会走索引

  2. 避免在where子句中对字段进行表达式或函数操作

  3. 避免隐式类型转换 如where age=‘18’,如果确定是int类型,应写为where age = 18;

  4. 对于联合索引,要遵守最左前缀法则

    • 举例来说索引含有字段id、name、school,可以直接用id字段,也可以id、name这样的顺序,但是name;school都无法使用这个索引。所以在创建联合索引的时候一定要注意索引字段顺序,常用的查询字段放在最前面。
  5. 必要时可以使用force index来强制查询使用某个索引

  6. 注意范围查询语句 对于联合索引来说,如果存在范围查询,比如between,>,<等条件时,会造成后面的索引字段失效

  7. 使用JOIN优化 LEFT JOIN里左边的表为驱动表,RIGHT JOIN里右边的表为驱动表,而INNER JOIN MySQL会自动找出数据少的表为驱动表

注意:

  • MySQL没有full join,可以用以下方式解决
select * from A left join B on B.name = A.name where B.name is null union all select * from B;
  • 尽量用inner join,避免left join
  • 合理利用索引字段作为on的限制字段
  • 利用小表去驱动大表

下图是join查询的原理图,从图中可以看出如果能够减少驱动表的话,就能减少嵌套循环中的次数,以减少IO总量及CPU运算的次数。
在这里插入图片描述

SQL优化实战案例

介绍:tbiguser表有10000000条记录,表结构如下:

create table tbiguser( id int primary key auto_increment, nickname varchar(255), loginname varchar(255), age int , sex char(1), status int, address varchar(255) );

创建存储过程,并执行,插入一千万条数据

CREATE PROCEDURE test_insert() BEGIN DECLARE i INT DEFAULT 1; WHILE i<=10000000 DO insert into tbiguser VALUES(null,concat('zy',i),concat('zhaoyun',i),23,'1',1,'beijing'); SET i=i+1; END WHILE ; commit; END;
call test_insert

还有tuser1表和tuser2表,两个表结构一致。

create table tuser1( id int primary key auto_increment, name varchar(255), address varchar(255) ); create table tuser2( id int primary key auto_increment, name varchar(255), address varchar(255) );

在这里插入图片描述
需求:tbiguser表按照地区分组统计求和,并且要求是在tuser1表和tuser2表中出现过的地区。
按照需求写出SQL:

SELECT COUNT(*) num,address FROM tbiguser WHERE address IN (SELECT address FROM tuser1) GROUP BY address UNION SELECT COUNT(*) num,address FROM tbiguser WHERE address IN (SELECT address FROM tuser2) GROUP BY address

执行时间:4.65s

第一次优化:
加索引。我们可以给address字段加索引。

ALTER TABLE tuser1 ADD INDEX idx_address(address); ALTER TABLE tuser2 ADD INDEX idx_address(address); ALTER TABLE tbiguser ADD INDEX idx_address(address);

执行时间0.9s
我们用explain分析sql
在这里插入图片描述
发现有两次都扫描了964147行,就是tbiguser这个大表扫描了两次。且有临时表使用。于是我们进行优化

第二次优化

SELECT COUNT(*) num,address FROM tbiguser WHERE address IN (SELECT address FROM tuser1) OR address IN (SELECT address FROM tuser2) GROUP BY address

执行时间0.65s
在这里插入图片描述
没有临时表了,大表也只扫描了一次。另外我尝试这样查询:

SELECT COUNT(*) num,address FROM tbiguser WHERE address IN (SELECT address FROM tuser1 UNION ALL SELECT address FROM tuser2) GROUP BY address

执行时间12s。

SELECT COUNT(x.id),x.address FROM (SELECT DISTINCT b.* FROM tuser1 a,tbiguser b WHERE a.address=b.address UNION ALL SELECT DISTINCT b.* FROM tuser2 a,tbiguser b WHERE a.address=b.address) X GROUP BY x.address;

执行时间5.8s

根据实践发现,sql查询优化没有定式,不同的数据量下相同的sql表现是不一样的,需要灵活运用。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

RK3568平台开发系列讲解(pinctrl 子系统篇)pinctrl_debug

🚀返回专栏总目录 文章目录 1. Overview2. debug信息2.1 pinctrl-devices2.2. pinctrl-handles2.3. pinctrl-handles3. debug信息3.1. 查看(pinctrl_register_pins)注册了哪些pins3.2. 查看pin groups;3.3. 查看每种functions所占用的gpio groups信息:3.4. pinconf沉淀、…

目标跟踪算法:SORT、卡尔曼滤波、匈牙利算法

目录 1 目标检测 2 卡尔曼滤波 3《从放弃到精通&#xff01;卡尔曼滤波从理论到实践》视频简单学习笔记 3.1 入门 3.2 进阶 3.2.1 状态空间表达式 3.2.2 高斯分布 3.3 放弃 3.4 精通 4 匈牙利算法 5 《【运筹学】-指派问题&#xff08;匈牙利算法&#xff09;》视…

5G Multicast/Broadcast Services(MBS) (八) MBS多播DRX

这里简单看下多播DRX的内容。 1 MBS multicast 对于MBS多播,RRC可配置 MAC entity使其具备per G-RNTI 或per G-CS-RNTI DRX 功能,从而控制 UE 对 MAC entity的G-RNTI和G-CS-RNTI 的 PDCCH 监听活动。当处于 RRC_CONNECTED 状态时,如果为 G-RNTI 或 G-CS-RNTI 配置了多播…

【JavaEE】多线程(7)

一、JUC的常见类 JUC→java.util.concurrent&#xff0c;放了和多线程相关的组件 1.1 Callable 接口 看以下从计算从1加到1000的代码&#xff1a; public class Demo {public static int sum;public static void main(String[] args) throws InterruptedException {Thread …

宝塔面板-java项目 spring 无法正常启动 java spring 宝塔 没有显示日志 问题解决方案-spring项目宝塔面板无日志

宝塔面板-java项目 spring 无法正常启动 java spring 宝塔 没有显示日志 -优雅草央千澈问题解决方案-spring项目宝塔面板无日志 问题描述 昨天安排了一个新项目的开发&#xff0c;搭建兄弟搭建完但是通信有问题&#xff0c;spring服务无法正常启动&#xff0c;于是交代后端兄…

关于一些游戏需要转区的方法

当玩非国区游戏时有时会出现乱码导致无法启动&#xff0c;此时多半需要转区来进行解决 1.下载转区软件 【转区工具】Locale Emulator 下载链接&#xff1a;Locale.Emulator.2.5.0.1.zip - 蓝奏云 用此软件可以解决大部分问题。 2.进行系统转区 首先打开控制面板选择时间与…

浅谈网络 | 应用层之云网络隔离GRE/VXLAN

目录 前言GRE 隧道技术VXLANGRE/VXLAN接入云平台 前言 之前提到&#xff0c;为云平台中的租户实现隔离时&#xff0c;常用的策略是基于 VLAN。然而&#xff0c;VLAN 只有 12 位&#xff0c;共支持 4096 个 ID&#xff0c;这在最初设计时看似足够&#xff0c;但随着云计算的快速…

【Python】批量下载抖音视频

1、代码 import os import re from concurrent.futures import ThreadPoolExecutor import requestsdef get_urls(max_cursor):# 请求头 &#xff08;页面获取&#xff09;headers {Cookie: ,Referer: ,User-Agent: }# 请求地址&#xff08;页面获取&#xff09;url # max_c…

刚入行Java,如何深入学习JVM底层原理?

对于JVM&#xff0c;我想大部分小伙伴都是要面试了才会去学&#xff0c;其余时间基本不会去看&#xff08;掐指一算&#xff0c;你们书架上面的深入理解Java虚拟机第三版应该都一层灰了吧【手动狗头】&#xff09;。但值得一说的是&#xff0c;当你工作多年之后&#xff0c;你遇…

【Redis】深入解析Redis缓存机制:全面掌握缓存更新、穿透、雪崩与击穿的终极指南

文章目录 一、Redis缓存机制概述1.1 Redis缓存的基本原理1.2 常见的Redis缓存应用场景 二、缓存更新机制2.1 缓存更新的策略2.2 示例代码&#xff1a;主动更新缓存 三、缓存穿透3.1 缓存穿透的原因3.2 缓解缓存穿透的方法3.3 示例代码&#xff1a;使用布隆过滤器 四、缓存雪崩4…

java中的数组(2)

大家好&#xff0c;我们今天继续来看java中数组这方面的知识点&#xff0c;那么话不多说&#xff0c;我们直接开始。 一.数组的使用 1.数组中元素访问 数组在内存中是一段连续的空间,空间的编号都是从0开始的,依次递增,数组可以通过下标访问其任意位置的元素. 也可以进行修改…

Qt入门7——Qt事件

目录 1. Qt事件介绍&#xff1a; 2. 事件的处理 示例1&#xff1a;鼠标进入(enterEvent)与离开事件(leaveEvent) 示例2&#xff1a;鼠标点击事件(mousePressEvent) 示例3&#xff1a;鼠标移动事件(mouseMoveEvent) 3. 按键事件 4. 定时器 5. 窗口事件 1. Qt事件介绍&a…

PyQt事件机制练习

一、思维导图 二、代码 import sysfrom PyQt6.QtTextToSpeech import QTextToSpeech from PyQt6.QtWidgets import QApplication, QWidget, QLabel, QPushButton, QLineEdit from PyQt6 import uic from PyQt6.QtCore import Qt, QTimerEvent, QTimeclass MyWidget(QWidget):d…

【河南】《关于省级政务信息化建设项目支出预算标准的规定(试行)》(豫财预〔2020〕81号)-省市费用标准解读系列25

《关于省级政务信息化建设项目支出预算标准的规定(试行)》&#xff08;豫财预 〔2020〕81号&#xff09;是河南省财政厅2020年8月27日发布的信息化项目预算标准&#xff08;了解更多可直接关注我们咨询&#xff09;。该标准旨在加强河南省省级部门预算管理&#xff0c;规范省级…

oscp备考,oscp系列——Kioptix Level 3靶场

Kioptix Level 3 oscp备考&#xff0c;oscp系列——Kioptix Level 3靶场 nmap扫描 主机发现 └─# nmap -sn 192.168.80.0/24 Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-12-09 00:33 CST Nmap scan report for 192.168.80.1 Host is up (0.00014s latency). MAC…

活动|华院计算董事长宣晓华应邀出席2024科创大会并作圆桌嘉宾

2024科创大会在上海举行&#xff0c;由中央广播电视总台和上海市人民政府共同主办。本次大会以“创新驱动 新质未来”为主题&#xff0c;来自知名院校、科研机构的专家学者以及科技企业、金融机构的相关负责人共聚一堂&#xff0c;探讨人工智能、生物医药等产业应用前景&#x…

Robust Univariate Mean Estimation算法简介

Robust Univariate Mean Estimation 是一种统计算法&#xff0c;主要用于在单变量场景中估计样本的均值&#xff0c;同时对异常值&#xff08;outliers&#xff09;具有鲁棒性。传统的均值估计使用样本的算术平均值&#xff0c;但它对异常值高度敏感。为了缓解这个问题&#xf…

C/C++流星雨

系列文章 序号直达链接1C/C爱心代码2C/C跳动的爱心3C/C李峋同款跳动的爱心代码4C/C满屏飘字表白代码5C/C大雪纷飞代码6C/C烟花代码7C/C黑客帝国同款字母雨8C/C樱花树代码9C/C奥特曼代码10C/C精美圣诞树11C/C俄罗斯方块12C/C贪吃蛇13C/C孤单又灿烂的神-鬼怪14C/C闪烁的爱心15C/C…

MySQL——buffer poll

为什么要有buffer poll&#xff1f; 如果没有buffer poll&#xff0c;每次读取数据的时候都是从磁盘上读的&#xff0c;这样效率是很差的的。 所以有了提高效率的方式&#xff0c;就加上了一个缓存——buffer poll 所以&#xff0c;当我们读取数据的时候就有以下的方式 当读…

2025年山东省职业院校技能大赛“信息安全管理与评估”(山东省) 任务书

2025年山东省职业院校技能大赛“信息安全管理与评估”(山东省 任务书 模块一网络平台搭建与设备安全防护任务1&#xff1a;网络平台搭建 &#xff08;50分&#xff09;任务2&#xff1a;网络安全设备配置与防护&#xff08;250分&#xff09; 模块二网络安全事件响应、数字取证…