当前位置:首页 > 数码 > 释放查询潜能-高级SQL优化之分组字段顺序优化 (释放 潜能)

释放查询潜能-高级SQL优化之分组字段顺序优化 (释放 潜能)

admin8个月前 (05-06)数码32

如果一个查询中既包含来自同一个表的排序字段也包含分组字段,但字段顺序不同,可以通过调整分组字段顺序,使其和排序字段顺序一致,这样数据库可以避免一次排序操作。

问题定义

考虑以下两个 SQL,二者唯一的不同点是分组字段的顺序(第一个 SQL 是 o_custkey,o_orderdate ,第二个 SQL 是 o_orderdate,o_custkey ):


SELECT
  o_custkey,
  o_orderdate,
  SUM(o_totalprice)
FROM orders
GROUP BY
  o_custkey,
  o_orderdate
ORDER BY
  o_orderdate;
  

SELECT
  o_custkey,
  o_orderdate,
  SUM(o_totalprice)
FROM orders
GROUP BY
  o_orderdate,
  o_custkey
ORDER BY
  o_orderdate;
  

由于分组字段中不包括 groupingset/cube/rollup 等高级 grouping 操作,所以两个 SQL 是等价的。但是二者的执行计划及执行效率却不一样。第二个 SQL 的执行计划由于避免了对 o_orderdate 的一次排序操作,性能比第一个 SQL 要好,因此可以考虑将第一个 SQL 重写为第二个 SQL。

适用条件

分组字段重排序优化是针对查询块(Queryblock)来进行的,多个查询块可以独立进行此优化。分组字段重排序优化的适用条件如下:

  • 查询块中包含 GROUP BY 子句。
  • 查询块中包含 ORDER BY 子句。
  • GROUP BY 子句中的字段和 ORDER BY 子句中的字段来自同一个表。
  • 潜能 GROUP BY 子句中的字段顺序和 ORDER BY 子句中的字段顺序不同。

性能验证

以下是在 PostgreSQL 上运行两个 SQL 的执行计划,可以看到第二个 SQL 的执行计划中避免了对 o_orderdate 的一次排序操作:

以下是两个 SQL 的执行时间对比,可以看到第二个 SQL 的执行时间要比第一个 SQL 短:

SQL 执行时间(ms)
第一个 SQL 100
第二个 SQL 50

PawSQL 此优化的支持

PawSQL 支持分组字段重排序优化。PawSQL 是一款专注于数据库性能优化的自动化和智能化工具,支持 MySQL、PostgreSQL、openGauss、Oracle 等数据库。PawSQL 提供的 SQL 优化产品包括:

  • SQL 优化建议:PawSQL 会自动分析 SQL 语句,并提供优化建议,包括分组字段重排序优化。
  • SQL 重写:PawSQL 可以自动将 SQL 语句重写为性能更好的形式,包括应用分组字段重排序优化。
  • 执行计划分析:PawSQL 提供执行计划分析工具,可以帮助用户了解 SQL 语句的执行过程,并找出性能瓶颈。

关于 PawSQL

PawSQL 专注于数据库性能优化的自动化和智能化,旨在帮助用户快速、高效地提升数据库性能。PawSQL 的主要特点包括:

  • 支持多种数据库:PawSQL 支持 MySQL、PostgreSQL、openGauss、Oracle 等多种数据库。
  • 自动化优化:PawSQL 提供自动化的 SQL 优化建议和重写功能, giúp用户轻松提升数据库性能。
  • 智能分析:PawSQL 采用人工智能算法,对数据库性能数据进行深入分析,并提供有价值的优化见解。
  • 易于使用:PawSQL 提供了一个直观易用的界面,即使非技术人员也可以轻松使用。

如果您正在寻找一款功能强大、易于使用的数据库性能优化工具,PawSQL 是您的不二之选。立即注册 PawSQL,体验数据库性能优化的强大功能!

访问 PawSQL 官网:


sql语句执行顺序之group by、order by

1、先执行group by后执行order by,如果相同id的记录只获取id大的一条记录,使用子查询(先排序后分组): select *from (select *from table1 order by id desc limit 9999) a group by type_id; PS:group by需要和limit配合使用,不使用limit语句会自动被优化掉group by无效。 2、字段值为0的记录不分组,字段值大于0的记录进行分组:方法1:使用union all SELECT * FROM `table1` WHERE UNION ALL SELECT * FROM `table1` WHERE name!=0 group by name;方法2:使用case when :select的时候判断id是否等于0,等于0的话则赋值,然后再使用group by分组 select * from (select _time,,(CASE WHEN _id<1 THEN _time ELSE _id END) as product_id from order as o left join order_goods as og on _id=_id order by _time desc limit 9999) table1 group by product_id order by add_time desc 拓展:(使用上面sql)如果product_id不为空,需要加上判断只获取开启展示状态的product数据: select * from (select _time,,(CASE WHEN _id>1 THEN (select id from product where =_id and _show=1) ELSE _time END) as product_id from order as o left join order_goods as og on _id=_id order by _time desc limit 9999) table1where product_id is not null group by product_id order by add_time desc方法3:使用isfull()函数 ,思路和方法2一样,都是判断字段值是否为空,若是空值先赋一个临时值后分组需要注意的是,isfull只能用于判断是否为null,若值是0无效(见图3 图4)

ORACLE SQL语句优化技术分析

为了让更多的新手受益,我抽空把SQL语句优化部分进行了整理,希望大家一起进步。

一、操作符优化

1、IN 操作符

用IN写出来的SQL的优点是比较容易写及清晰易懂,这比较适合现代软件开发的风格。但是用IN的SQL性能总是比较低的,从Oracle执行的步骤来分析用IN的SQL与不用IN的SQL有以下区别:

ORACLE试图将其转换成多个表的连接,如果转换不成功则先执行IN里面的子查询,再查询外层的表记录,如果转换成功则直接采用多个表的连接方式查询。由此可见用IN的SQL至少多了一个转换的过程。一般的SQL都可以转换成功,但对于含有分组统计等方面的SQL就不能转换了。

推荐方案:在业务密集的SQL当中尽量不采用IN操作符,用EXISTS 方案代替。

2、NOT IN操作符

此操作是强列不推荐使用的,因为它不能应用表的索引。

推荐方案:用NOT EXISTS 方案代替

3、IS NULL 或IS NOT NULL操作(判断字段是否为空)

判断字段是否为空一般是不会应用索引的,因为索引是不索引空值的。

推荐方案:用其它相同功能的操作运算代替,如:a is not null 改为 a0 或a’’等。不允许字段为空,而用一个缺省值代替空值,如申请中状态字段不允许为空,缺省为申请。

4、 及操作符(大于或小于操作符)

大于或小于操作符一般情况下是不用调整的,因为它有索引就会采用索引查找,但有的情况下可以对它进行优化,如一个表有100万记录,一个数值型字段A,30万记录的A=0,30万记录的A=1,39万记录的A=2,1万记录的A=3。那么执行A2与A=3的效果就有很大的区别了,因为A2时ORACLE会先找出为2的记录索引再进行比较,而A=3时ORACLE则直接找到=3的记录索引。

5、LIKE操作符

LIKE操作符可以应用通配符查询,里面的通配符组合可能达到几乎是任意的查询,但是如果用得不好则会产生性能上的问题,如LIKE ‘%5400%’ 这种查询不会引用索引,而LIKE ‘X5400%’则会引用范围索引。

一个实际例子:用YW_YHJBQK表中营业编号后面的户标识号可来查询营业编号 YY_BH LIKE ‘%5400%’ 这个条件会产生全表扫描,如果改成YY_BH LIKE ’X5400%’ OR YY_BH LIKE ’B5400%’ 则会利用YY_BH的索引进行两个范围的查询,性能肯定大大提高。

6、UNION操作符

UNION在进行表链接后会筛选掉重复的记录,所以在表链接后会对所产生的结果集进行排序运算,删除重复的记录再返回结果。实际大部分应用中是不会产生重复的记录,最常见的是过程表与历史表UNION。如: select * from gc_dfys union select * from ls_jg_dfys 这个SQL在运行时先取出两个表的结果,再用排序空间进行排序删除重复的记录,最后返回结果集,如果表数据量大的话可能会导致用磁盘进行排序。

推荐方案:采用UNION ALL操作符替代UNION,因为UNION ALL操作只是简单的将两个结果合并后就返回。

select * from gc_dfys union all select * from ls_jg_dfys

二、SQL书写的影响

1、同一功能同一性能不同写法SQL的影响。

如一个SQL在A程序员写的为 Select * from zl_yhjbqk

B程序员写的为 Select * from _yhjbqk(带表所有者的前缀)

C程序员写的为 Select * from (大写表名)

D程序员写的为 Select * from (中间多了空格)

以上四个SQL在ORACLE分析整理之后产生的结果及执行的时间是一样的,但是从ORACLE共享内存SGA的原理,可以得出ORACLE对每个SQL 都会对其进行一次分析,并且占用共享内存,如果将SQL的字符串及格式写得完全相同,则ORACLE只会分析一次,共享内存也只会留下一次的分析结果,这不仅可以减少分析SQL的时间,而且可以减少共享内存重复的信息,ORACLE也可以准确统计SQL的执行频率。

2、WHERE后面的条件顺序影响

WHERE子句后面的条件顺序对大数据量表的查询会产生直接的影响。如: Select * from zl_yhjbqk where dy_dj = 1KV以下 and xh_bz=1 Select * from zl_yhjbqk where xh_bz=1 and dy_dj = 1KV以下 以上两个SQL中dy_dj(电压等级)及xh_bz(销户标志)两个字段都没进行索引,所以执行的时候都是全表扫描,第一条SQL的dy_dj = 1KV以下条件在记录集内比率为99%,而xh_bz=1的比率只为0.5%,在进行第一条SQL的时候99%条记录都进行dy_dj及xh_bz的比较,而在进行第二条SQL的时候0.5%条记录都进行dy_dj及xh_bz的比较,以此可以得出第二条SQL的CPU占用率明显比第一条低。

3、查询表顺序的影响

在FROM后面的表中的列表顺序会对SQL执行性能影响,在没有索引及ORACLE没有对表进行统计分析的情况下,ORACLE会按表出现的顺序进行链接,由此可见表的顺序不对时会产生十分耗服物器资源的数据交叉。(注:如果对表进行了统计分析,ORACLE会自动先进小表的链接,再进行大表的链接)

三、SQL语句索引的利用

1、操作符优化(同上)

2、对条件字段的一些优化

采用函数处理的字段不能利用索引,如:

substr(hbs_bh,1,4)=’5400’,优化处理:hbs_bh like ‘5400%’

trunc(sk_rq)=trunc(sysdate), 优化处理:sk_rq=trunc(sysdate) and sk_rqtrunc(sysdate+1)

进行了显式或隐式的运算的字段不能进行索引,如:ss_df+2050,优化处理:ss_df30

‘X’ || hbs_bh’X’,优化处理:hbs_bh’’

sk_rq+5=sysdate,优化处理:sk_rq=sysdate-5

hbs_bh=,优化处理:hbs_bh=’ ’,注:此条件对hbs_bh 进行隐式的to_number转换,因为hbs_bh字段是字符型。

条件内包括了多个本表的字段运算时不能进行索引,如:ys_dfcx_df,无法进行优化 qc_bh || kh_bh=’’,优化处理:qc_bh=’5400’ and kh_bh=’’

四、其他

ORACLE的提示功能是比较强的功能,也是比较复杂的应用,并且提示只是给ORACLE执行的一个建议,有时如果出于成本方面的考虑ORACLE也可能不会按提示进行。根据实践应用,一般不建议开发人员应用ORACLE提示,因为各个数据库及服务器性能情况不一样,很可能一个地方性能提升了,但另一个地方却下降了,ORACLE在SQL执行分析方面已经比较成熟,如果分析执行的路径不对首先应在数据库结构(主要是索引)、服务器当前性能(共享内存、磁盘文件碎片)、数据库对象(表、索引)统计信息是否正确这几方面分析。

免责声明:本文转载或采集自网络,版权归原作者所有。本网站刊发此文旨在传递更多信息,并不代表本网赞同其观点和对其真实性负责。如涉及版权、内容等问题,请联系本网,我们将在第一时间删除。同时,本网站不对所刊发内容的准确性、真实性、完整性、及时性、原创性等进行保证,请读者仅作参考,并请自行核实相关内容。对于因使用或依赖本文内容所产生的任何直接或间接损失,本网站不承担任何责任。

标签: SQL优化