MySQL SQL语句性能优化
MySQL SQL语句性能优化指南
- 一、查询设计优化
- 1. 避免 SELECT *
- 2. 使用 WHERE 进行条件过滤
- 3. 避免在索引列上使用函数和表达式
- 4. 使用 LIMIT 限制返回行数
- 5. 避免使用子查询
- 6. 优化 JOIN 操作
- 7. 避免全表扫描
- 二、索引优化
- 1. 使用合适的索引
- 2. 覆盖索引
- 3. 索引选择性
- 4. 多列索引顺序
- 三、表结构优化
- 1. 垂直拆分
- 2. 水平分区
- 3. 使用适当的数据类型
- 四、查询缓存优化
- 1. 查询缓存的工作原理
- 2. 配置查询缓存
- 3. 查询缓存的优缺点
- 4. 查询缓存的最佳实践
- 五、配置优化
- 1. 调整连接池大小
- 2. 使用慢查询日志
- 六、其他优化技巧
- 1. 避免使用临时表
- 2. 使用批量插入
- 3. 定期优化表
- 4. 避免使用锁表
- 七、使用 EXPLAIN 分析查询
- 总结
MySQL作为一款流行的关系型数据库管理系统,广泛应用于各类应用系统中。然而,随着数据量的增加和查询复杂度的提高,SQL查询性能可能会成为系统瓶颈。本文将系统地介绍MySQL SQL语句性能优化的原则和方法,帮助提升数据库的运行效率。
一、查询设计优化
1. 避免 SELECT *
SELECT *
会检索表中的所有列,可能会带来不必要的I/O开销和网络传输。因此,应尽量选择需要的列。
-- 不推荐
SELECT *
FROM users
WHERE id = 1;-- 推荐
SELECT id, username, email
FROM users
WHERE id = 1;
2. 使用 WHERE 进行条件过滤
在查询中尽量使用 WHERE
子句进行条件过滤,减少全表扫描的行数,从而提高查询效率。
-- 不推荐
SELECT *
FROM orders;-- 推荐
SELECT *
FROM orders
WHERE status = 'completed';
3. 避免在索引列上使用函数和表达式
在 WHERE
子句中的索引列上使用函数或表达式会导致无法使用索引,影响查询性能。
-- 不推荐
SELECT *
FROM users
WHERE YEAR(created_at) = 2024;-- 推荐
SELECT *
FROM users
WHERE created_at BETWEEN '2024-12-01' AND '2024-12-10';
4. 使用 LIMIT 限制返回行数
对于需要分页显示的数据,应使用 LIMIT
限制返回的行数,避免一次性读取过多数据。
SELECT *
FROM orders
WHERE status = 'completed'
LIMIT 100;
5. 避免使用子查询
在可能的情况下,尽量避免使用子查询,而是使用连接(JOIN)来优化查询。
-- 不推荐
SELECT *
FROM users
WHERE id IN (SELECT user_id FROM orders WHERE status = 'completed');-- 推荐
SELECT users.*
FROM users
JOIN orders ON users.id = orders.user_id
WHERE orders.status = 'completed';
6. 优化 JOIN 操作
在使用JOIN操作时,确保被连接的列上有索引,并尽量减少JOIN的数量和复杂度。
-- 创建索引
CREATE INDEX idx_orders_user_id ON orders(user_id);-- 使用索引优化JOIN查询
SELECT users.*
FROM users
JOIN orders ON users.id = orders.user_id
WHERE orders.status = 'completed';
7. 避免全表扫描
当表中的数据量非常大时,执行没有过滤条件的查询或者查询条件不适合索引时,数据库可能需要进行全表扫描。
这不仅会增加查询时间,还会加重数据库负担。为了避免全表扫描,应该尽量通过索引列、合理的过滤条件等优化查询,减少扫描的数据量。
-- 不推荐
SELECT * FROM users WHERE name LIKE '%J%';-- 推荐
SELECT * FROM users WHERE user_id = 123 AND name LIKE '%J%';
在上述查询中,name LIKE '%J%'
会导致全表扫描,因为数据库无法利用索引来加速这种模糊匹配操作,特别是当表中的数据量非常大的时候,查询会非常慢。
改进后的查询通过添加具有索引的 user_id
作为条件,能够利用索引优化查询,避免全表扫描。
二、索引优化
1. 使用合适的索引
为常用的查询条件和排序条件添加索引,避免全表扫描。
-- 创建索引
CREATE INDEX idx_users_username ON users(username);-- 使用索引的查询
SELECT *
FROM users
WHERE username = 'john_doe';
2. 覆盖索引
覆盖索引包含查询所需的所有列,可以避免回表查询,进一步提高查询性能。
-- 创建覆盖索引
CREATE INDEX idx_orders_status_created_at ON orders(status, created_at);-- 使用覆盖索引的查询
SELECT status, created_at
FROM orders
WHERE status = 'completed';
3. 索引选择性
索引的选择性(即唯一值的比例)越高,索引的效率越高。对于低选择性的列(如性别),单独建立索引效果不佳,应考虑与其他高选择性列组合建立联合索引。
4. 多列索引顺序
在创建多列索引时,应将选择性高的列放在索引的前面,以提高索引的效率。
-- 选择性高的列在前
CREATE INDEX idx_users_lastname_firstname ON users(lastname, firstname);-- 查询时利用多列索引
SELECT *
FROM users
WHERE lastname = 'Smith' AND firstname = 'John';
三、表结构优化
1. 垂直拆分
将表中使用频率不同的字段拆分到不同的表中,减少查询的复杂度和数据量。
-- 原始表
CREATE TABLE user_details (id INT PRIMARY KEY,username VARCHAR(50),email VARCHAR(100),address TEXT,phone_number VARCHAR(20)
);-- 拆分后的表
CREATE TABLE users (id INT PRIMARY KEY,username VARCHAR(50),email VARCHAR(100)
);CREATE TABLE user_contacts (user_id INT,address TEXT,phone_number VARCHAR(20),FOREIGN KEY (user_id) REFERENCES users(id)
);
2. 水平分区
对于数据量非常大的表,可以使用分区来提高查询性能。
-- 创建分区表
CREATE TABLE orders (id INT,order_date DATE,amount DECIMAL(10, 2)
) PARTITION BY RANGE (YEAR(order_date)) (PARTITION p2020 VALUES LESS THAN (2021),PARTITION p2021 VALUES LESS THAN (2022)
);
3. 使用适当的数据类型
选择适当的数据类型可以减少存储空间和提高查询性能。例如,使用整数类型代替字符串类型作为主键。
-- 使用整数类型作为主键
CREATE TABLE users (id INT PRIMARY KEY,username VARCHAR(50),email VARCHAR(100)
);
四、查询缓存优化
在 MySQL 中,查询缓存是一个用于存储 SELECT
查询结果的机制。通过查询缓存,MySQL 可以避免重复执行相同的查询,直接从缓存中返回结果,从而显著提高查询性能,减少数据库负载。
1. 查询缓存的工作原理
查询缓存将查询的结果存储在内存中,并且是基于查询的文本来缓存的。只要查询的 SQL 语句完全相同,MySQL 会直接从缓存中获取结果,而不是重新执行查询。
工作流程:
- 用户提交查询时,MySQL 会首先检查查询缓存中是否存在相同的查询结果。
- 如果缓存中存在查询结果,MySQL 会直接返回缓存中的结果。
- 如果缓存中不存在结果,MySQL 会执行查询,将结果存入缓存,并返回给用户。
注意:查询缓存只会缓存 SELECT
查询的结果,不会缓存 INSERT、UPDATE、DELETE 等修改数据的操作。
2. 配置查询缓存
启用查询缓存
在 MySQL 配置文件 my.cnf 中,可以通过设置以下选项来启用查询缓存:
适当调整MySQL的缓存参数,如 query_cache_size
、innodb_buffer_pool_size
等,可以提高查询性能。
[mysqld]
query_cache_type = 1 # 启用查询缓存
query_cache_size = 256M # 设置查询缓存大小
query_cache_limit = 1M # 设置缓存的查询大小限制,超过此大小的查询将不缓存
query_cache_type
:指定查询缓存的启用方式。1
表示启用查询缓存,0
表示禁用查询缓存,2 表示只有 SQL_NO_CACHE(禁用缓存)标记的查询才不缓存。query_cache_size
:设置查询缓存的大小,单位为字节。合理设置缓存大小可以避免过多的内存消耗。query_cache_limit
:设置缓存的查询结果大小限制。如果查询的结果超过该大小,则不缓存。
动态调整查询缓存(运行时)
除了在配置文件中设置外,也可以通过 SQL 命令在运行时动态调整查询缓存的大小和启用状态:
-- 启用查询缓存
SET global query_cache_size = 1000000; # 设置查询缓存大小为 1MB
SET global query_cache_type = 1; # 启用查询缓存-- 执行查询
SELECT * FROM users WHERE username = 'John';
SET global query_cache_size
:此命令设置查询缓存的大小。在此示例中,将缓存大小设置为 1MB。
SET global query_cache_type
:设置查询缓存的启用类型。1 表示启用查询缓存。
查看查询缓存的状态
你可以通过以下 SQL 命令查看查询缓存的状态:
SHOW VARIABLES LIKE 'query_cache%';
SHOW STATUS LIKE 'Qcache%';
这些命令会显示与查询缓存相关的配置信息和当前状态:
Qcache_free_blocks
:查询缓存中空闲的块数。Qcache_hits
:查询缓存命中次数。Qcache_inserts
:查询缓存插入次数。Qcache_lowmem_prunes
:查询缓存由于内存不足而被清理的次数。Qcache_not_cached
:未缓存的查询次数。
3. 查询缓存的优缺点
优势
-
减少数据库负载:查询缓存通过缓存 SELECT 查询的结果,避免了对数据库的重复访问,尤其是在读取密集型应用中。
-
提高响应速度:查询缓存使得相同查询不再执行,而是直接返回缓存结果,减少查询时间,提升应用性能。
劣势
-
缓存失效:当表中的数据发生变化(如 INSERT、UPDATE、DELETE 操作)时,查询缓存会失效。这意味着缓存可能会在某些操作后被清空或无效,导致重新计算查询结果。
-
占用内存:查询缓存会占用一定的内存空间,特别是在缓存较大的查询结果时。如果配置不当,可能会导致内存压力过大。
-
适用场景限制:查询缓存对于频繁变更的数据表效果较差,因为每次数据更新都会导致缓存失效。在高并发的环境中,查询缓存可能会造成性能瓶颈。
-
全表扫描问题:对于需要扫描大量数据的查询,查询缓存并不能显著提高性能。
4. 查询缓存的最佳实践
适用于读取密集型的应用
查询缓存对于那些以读取操作为主且数据变化不频繁的应用非常有效。在这种场景下,缓存的查询结果可以显著提高应用性能,减少对数据库的请求。
-
数据分析报表:如果一个报表的查询结果不经常改变,查询缓存可以有效提高查询速度。
-
商品信息查询:电商网站中,商品信息的变化不频繁,查询缓存可以用来缓存商品查询结果,提升响应速度。
不适用于频繁更新的数据表
查询缓存不适用于频繁更新的表,特别是数据表中频繁的 INSERT、UPDATE 或 DELETE 操作会导致查询缓存的频繁失效,降低性能。
-
电商订单表:订单数据频繁变化,查询缓存的使用可能会导致性能瓶颈,因为每次更新都会清除缓存。
-
社交平台的用户动态:频繁的动态数据更新使得查询缓存无法有效提升性能,甚至可能会造成缓存失效和资源浪费。
五、配置优化
1. 调整连接池大小
根据应用的并发需求调整数据库连接池的大小,避免连接不足或过多。
-- 连接池配置示例(在 my.cnf 文件中)
[mysqld]
max_connections = 5000
2. 使用慢查询日志
启用慢查询日志,找出执行时间长的查询,进行针对性优化。
-- 启用慢查询日志(在 my.cnf 文件中)
[mysqld]
slow_query_log = 1
slow_query_log_file = /var/log/mysql/slow.log
long_query_time = 2
六、其他优化技巧
1. 避免使用临时表
临时表会增加I/O操作,应尽量避免使用。如果必须使用,确保临时表有适当的索引。
2. 使用批量插入
对于大量数据插入操作,使用批量插入可以显著提高效率,减少数据库连接次数和事务开销。
-- 批量插入示例
INSERT INTO users (username, email)
VALUES ('user1', 'user1@example.com'), ('user2', 'user2@example.com');
3. 定期优化表
定期使用 OPTIMIZE TABLE
命令优化表结构,减少碎片,提高查询性能。
-- 优化表
OPTIMIZE TABLE users;
4. 避免使用锁表
尽量避免使用 LOCK TABLES
,以减少锁争用,提升并发性能。
七、使用 EXPLAIN 分析查询
使用 EXPLAIN
语句分析查询执行计划,找出查询中的瓶颈和潜在的优化点。
EXPLAIN
SELECT *
FROM orders
WHERE status = 'completed' AND order_date BETWEEN '2020-01-01' AND '2020-12-31';
通过 EXPLAIN
的输出,可以了解查询是如何执行的,包括使用了哪些索引,扫描了多少行等。根据这些信息,可以进一步优化查询。
总结
- 查询设计:减少数据量,避免复杂计算和函数操作。
- 索引使用:合理创建索引,利用覆盖索引。
- 表结构:垂直拆分和水平分区,选择合适的数据类型。
- 配置优化:调整缓存和连接池,启用慢查询日志。
- 其他技巧:避免临时表和锁表,使用批量插入和定期优化表。
- 分析工具:使用 EXPLAIN 分析查询执行计划。
相关文章:

MySQL SQL语句性能优化
MySQL SQL语句性能优化指南 一、查询设计优化1. 避免 SELECT *2. 使用 WHERE 进行条件过滤3. 避免在索引列上使用函数和表达式4. 使用 LIMIT 限制返回行数5. 避免使用子查询6. 优化 JOIN 操作7. 避免全表扫描 二、索引优化1. 使用合适的索引2. 覆盖索引3. 索引选择性4. 多列索引…...

【蓝桥杯每日一题】技能升级
技能升级 2024-12-10 蓝桥杯每日一题 技能升级 二分 题目大意 一个角色有 N 种可以增加攻击力的技能,对于第 i 个技能首次升级可以提升 A i A_i Ai 点攻击力,随后的每次升级增加的攻击力都会减少 B i B_i Bi 。升级 ⌈ A i B i ⌉ \lceil \frac{A…...

css 实现在一条线上流动小物体(offset-path)
直接贴代码,留几个参考网址给大家 【SVG】路径<Path>标签详解,一次搞懂所有命令参数 探秘神奇的运动路径动画 Motion Path <!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><meta name="viewport&quo…...

探索 Robyn 框架 —— 下一代高性能 Web 框架
技术博客:探索 Robyn 框架 —— 下一代高性能 Web 框架 什么是 Robyn? Robyn 是一个用 Rust 编写的高性能 Web 框架,旨在通过极简设计和高效并发处理,帮助开发者快速构建可扩展的现代 Web 应用。得益于 Rust 的内存安全性和性能…...

STL容器-map P3613【深基15.例2】寄包柜 普及-
题目来源:洛谷题库 文章目录 map例题map知识点map使用注意:map的常用用法 map例题 P3613【深基15.例2】寄包柜 普及- 题意 根据数据插入/查询 思路 map键值对可以根据柜子编号查找物品,但是柜子又有很多个,考虑数组或者map数组…...

【MySQL 进阶之路】了解 性能优化 与 设计原则
1.B树的优势 “矮胖”结构: 矮:B树的每个节点存储更多的关键字,从而减少了树的层级(最多三层),减少了磁盘I/O操作,提高了查询效率。胖:叶子节点存储实际的数据,并使用双…...

MySQL之数据库三大范式
一、什么是范式? 范式是数据库遵循设计时遵循的一种规范,不同的规范要求遵循不同的范式。 (范式是具有最小冗余的表结构) 范式可以 提高数据的一致性和 减少数据冗余和 更新异常的问题 数据库有六种范式(1NF/2NF/3NF…...

[大数据]Hudi
G:\Bigdata\17.hudi\大数据技术之数据湖Hudi 第1章 Hudi概述 1.1 Hudi简介 Apache Hudi(Hadoop Upserts Delete and Incremental)是下一代流数据湖平台。Apache Hudi将核心仓库和数据库功能直接引入数据湖。Hudi提供了表、事务、高效的upserts/delete、高级索引、流摄取服…...

jenkins harbor安装
Harbor是一个企业级Docker镜像仓库。 文章目录 1. 什么是Docker私有仓库2. Docker有哪些私有仓库3. Harbor简介4. Harbor安装 1. 什么是Docker私有仓库 Docker私有仓库是用于存储和管理Docker镜像的私有存储库。Docker默认会有一个公共的仓库Docker Hub,而与Dock…...

JavaScript 高级特性与 ES6 新特性:正则表达式的深度探索
在现代 JavaScript 开发中,正则表达式(Regular Expressions)和高级特性、ES6 新特性的结合使用,能够极大地提升代码的简洁性、可读性和功能性。本文将深入探讨 JavaScript 中的正则表达式及其在高级特性和 ES6 新特性中的应用&…...

正则表达式——参考视频B站《奇乐编程学院》
智能指针 一、背景🎈1.1. 模式匹配🎈1.2. 文本替换🎈1.3. 数据验证🎈1.4. 信息提取🎈1.5. 拆分字符串🎈1.6. 高级搜索功能 二、原料2.1 参考视频2.2 验证网址 三、用法3.1 限定符3.1.1 ?3.1.2 *3.1.3 3.1.…...

【FFmpeg】FFmpeg 内存结构 ⑥ ( 搭建开发环境 | AVPacket 创建与释放代码分析 | AVPacket 内存使用注意事项 )
文章目录 一、搭建开发环境1、开发环境搭建参考2、项目搭建 二、AVPacket 创建与释放代码分析1、AVPacket 创建与释放代码2、Qt 单步调试方法3、单步调试 - 分析 AVPacket 创建与销毁代码 三、AVPacket 内存使用注意事项1、谨慎使用 av_init_packet 函数2、av_init_packet 函数…...

【多模态文档智能】OCR-free感知多模态大模型技术链路及训练数据细节
目前的一些多模态大模型的工作倾向于使用MLLM进行推理任务,然而,纯OCR任务偏向于模型的感知能力,对于文档场景,由于文字密度较高,现有方法往往通过增加图像token的数量来提升性能。这种策略在增加新的语言时࿰…...

Mybatis动态sql执行过程
动态SQL的执行原理主要涉及到在运行时根据条件动态地生成SQL语句,然后将其发送给数据库执行。以下是动态SQL执行原理的详细解释: 一、接收参数 动态SQL首先会根据用户的输入或系统的条件接收参数。这些参数可以是查询条件、更新数据等,它们…...

leetcode 31 Next Permutation
题意 找到下一个permutation是什么,对于一个数组[1,2,3],下一个排列就是[1, 3, 2] 链接 https://leetcode.com/problems/next-permutation/ 思考 首先任何一个permutation满足一个性质,从某个位置往后一定是降序。…...

每日一练 | 华为 eSight 创建的缺省角色
01 真题题目 下列选项中,不属于华为 eSight 创建的缺省角色的是: A. Administrator B. Monitor C. Operator D. End-User 02 真题答案 D 03 答案解析 华为 eSight 是一款综合性的网络管理平台,提供了多种管理和监控功能。 为了确保不同用…...

PyTorch基本使用-自动微分模块
学习目的:掌握自动微分模块的使用 训练神经网络时,最常用的算法就是反向传播。在该算法中,参数(模型权重)会根据损失函数关于对应参数的梯度进行调整。为了计算这些梯度,PyTorch 内置了名为 torch.autogra…...

libevent-Reactor设计模式【1】
一、Libevent概述 1、简介 Libevent 是一个用C语言编写的、轻量级的开源高性能事件通知库,主要有以下几个亮点:事件驱动( event-driven),高性能;轻量级,专注于网络,不如 ACE 那么臃肿庞大&#…...

奇奇怪怪的错误-Tag和space不兼容
报错信息如下: TabError: inconsistent use of tabs and spaces in indentation make: *** [Makefile:24: train] Error 1不能按Tab,要老老实实按space 不过可以在编辑器里面改,把它们调整成一致的;...

29.攻防世界ics-06
ics-06 难度:1 方向:Web 题目描述: 云平台报表中心收集了设备管理基础服务的数据,但是数据被删除了,只有一处留下了入侵者的痕迹。 进入靶场 发现有一处能点动 多了个id1 我其实尝试改过id数,不过没什么变化…...

强化学习路径规划:基于SARSA算法的移动机器人路径规划,可以更改地图大小及起始点,可以自定义障碍物,MATLAB代码
一、SARSA算法概述 SARSA(State-Action-Reward-State-Action)是一种在线强化学习算法,用于解决决策问题,特别是在部分可观测的马尔可夫决策过程(POMDPs)中。SARSA算法的核心思想是通过与环境的交互来学习一…...

【MFC】如何读取rtf文件并进行展示
tf是微软的一个带格式的文件,比word简单,我们可以用写字板等程序打开编辑。下面以具体实例讲解如何在自己程序中展示rtf文件。 首先使用VS2022创建一个MFC的工程。 VIEW类需要选择richview类,用于展示,如下图: 运行效…...

Vulhub:Log4j[漏洞复现]
CVE-2017-5645(Log4j反序列化) 启动靶场环境 docker-compose up -d 靶机IPV4地址 ifconfig | grep eth0 -A 5 ┌──(root㉿kali)-[/home/kali/Desktop/temp] └─# ifconfig | grep eth0 -A 5 eth0: flags4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500 in…...

面向预测性维护的TinyML技术栈全面综述
论文标题:A Holistic Review of the TinyML Stack for Predictive Maintenance(面向预测性维护的TinyML技术栈全面综述) 作者信息:Emil Njor, Mohammad Amin Hasanpour, Jan Madsen, Xenofon Fafoutis,均来自丹麦技术…...

沈阳理工大学《2024年811自动控制原理真题》 (完整版)
本文内容,全部选自自动化考研联盟的:《沈阳理工大学811自控考研资料》的真题篇。后续会持续更新更多学校,更多年份的真题,记得关注哦~ 目录 2024年真题 Part1:2024年完整版真题 2024年真题...

用前端html如何实现2024烟花效果
用HTML、CSS和JavaScript编写的网页,主要用于展示“2024新年快乐!”的文字形式烟花效果。下面是对代码主要部分的分析: HTML结构 包含三个<canvas>元素,用于绘制动画。引入百度统计的脚本。 CSS样式 设置body的背景为黑…...

Redis应用-在用户数据里的应用
1.社区电商的业务闭环 接下来介绍的社区电商是以Redis作为主体技术、以MySQL和RocketMQ作为辅助技术实现的。 (1)社区电商运作模式 社区电商的关键点在于社区,而电商则是辅助性质(次要地位,流量变现)。社区可以分成很多种社区,比如美食社区、美妆社区、影评社区、妈妈社区…...

C++ 中面向对象编程如实现数据隐藏
在C中,面向对象编程(OOP)通过封装(Encapsulation)来实现数据隐藏。封装是OOP的一个核心概念,它允许将对象的属性和行为(即数据和方法)组合在一起,并对外隐藏对象的内部实…...

JavaEE 【知识改变命运】04 多线程(3)
文章目录 多线程带来的风险-线程安全线程不安全的举例分析产出线程安全的原因:1.线程是抢占式的2. 多线程修改同一个变量(程序的要求)3. 原子性4. 内存可见性5. 指令重排序 总结线程安全问题产生的原因解决线程安全问题1. synchronized关键字…...

gz中生成模型
生成模型 通过服务调用生成 还记得parameter_bridge 吗? 我们在生成桥接的时候调用了这个cpp文件。 一个 parameter_bridge 实例用于消息传递(传感器数据)。之前的例子 另一个 parameter_bridge 实例用于服务桥接(动态生成模型…...