MySQL进阶——DQL语句日常优化建议(详细版!)

本文将深入探讨MySQL数据查询语言DQL的优化,包括从基础查询优化的字段选择与分页技巧,到条件过滤、索引命中、JOIN 查询、聚合分组、子查询、JSON 数据处理等方面的深入剖析。

本文目录

一、基础查询优化

避免使用 SELECT *,会返回表中的所有字段,增加网络传输和内存消耗。建议明确指定需要的字段。

sql 复制代码
SELECT * FROM products WHERE category = 'electronics';

-- 正确
SELECT product_id, name, price FROM products WHERE category = 'electronics';

传统的 LIMIT OFFSET 分页方式在处理大数据量时效率较低,需要扫描偏移量之前的所有行。可以使用基于游标的分页方式来优化。

sql 复制代码
-- 低效分页
SELECT * FROM orders 
ORDER BY order_id 
LIMIT 10 OFFSET 100000;

-- 高效分页
SELECT * FROM orders 
WHERE order_id > 100000 
ORDER BY order_id 
LIMIT 10;

二、条件过滤与索引命中

1. 最左前缀原则

在使用联合索引时,必须遵循最左前缀原则,即查询条件必须从联合索引的最左边的列开始。

sql 复制代码
-- 联合索引 (user_id, status)
-- 有效查询
SELECT * FROM orders 
WHERE user_id = 1001 AND status = 'paid';

-- 无效查询
SELECT * FROM orders WHERE status = 'paid';  -- 全表扫描

2. 避免隐式类型转换

隐式类型转换会导致索引失效,从而影响查询性能。在编写查询语句时,应确保查询条件的数据类型与索引列的数据类型一致。

sql 复制代码
-- 错误
SELECT * FROM products WHERE product_id = '1001';  -- 索引失效

-- 正确
SELECT * FROM products WHERE product_id = 1001;

三、多表关联与性能

在进行多表关联查询时,应确保关联字段上有索引,以提高查询性能。同时,可以限制结果集的大小,减少不必要的数据传输。

sql 复制代码
SELECT o.order_id, u.username, p.name, oi.quantity
FROM orders o
INNER JOIN users u ON o.user_id = u.user_id
INNER JOIN order_items oi ON o.order_id = oi.order_id
INNER JOIN products p ON oi.product_id = p.product_id
WHERE o.user_id = 1001;

在使用 LEFT JOIN 时,需要注意空值的处理。可以使用 COUNT 函数统计关联表中的记录数,以避免空值的影响。

sql 复制代码
-- 统计商品销售情况
SELECT p.product_id, p.name, COUNT(oi.item_id) AS sales
FROM products p
LEFT JOIN order_items oi ON p.product_id = oi.product_id
GROUP BY p.product_id;

四、聚合与分组

1. GROUP BY

在使用 GROUP BY 进行分组统计时,应确保分组字段与索引匹配,以提高查询性能。在处理大数据量时,可以使用 SQL_BIG_RESULT 提示优化器。

sql 复制代码
-- 按商品分类统计销售额
SELECT p.category, SUM(oi.quantity * oi.price) AS total_sales
FROM order_items oi
INNER JOIN products p ON oi.product_id = p.product_id
GROUP BY p.category
ORDER BY total_sales DESC;

2. HAVING 与 WHERE 区别

HAVING 用于在聚合后过滤数据,而 WHERE 用于在聚合前过滤数据。在编写查询语句时,应尽量使用 WHERE 进行过滤,以提高查询性能。

sql 复制代码
SELECT p.category, SUM(oi.quantity * oi.price) AS total_sales
FROM order_items oi
INNER JOIN products p ON oi.product_id = p.product_id
GROUP BY p.category
HAVING total_sales > 10000;  -- 聚合后过滤

-- 先过滤再聚合(效率更高)
SELECT p.category, SUM(oi.quantity * oi.price) AS total_sales
FROM order_items oi
INNER JOIN products p ON oi.product_id = p.product_id
WHERE oi.created_at > '2023-01-01'  -- 先过滤
GROUP BY p.category;

五、子查询与 EXISTS

在处理子查询时,应根据具体情况选择使用 INEXISTS。通常情况下,EXISTS 更高效,只需要检查子查询中是否存在匹配的记录。

sql 复制代码
-- 查询有订单的用户
SELECT * FROM users u
WHERE EXISTS (
  SELECT 1 FROM orders o 
  WHERE o.user_id = u.user_id
);

-- 等效 IN 查询
SELECT * FROM users 
WHERE user_id IN (SELECT user_id FROM orders);

六、JSON 数据处理

MySQL 支持对 JSON 字段进行提取和查询。可以使用 -> 操作符或 JSON_EXTRACT 函数来提取 JSON 字段中的值。

sql 复制代码
SELECT product_id, 
       attributes->'$.color' AS color,
       attributes->'$.size' AS size 
FROM products 
WHERE attributes->'$.color' = '"red"';


SELECT JSON_EXTRACT(attributes, '$.weight') 
FROM products 
WHERE product_id = 1001;

|-----------------------------------------------------------------------------------------------------|--------------------|--------------------------------------------------------------------------------------------------|
| ← 上一篇 Java进阶------常用类及常用方法详解 | 记得点赞、关注、收藏哦! | 下一篇 Java进阶------数组超详细整理 → |

相关推荐
计算机学姐22 分钟前
基于SpringBoot的在线教育管理系统
java·vue.js·spring boot·后端·mysql·spring·mybatis
onkel in blog23 分钟前
【Docker】Docker Compose方式搭建分布式内存数据库(Redis)集群
数据库·redis·分布式·docker
Minyy1135 分钟前
“爱生活”小项目问题总结
java·数据库·spring boot·spring·maven·intellij-idea
大G哥41 分钟前
【SQL 周周练】爬取短视频发现数据缺失,如何用 SQL 填充
数据库·sql
Qdgr_1 小时前
电厂数据库未来趋势:时序数据库 + AI 驱动的自优化系统
数据库·人工智能·时序数据库
搏博1 小时前
软件工程之需求分析涉及的图与工具
数据库·软件工程·软件构建·软件需求
PXM的算法星球2 小时前
数据库分库分表实战指南:从原理到落地
数据库
我科绝伦(Huanhuan Zhou)2 小时前
Redis再次开源!reids8.0.0一键安装脚本分享
数据库·redis·开源
Kookoos3 小时前
基于 PostgreSQL 的 ABP vNext + ShardingCore 分库分表实战
数据库·docker·postgresql·c#·.net
czhc11400756633 小时前
Linux511SSH连接 禁止root登录 服务任务解决方案 scp Vmware三种模式回顾
运维·服务器·数据库