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数,不过没什么变化…...
手游刚开服就被攻击怎么办?如何防御DDoS?
开服初期是手游最脆弱的阶段,极易成为DDoS攻击的目标。一旦遭遇攻击,可能导致服务器瘫痪、玩家流失,甚至造成巨大经济损失。本文为开发者提供一套简洁有效的应急与防御方案,帮助快速应对并构建长期防护体系。 一、遭遇攻击的紧急应…...
【JavaEE】-- HTTP
1. HTTP是什么? HTTP(全称为"超文本传输协议")是一种应用非常广泛的应用层协议,HTTP是基于TCP协议的一种应用层协议。 应用层协议:是计算机网络协议栈中最高层的协议,它定义了运行在不同主机上…...
YSYX学习记录(八)
C语言,练习0: 先创建一个文件夹,我用的是物理机: 安装build-essential 练习1: 我注释掉了 #include <stdio.h> 出现下面错误 在你的文本编辑器中打开ex1文件,随机修改或删除一部分,之后…...
关于iview组件中使用 table , 绑定序号分页后序号从1开始的解决方案
问题描述:iview使用table 中type: "index",分页之后 ,索引还是从1开始,试过绑定后台返回数据的id, 这种方法可行,就是后台返回数据的每个页面id都不完全是按照从1开始的升序,因此百度了下,找到了…...
汽车生产虚拟实训中的技能提升与生产优化
在制造业蓬勃发展的大背景下,虚拟教学实训宛如一颗璀璨的新星,正发挥着不可或缺且日益凸显的关键作用,源源不断地为企业的稳健前行与创新发展注入磅礴强大的动力。就以汽车制造企业这一极具代表性的行业主体为例,汽车生产线上各类…...
最新SpringBoot+SpringCloud+Nacos微服务框架分享
文章目录 前言一、服务规划二、架构核心1.cloud的pom2.gateway的异常handler3.gateway的filter4、admin的pom5、admin的登录核心 三、code-helper分享总结 前言 最近有个活蛮赶的,根据Excel列的需求预估的工时直接打骨折,不要问我为什么,主要…...
Nuxt.js 中的路由配置详解
Nuxt.js 通过其内置的路由系统简化了应用的路由配置,使得开发者可以轻松地管理页面导航和 URL 结构。路由配置主要涉及页面组件的组织、动态路由的设置以及路由元信息的配置。 自动路由生成 Nuxt.js 会根据 pages 目录下的文件结构自动生成路由配置。每个文件都会对…...
【C++从零实现Json-Rpc框架】第六弹 —— 服务端模块划分
一、项目背景回顾 前五弹完成了Json-Rpc协议解析、请求处理、客户端调用等基础模块搭建。 本弹重点聚焦于服务端的模块划分与架构设计,提升代码结构的可维护性与扩展性。 二、服务端模块设计目标 高内聚低耦合:各模块职责清晰,便于独立开发…...
Spring AI与Spring Modulith核心技术解析
Spring AI核心架构解析 Spring AI(https://spring.io/projects/spring-ai)作为Spring生态中的AI集成框架,其核心设计理念是通过模块化架构降低AI应用的开发复杂度。与Python生态中的LangChain/LlamaIndex等工具类似,但特别为多语…...
深度学习习题2
1.如果增加神经网络的宽度,精确度会增加到一个特定阈值后,便开始降低。造成这一现象的可能原因是什么? A、即使增加卷积核的数量,只有少部分的核会被用作预测 B、当卷积核数量增加时,神经网络的预测能力会降低 C、当卷…...
