SQL 的性能优化是数据库工程师在实际工作中必须面对的课题之一。对于某些数据库工程师来说,它几乎是唯一的课题。实际上,在像 Web 服务这样需要快速响应的应用场景中,SQL 的性能直接决定了系统是否可以使用。在 SQL 中,很多时候不同代码能够得出相同结果。从理论上来说,得到相同结果的不同代码应该有相同的性能,但遗憾的是,查询优化器生成的执行计划很大程度上要受到代码外部结构的影响。因此如果想优化查询性能,必须知道如何写代码才能使优化器的执行效率更高。

一、使用高效查询

1.1 参数是子查询时,使用 EXISTS 代替 IN

在大多时候,[NOT] IN 和 [NOT] EXISTS 返回的结果是相同的。但是两者用于子查询时,EXISTS 的速度会更快一些。

如下两张表中包含了选课程 A 和课程 B 的学生。

Table: class_A
Table: class_B

从 class_A 表中找出同时选了课程 B 的学生。

-- slow

使用 EXISTS 时更快的原因有以下两个。

  • 如果连接列 (id) 上建立了索引,那么查询 class_B 时不用查实际的表,只需查索引就可以了。
  • 如果使用EXISTS,那么只要查到一行数据满足条件就会终止查询,不用像使用 IN 时一样扫描全表。在这一点上 NOT EXISTS 也一样。

当 IN 的参数是子查询时,数据库首先会执行子查询,然后将结果存储在一张临时的工作表里(内联视图),然后扫描整个视图。很多情况下这种做法都非常耗费资源。使用 EXISTS 的话,数据库不会生成临时的工作表。 但是从代码的可读性上来看,IN 比 EXISTS 好。使用 IN 时的代码看起来更加一目了然,易于理解。因此,如果确信使用 IN 也能快速获取结果,就没有必要非得改成 EXISTS 了。

1.2 参数是子查询时,使用联结代替 IN

针对上述的问题,也可以改用联结:

SELECT 

这种写法至少能用到一张表的 "id" 列上的索引。而且,因为没有子查询,所以数据库也不会生成中间表。

二、避免排序

在 SQL 中会进行排序的代表型运算有:

  • GROUP BY 子句
  • ORDER BY 子句
  • DISTINCT
  • 聚合函数 (SUM, COUNT, AVG, MAX, MIN)
  • 集合运算符 (UNION, INTERSECT, EXCEPT)
  • 窗口函数 (RANK, DENSE_RANK ROW_NUMBER)

2.1 灵活使用集合运算符的 ALL 可选项

SQL 中有 UNION, INTERSECT 和 EXCEPT 三个集合运算符。在默认的使用方式下,这些运算符会为了排除掉重复数据而进行排序。

SELECT 

UNION 查询结果 -- 无重复项

如果不在乎结果中是否有重复数据,或者事先知道不会有重复数据,尽量使用 UNION ALL 代替 UNION。这样就不会进行排序了。

SELECT 

UNION ALL 查询结果 -- 有重复项

对于 INTERSECT 和 EXCEPT 也是一样的,加上 ALL 可选项后就不会进行排序了。加上 ALL 可选项是优化性能的一个非常有效的手段,但在 MySQL 中 不支持 INTERCEPT ALL 和 EXCEPT ALL。

2.2 使用 EXISTS 代替 DISTINCT

为了排除重复数据,DISTINCT 也会进行排序。如果需要对两张表的联结结果进行去重,可以考虑使用 EXISTS 代替 DISTINCT,以避免排序。

如下 Items 表中包含某公司的各商品编号及名称;SalesHistory 表中包含各商品的销售情况。

Table: Item
Table: SalesHistory

从上面的商品表 Items 中找出同时存在于销售记录 表 SalesHistory 中的商品

-- slow

2.3 在极值函数中使用索引

SQL 语言里有 MAX 和 MIN 两个极值函数。使用这两个函数时都会进行排序。但是如果参数字段上建有索引,则 只需要扫描索引,不需要扫描整张表。以刚才的表 Items 为例来说,SQL 语句可以像下面这样写:

-- slow

因为 item_no 是表 Items 的唯一索引,所以效果更好。对于联合索引,只要查询条件是联合索引的第一个字段,索引就是有效的,所以也可以对表 SalesHistory 的 sale_date 字段使用极值函数。这种方法并不是去掉了排序这一过程,而是优化了排序前的查找速度,从而减弱排序对整体性能的影响。

2.4 能写在 WHERE 子句里的条件不要写在 HAVING 子句里

例如,下面两条 SQL 语句返回的结果是一样的。

-- slow

但是从性能上来看,第二条语句写法效率更高。原因通常有两个。

  • 在使用 GROUP BY子句聚合时会进行排序,如果事先通过 WHERE 子句筛选出一部分行,就能够减轻排序的负担。
  • 在 WHERE 子句的条件里可以使用索引。HAVING 子句是针对聚合后生成的视图进行筛选的, 但是很多时候聚合后的视图都没有继承原表的索引结构

2.5 在 GROUP BY 子句和 ORDER BY 子句中使用索引

一般来说,GROUP BY 子句和 ORDER BY 子句都会进行排序,来对行进行排列和替换。不过,通过指定带索引的列作为 GROUP BY 和 ORDER BY 的列,可以实现高速查询。特别是,在一些数据库中,如果操作对象的列上建立的是唯一索引,那么排序过程本身都会被省略掉。

三、使用索引

3.1 尽量避免在索引字段上进行运算

假设我们在一个叫作 col_1 的列上建立了索引,然后来看一看下面这条 SQL 语句。这条 SQL 语句本来是想使用索引,但实际上执行时却进行了全表扫描。

SELECT 

像下面这样把运算的表达式放到查询条件的右侧,就能用到索引了。

SELECT 

同样,在查询条件的左侧使用函数时,也不能用到索引。

SELECT 

使用索引时,条件表达式的左侧应该是原始字段。

3.2 不要对索引使用 IS NULL 谓词

索引字段通常是不存在 NULL 的,所以指定 IS NULL 和 IS NOT NULL 的话会使索引无法使用,进而导致查询性能低下。

SELECT 

如果需要使用类似 IS NOT NULL 的功能,又想用到索引,那么可以使用下面的方法,假设“col_1”列的最小值是 1。

-- IS NOT NULL 的替代方案

3.3 尽量避免否定形式

下面这几种否定形式不能用到索引。

  • <>
  • !=
  • NOT IN

因此,下面的 SQL 语句也会进行全表扫描。

SELECT 

3.4 尽量避免使用 OR

在 col_1 和 col_2 上分别建立了不同的索引,或者建立了 (col_1, col_2) 这样的联合索引时,如果使用 OR 连接条件,那么要么用不到索引,要么用到了但是效率比 AND 要差很多。

3.5 使用联合索引时 注意列的顺序

假设存在这样顺序的一个联合索引“col_1, col_2, col_3”。 这时,指定条件的顺序就很重要。联合索引中的第一列 (col_1) 必须写在查询条件的开头,而且索引中列的顺序不能颠倒。有些数据库里顺序颠倒后也能使用索引,但是性能还是比顺序正确时差一些。

--  fast

3.6 使用 LIKE 谓词前方一致

使用 LIKE 谓词时,只有前方一致的匹配才能用到索引。

-- fast

四、减少中间表

频繁使用中间表会带来两个问题,一是展开数据需要耗费内存资源, 二是原始表中的索引不容易使用到(特别是聚合时)。因此,尽量减少中 间表的使用也是提升性能的一个重要方法。

4.1 灵活使用 HAVING 子句

HAVING 子句和聚合操作是同时执行的,所以比起生成中间表后再执行的 WHERE 子句,效率会更高一些,而且代码看起来也更简洁。

-- slow

4.2 需要对多个字段使用 IN 谓词时,将他们汇总到一处

这种方法与前面的连接字段的方法相比有两个优点。一是不用担心连 接字段时出现的类型转换问题,二是这种方法不会对字段进行加工,因此 可以使用索引。

-- slow

4.3 先联结再聚合

先联结可以避免产生中间表。因为从集合运算的角度来看,联结做的是“乘法运算”。 联结表双方是一对一、一对多的关系时,联结运算后数据的行数不会增加。 而且,因为在很多设计中多对多的关系都可以分解成两个一对多的关系, 因此这个技巧在大部分情况下都可以使用。

4.4 合理使用视图

在视图的定义语句中包含以下运算的时候,SQL 会非常低效,执行速度也会变得非常慢。

  • 聚合函数 (SUM, COUNT, AVG, MAX, MIN)
  • 集合运算符 (UNION, INTERSECT, EXCEPT)

groupby多个字段性能_SQL 性能优化相关推荐

  1. 超级干货:3个性能监控和优化命令详解

    小编为大家整理出了三个有关性能监控和优化命令详细讲解,别看只有三个,但不影响他噎啊,本篇文章很长,涉及top命令.free命令和vmstat命令,真的是很详细的讲解,希望能帮到大家,另外还有两条相关的 ...

  2. java如何监控cpu耗时_超级干货:3个性能监控和优化命令讲解

    原标题:超级干货:3个性能监控和优化命令讲解 小编为大家整理出了三个有关性能监控和优化命令详细讲解,别看只有三个,但不影响他噎啊,本篇文章很长,涉及top命令.free命令和 vmstat命令,真的是 ...

  3. 基于linux服务器的性能分析与优化

    基于linux服务器的性能分析与优化 方面:硬件系统软件网络 现象:系统不稳定相应速度慢 web无法打开打开速度慢 方案:硬件故障更换硬件或升级硬件 系统问题修改系统参数和配置 软件问题修改和升级软件 ...

  4. 一个SQL性能问题的优化探索(二)(r11笔记第38天)

    继续前几天的一个案例一个SQL性能问题的优化探索(一)(r11笔记第33天) 如下的SQL语句存在索引字段CARD_NO,但是执行的时候却走了全表扫描,因为这是一个核心表,数据量很大,导致数据库负载很 ...

  5. DB2数据库性能调整和优化(第2版)

    <DB2数据库性能调整和优化(第2版)> 基本信息 作者: 牛新庄 出版社:清华大学出版社 ISBN:9787302325260 上架时间:2013-7-3 出版日期:2013 年7月 开 ...

  6. mysql 嵌套查询性能_mysql SQL优化之嵌套查询-遁地龙卷风

    (-1) 写在前面 这篇随笔的数据使用的是http://blog.csdn.net/friendan/article/details/8072668#comments里的,里面有一些常见的select ...

  7. 3个性能监控和优化命令讲解

    整理出了三个有关性能监控和优化命令详细讲解,文章很长,涉及top命令.free命令和vmstat命令,真的是很详细的讲解,希望能帮到大家 1 top命令 top命令是Linux下常用的性能分析工具,能 ...

  8. 推理芯片的性能建立在优化的存储子系统设计上

    推理芯片的性能建立在优化的存储子系统设计上 Inference chip performance builds on optimized memory subsystem design 好的推断芯片可 ...

  9. linux 性能 管理 与 优化

    一.影响Linux服务器性能的因素 操作系统级:CPU.内存.磁盘I/O带宽.网络I/O带宽 程序应用级 二.系统性能评估 影响性能因素   评判标准 好   坏   糟糕 CPU   user% + ...

最新文章

  1. Jackson 框架使用说明,轻易转换JSON【转】
  2. 数组转换成json key-value形式
  3. iframe嵌入页面白屏_封闭在家学网页制作!为页面嵌入PDF文件——零基础自学网页制作
  4. mysql replace 不区分大小写_mysql 不区分大小写的解决
  5. java构建学生对象布尔类型,Java如何将原始布尔类型转换为布尔对象?
  6. 编程中的数学——编程遇见数学,让数学更有趣!
  7. 疫情之后的2020长什么样
  8. pytest常用参数
  9. php 数组的长度函数,php数组长度函数的例子
  10. 展讯7731C_M Android6.0 充电指示灯实现(一)------关机充电实现
  11. 电子印章怎么验证真假?
  12. PADS9.5如何导出的光绘文件(Gerber),应该检查什么?
  13. JS 时间加减 / 小时加减
  14. tabindex 属性 - HTML中代表使用Tab键的遍历顺序
  15. RNN结构,双向LSTM,Transformer, BERT对比分析
  16. 业界最快的高转速马达,追觅科技V12无线吸尘器
  17. koa2搭建项目(一)
  18. 中兴通讯联合Heavy Reading解读5G承载解决方案的四个重要技术特征
  19. 【人工智能】什么是数据标注?
  20. 编写高性能JavaScript【转】

热门文章

  1. javascript之生成一个指定范围内的随机数
  2. matlab2c使用c++实现matlab函数系列教程-flipud函数
  3. Quartus17运行仿真RTL Simulation
  4. Spring Cloud之服务治理(注册发现)
  5. T-SQL Apply的用法
  6. nodejs+react使用webpack打包时控制台报错
  7. centos7安装git踩坑记
  8. 南阳理工oj 题目26 孪生素数问题 素数筛选法
  9. Codeforces Round #295 (Div. 1) C. Pluses everywhere
  10. JQuery ajax 在aspx中传值和取值