mysql性能优化-SQL 查询优化

news2024/9/22 7:17:44

MySQL 性能优化之 SQL 查询优化

MySQL 是常用的开源关系型数据库管理系统(RDBMS),具有高效、稳定、易用等特点。在大数据量和高并发的场景中,数据库性能的瓶颈往往是 SQL 查询不够高效。因此,SQL 查询优化是 MySQL 性能优化的重要环节之一。


1. SQL 查询优化的必要性

在数据库应用中,SQL 查询的效率直接影响应用程序的性能。随着数据量的增加,查询响应时间也会变得更长。如果没有良好的查询优化策略,复杂查询可能会消耗大量的系统资源,导致数据库性能下降,影响系统的吞吐量和用户体验。

通过优化 SQL 查询,能有效减少查询时间,降低数据库服务器的负载,提高并发处理能力。


2. 索引优化

2.1 索引的作用

索引是优化 SQL 查询最有效的方法之一。它类似于书的目录,帮助数据库快速定位所需数据,减少全表扫描的开销。

2.2 使用合适的索引
  1. 单列索引:为查询条件中的某个列创建索引。例如:

    CREATE INDEX idx_username ON users(username);
    

    当查询涉及 username 字段时,索引将加快查找速度:

    SELECT * FROM users WHERE username = 'john_doe';
    
  2. 复合索引(多列索引):如果查询涉及多个条件,可以创建复合索引。复合索引包含多个字段,MySQL 会按索引字段的顺序匹配。

    CREATE INDEX idx_username_email ON users(username, email);
    

    这条索引在查询时不仅加速了单个字段查询(如 username),也可以加速组合条件查询:

    SELECT * FROM users WHERE username = 'john_doe' AND email = 'john@example.com';
    
2.3 索引的最佳实践
  • 选择性高的字段上创建索引:索引最适合用于选择性较高的字段(唯一值较多的字段),如用户 ID 或邮箱。
  • 避免过多的索引:虽然索引可以加速查询,但创建过多的索引也会增加数据库的写操作成本(如 INSERTUPDATEDELETE),因为每次修改数据都需要更新索引。
  • 复合索引的顺序:在复合索引中,最左边的字段应该是选择性最高的字段,因为 MySQL 在匹配索引时会按照从左到右的顺序进行匹配。
2.4 覆盖索引

覆盖索引是指查询中所需要的字段都可以从索引中获取,而不需要访问实际的表数据。这样可以显著提高查询效率。

SELECT username, email FROM users WHERE username = 'john_doe';

如果 usernameemail 都在索引中,这个查询就可以只从索引中获取数据,而不需要查询实际的数据表,减少 I/O 操作。


3. 查询语句优化

3.1 避免使用 SELECT *

使用 SELECT * 会查询出表中的所有列,但往往并不是所有的列都需要返回。查询不必要的列会增加网络传输和数据库处理的开销。因此,应该明确指定需要的列:

SELECT username, email FROM users WHERE id = 1;
3.2 减少 JOIN 的使用

JOIN 操作会将多个表的数据进行合并,通常会带来较大的性能开销。尤其是在大数据量表上进行多表 JOIN 时,会导致查询速度变慢。因此,尽量避免复杂的 JOIN,并确保连接条件上有适当的索引。

如果确实需要 JOIN 操作,可以考虑拆分查询,分步骤执行,或进行表的反范式化设计(即适当冗余数据)。

3.3 使用合适的 WHERE 条件

优化查询最直接的方法是使用合适的 WHERE 条件,避免全表扫描。WHERE 条件应与索引字段相结合,以加快检索速度。

例如,避免对索引列进行函数或操作:

-- 避免这种写法,因为它会导致索引失效
SELECT * FROM users WHERE YEAR(created_at) = 2023;

-- 推荐的做法是直接使用索引字段的比较
SELECT * FROM users WHERE created_at BETWEEN '2023-01-01' AND '2023-12-31';
3.4 使用 EXPLAIN 分析查询

MySQL 提供了 EXPLAIN 命令来帮助分析 SQL 查询的执行计划。通过 EXPLAIN,可以了解查询是否使用了索引、查询的执行顺序等信息。

EXPLAIN SELECT * FROM users WHERE username = 'john_doe';

EXPLAIN 的输出中,重点关注以下字段:

  • type:表示查询的类型。ALL 表示全表扫描,index 表示使用了索引,refeq_ref 表示有效的索引匹配。
  • key:表示查询使用的索引。
  • rows:表示预计扫描的行数,行数越少越好。

根据 EXPLAIN 结果,可以针对性地优化查询和索引。

3.5 避免 OR 条件中的索引失效

OR 条件中的索引使用需要特别注意,某些情况下可能导致索引失效。

-- 如果 username 和 email 都没有联合索引,查询会导致全表扫描
SELECT * FROM users WHERE username = 'john_doe' OR email = 'john@example.com';

可以改为使用 UNION 将两次查询合并:

SELECT * FROM users WHERE username = 'john_doe'
UNION
SELECT * FROM users WHERE email = 'john@example.com';

这样能更好地利用索引,提高查询性能。


4. 表结构优化

4.1 规范化与反规范化

数据库设计中有两种设计范式:规范化反规范化。规范化通过减少数据冗余来提高数据一致性,而反规范化则通过适度的数据冗余来提高查询性能。在性能要求较高的场景下,可以考虑反规范化,以减少 JOIN 查询。

4.2 合理选择数据类型

为表中的字段选择合适的数据类型可以显著提高查询效率。例如:

  • 使用 INT 类型来存储数值型数据,而不是 VARCHAR
  • 对于定长字符,可以使用 CHAR 而不是 VARCHAR,提高存储和查询效率。
  • 使用 DECIMAL 类型来存储货币等精确数值,而不是 FLOATDOUBLE,以避免精度问题。
4.3 拆分大表

当表的数据量非常大时,可以考虑将表按时间或其他条件进行垂直或水平拆分。水平拆分是将数据按行进行分表,垂直拆分是将表的列进行拆分。

例如,按日期进行分表:

CREATE TABLE users_2023 LIKE users;
INSERT INTO users_2023 SELECT * FROM users WHERE created_at BETWEEN '2023-01-01' AND '2023-12-31';

通过分表,可以减少单个表的数据量,从而提高查询性能。


5. 缓存查询结果

5.1 MySQL 查询缓存

MySQL 提供了查询缓存功能,可以缓存查询结果,减少相同查询的执行次数。不过,MySQL 8.0 版本已经弃用了查询缓存功能,建议使用应用层的缓存系统(如 Redis)来缓存频繁查询的结果。

5.2 使用 Redis 进行缓存

通过将一些热点数据存储在 Redis 中,可以减少对 MySQL 的访问次数,从而显著提高查询性能。

# 使用 Redis 缓存查询结果(示例为 Python)
import redis

r = redis.Redis(host='localhost', port=6379, db=0)

# 首先检查缓存中是否有数据
cached_data = r.get('user_1')
if cached_data:
    # 如果缓存命中,返回缓存中的数据
    return cached_data
else:
    # 如果缓存未命中,查询 MySQL
    data = query_mysql_for_user(1)
    # 将查询结果写入缓存
    r.set('user_1', data)
    return data

通过缓存可以大幅减少对数据库的查询压力,提升应用性能。


6. 总结

MySQL 查询优化是数据库性能优化的重要环节

。通过合理使用索引、优化查询语句和设计表结构,可以显著提高 MySQL 的查询性能。

  • 索引优化:为高频查询字段创建合适的索引,并避免过多的索引。
  • 查询语句优化:避免使用 SELECT *,简化 JOIN 操作,优化 WHERE 条件。
  • 表结构优化:合理规范化与反规范化,选择合适的数据类型,必要时进行表拆分。
  • 缓存优化:使用 Redis 等缓存系统来减轻数据库查询压力。

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

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

相关文章

力扣115-不同的子序列(Java详细题解)

题目链接:不同的子序列 前情提要: 因为本人最近都来刷dp类的题目所以该题就默认用dp方法来做。 dp五部曲。 1.确定dp数组和i下标的含义。 2.确定递推公式。 3.dp初始化。 4.确定dp的遍历顺序。 5.如果没有ac打印dp数组 利于debug。 每一个dp题目…

Spring IDEA 2024 安装Lombok插件

1.简介 Lombook插件的Data标签可以自动生成类的get和set以及toString方法。 2.安装步骤 在idead设置的插件中搜索lombok插件&#xff0c;安装。 在Spring项目的pom.xml中添加依赖项 <dependency><groupId>org.projectlombok</groupId><artifactId…

数据结构与算法——Java实现 7.习题——反转链表

当你穿过了暴风雨&#xff0c;你已不是原来那个人 —— 24.9.21 206. 反转链表 给你单链表的头节点 head &#xff0c;请你反转链表&#xff0c;并返回反转后的链表。 示例 1&#xff1a; 输入&#xff1a;head [1,2,3,4,5] 输出&#xff1a;[5,4,3,2,1]示例 2&#xff1a; 输…

echarts标注legend的配置

代码&#xff1a; legend: [{top: bottom, //上下位置 top center bottom 还可以用百分比50%等orient: horizontal, // 竖立 vertical horizontal 水平的// right: 0, //靠右 还可以用百分比 50%等// left: 0,// 靠左 还可以用百分比 50%等// 左右位置 否则居中itemWidth: …

前端框架Vue、React、Angular、Svelte对比

在对比 React、Vue.js、Angular 和 Svelte 时&#xff0c;除了在高层次的特性上有显著差异&#xff0c;它们在核心设计理念和底层实现机制上也有明显的不同。为了清晰地理解这些框架&#xff0c;我们可以从以下几个方面来分析它们的核心不同点和底层不同点。 1. 框架类型和设计…

ARM 栈和函数调用

阅读本文前&#xff0c;可以先阅读下述文档&#xff0c;对函数栈、栈帧等的概念会有所了解&#xff0c;会对本文章的理解大有益处 X86_64 栈和函数调用 1、调试环境 Ubuntu&#xff1a; liangjieliangjie-virtual-machine:~/Desktop$ cat /proc/version Linux version 6.5.0…

WebRTC编译后替换libwebrtc.aar时提示找不到libjingle_peerconnection_so.so库

Loading native library: jingle_peerconnection_so 问题原因&#xff1a;编译的时候只编译了armeabi-v7a的版本&#xff0c;但是应用程序是arm64-v8a&#xff0c;所以无法运行 解决方法&#xff1a;更新编译脚本&#xff0c;加上arm64-v8a进行编译 ./tools_webrtc/android/bu…

OpenAI GPT o1技术报告阅读(5)-安全性对齐以及思维链等的综合评估与思考

✨继续阅读报告&#xff1a;使用大模型来学习推理(Reason) 原文链接&#xff1a;https://openai.com/index/learning-to-reason-with-llms/ 编码 我们训练了一个模型&#xff0c;在2024年国际信息学奥林匹克竞赛&#xff08;IOI&#xff09;中得分213分&#xff0c;排名在第…

Arthas sysenv(查看JVM的环境变量)

文章目录 二、命令列表2.1 jvm相关命令2.1.5 sysenv&#xff08;查看JVM的环境变量&#xff09;举例1&#xff1a;sysenv 查看所有环境变量举例2&#xff1a;sysenv java.version 查看单个属性&#xff0c;支持通过tab补全 二、命令列表 2.1 jvm相关命令 2.1.5 sysenv&#x…

saas收银系统源码

1. 线下门店多样化收银 ①门店有社区小店、也会有大店&#xff0c;甚至还会有夫妻店&#xff0c;同时还要有Windows版和安卓版&#xff0c;需满足不同门店的收银需求。 ②支持Windows收银、安卓收银、无人自助收银、聚合码收银等&#xff0c;支持ai智能称重、收银称重一体机等…

Unity3D入门(二) :Unity3D实现视角的丝滑过渡切换

1. 前言 上篇文章&#xff0c;我们已经初步了解了Unity3D&#xff0c;并新建并运行起来了一个项目&#xff0c;使相机视角自动围绕着立方体旋转。 这篇文章&#xff0c;我们来讲一下Unity3D怎么过渡地切换视角。 我们继续是我上篇文章中的项目&#xff0c;但是需要向把Camera…

Qt Debugging帮助文档

Qt中给断点添加条件&#xff1a; 示例1&#xff1a; 当i10时&#xff0c;程序中断 但不知道为什么&#xff0c;46行的条件没有生效&#xff0c;47行的条件生效了 给断点添加忽略次数&#xff1a; 在程序停止之前忽略该断点200次。 Breakpoints (Debugging with GDB)

AI 时代的网络危机沟通计划

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

Go-知识recover

Go-知识recover 1. 介绍2. 工作机制2.1 recover 定义2.2 工作流程2.3 总结 3. 原理3.1 recover函数的真正逻辑3.2 恢复逻辑3.3 生效条件 4. 总结4.1 recover的返回值是什么&#xff1f;4.2 执行recover之后程序将从哪里继续运行&#xff1f;4.3 recover为什么一定要在defer中使…

2024年信息学奥赛CSP-J1入门组初赛真题试卷

2024年信息学奥赛CSP-J1入门组初赛真题试卷 题目总数&#xff1a;20 总分数&#xff1a;100 选择题 第 1 题 单选题 32位int类型的存储范围是&#xff08; &#xff09; A. -2147483647 ~ 2147483647 B. -2147483647 ~ 2147483648 C. -2147483648 ~ 2147483647…

如何使用 React、TypeScript、TailwindCSS 和 Vite 创建 Chrome 插件

创建一个 Chrome 插件是一个有趣的项目&#xff0c;特别是当结合使用强大的工具如 React、TypeScript、TailwindCSS 和 Vite 时 在这篇文章中&#xff0c;我们将逐步引导完成整个过程&#xff0c;了解如何在 2024 年构建自己的 Chrome 插件。无论是经验丰富的开发者还是刚刚起…

C++ | Leetcode C++题解之第423题从英文中重建数字

题目&#xff1a; 题解&#xff1a; class Solution { public:string originalDigits(string s) {unordered_map<char, int> c;for (char ch: s) {c[ch];}vector<int> cnt(10);cnt[0] c[z];cnt[2] c[w];cnt[4] c[u];cnt[6] c[x];cnt[8] c[g];cnt[3] c[h] - …

JavaScript使用leaflet库显示信息窗口

前言 我们可千万不能忘记我们之前花的流程图哦&#xff0c;我们所有的计划都按照我们的流程图来去构建&#xff1b; 我们已经完成了&#xff0c;页面的加载&#xff0c;也已经完成获取用户当前的位置坐标&#xff0c;并且我们通过地图的API将当前的位置在地图中渲染出来&…

【每日刷题】Day128

【每日刷题】Day128 &#x1f955;个人主页&#xff1a;开敲&#x1f349; &#x1f525;所属专栏&#xff1a;每日刷题&#x1f34d; &#x1f33c;文章目录&#x1f33c; 1. 606. 根据二叉树创建字符串 - 力扣&#xff08;LeetCode&#xff09; 2. LCR 194. 二叉树的最近公…

TryHackMe 第3天 | Pre Security (中)

该学习路径讲解了网络安全入门的必备技术知识&#xff0c;比如计算机网络、网络协议、Linux命令、Windows设置等内容。上一篇中简短介绍了计算机网络相关的知识&#xff0c;本篇博客将记录 网络协议 部分。 How the web works? DNS in detail DNS (Domain name system&…