groupby多个字段性能_SQL 性能优化
![](/assets/blank.gif)
SQL 的性能优化是数据库工程师在实际工作中必须面对的课题之一。对于某些数据库工程师来说,它几乎是唯一的课题。实际上,在像 Web 服务这样需要快速响应的应用场景中,SQL 的性能直接决定了系统是否可以使用。在 SQL 中,很多时候不同代码能够得出相同结果。从理论上来说,得到相同结果的不同代码应该有相同的性能,但遗憾的是,查询优化器生成的执行计划很大程度上要受到代码外部结构的影响。因此如果想优化查询性能,必须知道如何写代码才能使优化器的执行效率更高。
一、使用高效查询
1.1 参数是子查询时,使用 EXISTS 代替 IN
在大多时候,[NOT] IN 和 [NOT] EXISTS 返回的结果是相同的。但是两者用于子查询时,EXISTS 的速度会更快一些。
如下两张表中包含了选课程 A 和课程 B 的学生。
![](/assets/blank.gif)
![](/assets/blank.gif)
从 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
![](/assets/blank.gif)
如果不在乎结果中是否有重复数据,或者事先知道不会有重复数据,尽量使用 UNION ALL 代替 UNION。这样就不会进行排序了。
SELECT
![](/assets/blank.gif)
对于 INTERSECT 和 EXCEPT 也是一样的,加上 ALL 可选项后就不会进行排序了。加上 ALL 可选项是优化性能的一个非常有效的手段,但在 MySQL 中 不支持 INTERCEPT ALL 和 EXCEPT ALL。
2.2 使用 EXISTS 代替 DISTINCT
为了排除重复数据,DISTINCT 也会进行排序。如果需要对两张表的联结结果进行去重,可以考虑使用 EXISTS 代替 DISTINCT,以避免排序。
如下 Items 表中包含某公司的各商品编号及名称;SalesHistory 表中包含各商品的销售情况。
![](/assets/blank.gif)
![](/assets/blank.gif)
从上面的商品表 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 性能优化相关推荐
- 超级干货:3个性能监控和优化命令详解
小编为大家整理出了三个有关性能监控和优化命令详细讲解,别看只有三个,但不影响他噎啊,本篇文章很长,涉及top命令.free命令和vmstat命令,真的是很详细的讲解,希望能帮到大家,另外还有两条相关的 ...
- java如何监控cpu耗时_超级干货:3个性能监控和优化命令讲解
原标题:超级干货:3个性能监控和优化命令讲解 小编为大家整理出了三个有关性能监控和优化命令详细讲解,别看只有三个,但不影响他噎啊,本篇文章很长,涉及top命令.free命令和 vmstat命令,真的是 ...
- 基于linux服务器的性能分析与优化
基于linux服务器的性能分析与优化 方面:硬件系统软件网络 现象:系统不稳定相应速度慢 web无法打开打开速度慢 方案:硬件故障更换硬件或升级硬件 系统问题修改系统参数和配置 软件问题修改和升级软件 ...
- 一个SQL性能问题的优化探索(二)(r11笔记第38天)
继续前几天的一个案例一个SQL性能问题的优化探索(一)(r11笔记第33天) 如下的SQL语句存在索引字段CARD_NO,但是执行的时候却走了全表扫描,因为这是一个核心表,数据量很大,导致数据库负载很 ...
- DB2数据库性能调整和优化(第2版)
<DB2数据库性能调整和优化(第2版)> 基本信息 作者: 牛新庄 出版社:清华大学出版社 ISBN:9787302325260 上架时间:2013-7-3 出版日期:2013 年7月 开 ...
- mysql 嵌套查询性能_mysql SQL优化之嵌套查询-遁地龙卷风
(-1) 写在前面 这篇随笔的数据使用的是http://blog.csdn.net/friendan/article/details/8072668#comments里的,里面有一些常见的select ...
- 3个性能监控和优化命令讲解
整理出了三个有关性能监控和优化命令详细讲解,文章很长,涉及top命令.free命令和vmstat命令,真的是很详细的讲解,希望能帮到大家 1 top命令 top命令是Linux下常用的性能分析工具,能 ...
- 推理芯片的性能建立在优化的存储子系统设计上
推理芯片的性能建立在优化的存储子系统设计上 Inference chip performance builds on optimized memory subsystem design 好的推断芯片可 ...
- linux 性能 管理 与 优化
一.影响Linux服务器性能的因素 操作系统级:CPU.内存.磁盘I/O带宽.网络I/O带宽 程序应用级 二.系统性能评估 影响性能因素 评判标准 好 坏 糟糕 CPU user% + ...
最新文章
- Jackson 框架使用说明,轻易转换JSON【转】
- 数组转换成json key-value形式
- iframe嵌入页面白屏_封闭在家学网页制作!为页面嵌入PDF文件——零基础自学网页制作
- mysql replace 不区分大小写_mysql 不区分大小写的解决
- java构建学生对象布尔类型,Java如何将原始布尔类型转换为布尔对象?
- 编程中的数学——编程遇见数学,让数学更有趣!
- 疫情之后的2020长什么样
- pytest常用参数
- php 数组的长度函数,php数组长度函数的例子
- 展讯7731C_M Android6.0 充电指示灯实现(一)------关机充电实现
- 电子印章怎么验证真假?
- PADS9.5如何导出的光绘文件(Gerber),应该检查什么?
- JS 时间加减 / 小时加减
- tabindex 属性 - HTML中代表使用Tab键的遍历顺序
- RNN结构,双向LSTM,Transformer, BERT对比分析
- 业界最快的高转速马达,追觅科技V12无线吸尘器
- koa2搭建项目(一)
- 中兴通讯联合Heavy Reading解读5G承载解决方案的四个重要技术特征
- 【人工智能】什么是数据标注?
- 编写高性能JavaScript【转】
热门文章
- javascript之生成一个指定范围内的随机数
- matlab2c使用c++实现matlab函数系列教程-flipud函数
- Quartus17运行仿真RTL Simulation
- Spring Cloud之服务治理(注册发现)
- T-SQL Apply的用法
- nodejs+react使用webpack打包时控制台报错
- centos7安装git踩坑记
- 南阳理工oj 题目26 孪生素数问题 素数筛选法
- Codeforces Round #295 (Div. 1) C. Pluses everywhere
- JQuery ajax 在aspx中传值和取值