当前位置: 首页 > news >正文

sql查询优化方式常见情况总结

目录

  • 零、前言
  • 一、查询语句优化
    • 1 避免使用【SELECT * 】
    • 2 使用索引
    • 3 避免子查询
    • 4 使用EXISTS代替IN
    • 5 避免使用函数
    • 6 使用LIMIT
    • 7 优化JOIN操作
    • 8 避免使用DISTINCT
    • 9 使用UNION ALL代替UNION
    • 10 分页优化
    • 11 优化Group By语句
    • 12 使用EXPLAIN分析查询
  • 二、索引优化
  • 三、数据库设计优化
  • 四、执行计划分析
  • 五、硬件和配置优化
  • 六、并发和锁优化
  • 七、缓存优化
  • 八、定期维护
  • 九、分库分表
  • 十、使用数据库工具
  • 最后、总结
  • 参考学习


零、前言

不同数据库的性能和使用场景差别还是挺大的,比如说clickhouse数据库,千万级别的数据关联查询,即便不加索引等优化方式,日常查询使用的话,感觉效率也能接受。但对于有的数据库,如果不做优化,可能就执行一条sql语句,坐等半天冷板凳。另外,sql的查询优化,在面试时也常常被问,不懂就记录和总结,实践中遇到问题,那就顺着这总结的操作手册,顺藤摸瓜,来排忧解难!

总体来说,sql查询优化排查三板斧

  • 由内及外先看内部哪个子查询需要优化;
  • 表连接驱动是否小表联大表;
  • sql语句是否索引无效化

具体优化细节总结如下文。

一、查询语句优化

1 避免使用【SELECT * 】

  • 问题:SELECT *会返回表中所有列,即使你只需要其中几列,这会导致不必要的数据传输和处理。
  • 优化:明确指定需要的列,减少数据传输和处理的开销。

2 使用索引

确保查询中的WHERE条件、JOIN条件和ORDER BY子句中的列都有适当的索引。

  • 问题:如果查询中的WHERE、JOIN或ORDER BY子句中的列没有索引,数据库可能需要进行全表扫描。
  • 优化:(1)为查询中的关键列创建索引;(2)对于复合查询,使用复合索引。

3 避免子查询

尽量将子查询转换为JOIN操作,子查询可能会导致全表扫描。

  • 问题:子查询可能会导致全表扫描,尤其是在嵌套查询中。
  • 优化:尽量将子查询转换为JOIN操作。

4 使用EXISTS代替IN

在某些情况下,EXISTS比IN更高效。

  • 问题:IN子句在处理大量数据时性能较差。
  • 优化:使用EXISTS代替IN,尤其是当子查询返回大量数据时。

备注:区分in和exists主要是造成了驱动顺序的改变(这是性能变化的关键),如果是exists,那么以外层表为驱动表,先被访问,如果是IN,那么先执行子查询。所以IN适合于外表大而内表小的情况;EXISTS适合于外表小而内表大的情况。

5 避免使用函数

在WHERE条件中避免对列使用函数,这会导致索引失效。

  • 问题:在WHERE子句中对列使用函数(如DATE()、UPPER()等)会导致索引失效。
  • 优化:尽量在应用层处理数据,或者在查询中避免对列使用函数。

6 使用LIMIT

如果只需要部分结果,使用LIMIT来减少返回的数据量。

  • 问题:查询返回大量数据时,会占用大量内存和网络带宽。
  • 优化:如果只需要部分结果,使用LIMIT来减少返回的数据量。

7 优化JOIN操作

  • 问题:JOIN操作可能会导致大量数据扫描,尤其是在没有索引的情况下。
  • 优化: (1)确保JOIN条件中的列有索引。(2) 尽量减少JOIN的表数量。(3)使用小表驱动大表(小表在前,大表在后)。

8 避免使用DISTINCT

  • 问题:DISTINCT会对结果集进行去重,可能导致额外的排序和扫描操作。
  • 优化:如果可能,通过优化查询逻辑来避免使用DISTINCT

9 使用UNION ALL代替UNION

  • 问题:UNION会对结果集进行去重,导致额外的开销。
  • 优化:如果不需要去重,使用UNION ALL。

10 分页优化

  • 问题:使用LIMIT和OFFSET进行分页时,OFFSET值越大,查询越慢。
  • 优化:使用基于游标的分页(如WHERE id > last_id)来替代OFFSET。

11 优化Group By语句

  • 优化1:如果对group by语句的结果没有排序要求,要在语句后面加 order by null(group 默认会排序);
  • 优化2:尽量让group by过程用上表的索引,确认方法是explain结果里没有Using temporary 和 Using filesort;
  • 优化3:使用where子句替换Having子句:避免使用having子句,having只会在检索出所有记录之后才会对结果集进行过滤,这个处理需要排序分组,如果能通过where子句提前过滤查询的数目,就可以减少这方面的开销。
  • 如果group by需要统计的数据量不大,尽量只使用内存临时表;也可以通过适当调大tmp_table_size参数,来避免用到磁盘临时表;
  • 如果数据量实在太大,使用SQL_BIG_RESULT这个提示,来告诉优化器直接使用排序算法(直接用磁盘临时表)得到group by的结果。

12 使用EXPLAIN分析查询

  • 问题:无法直观了解查询的执行计划。
  • 优化:使用EXPLAIN或EXPLAIN ANALYZE查看查询的执行计划,找出瓶颈。

二、索引优化

  • 创建合适的索引:确保经常查询的列有索引,但不要过度索引,因为索引会增加写操作的开销。
  • 复合索引:对于多列查询,使用复合索引(组合索引)来提高查询效率。
  • 索引选择性:高选择性的列(如唯一值较多的列)更适合建立索引。
  • 删除不必要的索引:未使用或很少使用的索引会增加写操作的开销。

三、数据库设计优化

  • 范式化与反范式化:适当的反范式化可以减少JOIN操作,提高查询性能。
  • 分区表:对于大表,使用分区表可以提高查询效率,减少扫描的数据量。
  • 数据类型优化:使用合适的数据类型,避免使用过大的数据类型。

四、执行计划分析

  • 查看执行计划:使用EXPLAIN或EXPLAIN ANALYZE查看查询的执行计划,找出瓶颈。
  • 优化JOIN顺序:确保JOIN的顺序是最优的,减少中间结果集的大小。
  • 避免全表扫描:尽量通过索引来避免全表扫描。

五、硬件和配置优化

  • 增加内存:增加数据库服务器的内存,特别是缓冲池(Buffer Pool)的大小。
  • 优化磁盘I/O:使用SSD或RAID来提高磁盘I/O性能。
  • 调整数据库参数:根据工作负载调整数据库的配置参数,如innodb_buffer_pool_size、query_cache_size等。

六、并发和锁优化

  • 减少锁竞争:避免长时间的事务和锁,减少锁等待时间。
  • 使用读写分离:对于读多写少的场景,使用主从复制和读写分离来分担负载。

七、缓存优化

  • 使用查询缓存:如果查询结果不经常变化,可以使用查询缓存。
  • 应用层缓存:在应用层使用缓存(如Redis、Memcached)来减少数据库查询。

八、定期维护

  • 优化表和索引:定期使用OPTIMIZE TABLE或ANALYZE TABLE来优化表和索引。
  • 清理无用数据:定期清理无用数据,减少表的大小。

九、分库分表

  • 水平分表:对于非常大的表,考虑将其分成多个小表。
  • 垂直分表:将不常用的列拆分到其他表中,减少单表的大小。

十、使用数据库工具

  • 性能监控工具:使用数据库自带的性能监控工具(如MySQL的Performance Schema)来监控和分析查询性能。
  • 慢查询日志:启用慢查询日志,找出执行时间较长的查询。

最后、总结

SQL查询性能调优需要从多个角度入手,包括查询语句、索引、数据库设计、硬件配置等。通过逐步排查和优化,可以显著提高查询性能。当然,最可控的还是规范化编写sql脚本的形式,了解熟悉常见的sql查询语句编写的优化应对之策。

参考学习

  • 30个业务场景的SQL优化(https://developer.aliyun.com/article/1497219)
  • 老司机总结的12条 SQL 优化方案(https://developer.aliyun.com/article/1008410)
  • 【干货实战】SQL太慢,教你调优三板斧-Select篇

http://www.dtcms.com/a/330147.html

相关文章:

  • TLSv1.2协议与TCP/UDP协议传输数据内容差异
  • 【Redis】Sentinel (哨兵)
  • 深度学习实战114-基于大模型的深度研究(DeepResearch)架构:从自主信息探索到洞察生成的革命
  • games101 第三讲 Transformation(变换)
  • RK3568项目(十五)--linux驱动开发之进阶驱动
  • Linux应用层开发--进程处理
  • 【完整源码+数据集+部署教程】医学报告图像分割系统源码和数据集:改进yolo11-HGNetV2
  • @Linux进程管理工具 - PM2全面指南
  • 理财 - 基金
  • 【React】use-immer vs 原生 Hook:谁更胜一筹?
  • PromptPilot — AI 自动化任务的下一个环节
  • 云蝠智能 Voice Agent 多模型接入技术架构与实践
  • 微信小程序实现导航至目的地
  • 腾讯位置商业授权微信小程序关键词输入提示
  • python自学笔记7 可视化初步
  • 并发编程(八股)
  • epoll模型解析
  • 数据科学与计算:从基础到实践的全面探索
  • 深度学习(6):参数初始化
  • 动画相关 属性动画+animateToImmediately+ImageAnimator帧动画组件+模态转场
  • 【C++】哈希表的实现
  • EUDR的核心内容,EUDR认证的好处,EUDR意义
  • web开发,在线%射击比赛管理%系统开发demo,基于html,css,jquery,python,django,三层mysql数据库
  • lesson37:MySQL核心技术详解:约束、外键、权限管理与三大范式实践指南
  • SpringBoot工程妙用:不启动容器也能享受Fat Jar的便利
  • CAD 的 C# 开发中,对多段线(封闭多边形)内部的点进行 “一笔连线且不交叉、不出界
  • ECC的原理、背景、工作机制和数学基础
  • 升级Gradle版本后,安卓点击事件使用了SwitchCase的情况下,报错无法使用的解决方案
  • Query通过自注意力机制更新(如Transformer解码器的自回归生成)的理解
  • Unity3D 中纯 Shader 的双色纹理的平铺计算与实现