DM SQL 排序优化-消除排序

在数据库查询优化中,ORDER BY 子句导致的排序操作往往是性能瓶颈之一。当前测试展示如何通过合理的索引设计来消除排序操作,显著提升查询性能。

场景介绍 我们有一个销售表 EMPLOYEE,包含以下字段:

  • HIRE_DATE:入职时间
  • EMPLOYEE_ID:员工ID
  • SALARY:薪水

业务需求:查询最近11 年的员工信息,并按入职时间降序、员工ID 降序排列。

场景一:没有索引

初始查询语句:

复制代码
  select e.HIRE_DATE,
         e.EMPLOYEE_ID,
         e.SALARY
    from DMHR.EMPLOYEE e
   where e.HIRE_DATE >= trunc(sysdate) - interval '11' year
order by e.HIRE_DATE desc,
         e.EMPLOYEE_ID desc;

查询出的数据:

复制代码
HIRE_DATE	EMPLOYEE_ID	SALARY
'2015-03-27'	8004	5000
'2015-03-27'	6004	5000

执行计划:

复制代码
1   #NSET2: [1, 1, 33] 
2     #PRJT2: [1, 1, 33]; exp_num(4), is_atom(FALSE) 
3       #SORT3: [1, 1, 33]; key_num(2), partition_key_num(0), is_distinct(FALSE), top_flag(0), is_adaptive(0)
4         #SLCT2: [1, 1, 33]; e.HIRE_DATE >= var4
5           #CSCN2: [1, 856, 33]; INDEX33555499(EMPLOYEE as e); btr_scan(1)

场景二:只有一个单列索引

只在 HIRE_DATE 列上创建一个索引:

复制代码
CREATE INDEX DMHR.IND_HIRE_DATE20251231 ON DMHR.EMPLOYEE("HIRE_DATE" ASC);

执行计划:

复制代码
1   #NSET2: [1, 1, 33] 
2     #PRJT2: [1, 1, 33]; exp_num(4), is_atom(FALSE) 
3       #SORT3: [1, 1, 33]; key_num(2), partition_key_num(1), is_distinct(FALSE), top_flag(0), is_adaptive(0)
4         #BLKUP2: [1, 1, 33]; IND_HIRE_DATE20251231(e)
5           #SSEK2: [1, 1, 33]; scan_type(DESC), IND_HIRE_DATE20251231(EMPLOYEE as e), scan_range[exp11,max], is_global(0)

关键发现:上面执行计划中出现了 SORT3 操作符,说明数据库在进行显式排序,可以通过ET 输出,可以判断使用了多少内存(MEM_USED(KB),DISK_USED(KB))。

第一次优化:创建复合索引

复制代码
create index IND_HIRE_ID on  DMHR.EMPLOYEE(HIRE_DATE, EMPLOYEE_ID);

(删除旧索引后,实际测试没有删除页可以)重新执行查询,执行计划变为:

复制代码
1   #NSET2: [1, 1, 33] 
2     #PRJT2: [1, 1, 33]; exp_num(4), is_atom(FALSE) 
3       #BLKUP2: [1, 1, 33]; IND_HIRE_ID(e)
4         #SSEK2: [1, 1, 33]; scan_type(DESC), IND_HIRE_ID(EMPLOYEE as e), scan_range[(exp11,min),(max,max)), is_global(0)

优化效果:SORT3 操作符消失了!数据库通过反向扫描索引直接获得了正确排序的结果。

场景二:混合排序场景

修改查询,要求按入职时间降序、员工ID升序排列:

复制代码
  select e.HIRE_DATE,
         e.EMPLOYEE_ID,
         e.SALARY
    from DMHR.EMPLOYEE e
   where e.HIRE_DATE >= trunc(sysdate) - interval '11' year
order by e.HIRE_DATE desc,
         e.EMPLOYEE_ID asc;

执行计划:

复制代码
1   #NSET2: [1, 1, 33] 
2     #PRJT2: [1, 1, 33]; exp_num(4), is_atom(FALSE) 
3       #SORT3: [1, 1, 33]; key_num(2), partition_key_num(1), is_distinct(FALSE), top_flag(0), is_adaptive(0)
4         #BLKUP2: [1, 1, 33]; IND_HIRE_DATE20251231(e)
5           #SSEK2: [1, 1, 33]; scan_type(DESC), IND_HIRE_DATE20251231(EMPLOYEE as e), scan_range[exp11,max], is_global(0)

问题再现:SORT3 操作符再次出现!虽然使用了复合索引,但排序方向不匹配。

解决方案:匹配排序方向的索引

创建与 ORDER BY 子句完全一致的索引:

复制代码
create or replace index IND_HIRE_ID on DMHR.EMPLOYEE(HIRE_DATE desc, EMPLOYEE_ID asc);

执行计划:

复制代码
1   #NSET2: [1, 1, 33] 
2     #PRJT2: [1, 1, 33]; exp_num(4), is_atom(FALSE) 
3       #BLKUP2: [1, 1, 33]; IND_HIRE_ID(e)
4         #SSEK2: [1, 1, 33]; scan_type(ASC), IND_HIRE_ID(EMPLOYEE as e), scan_range[(null2,min),(exp11,max)), is_global(0)

最终效果:排序再次被消除!这次数据库通过正向扫描特殊设计的索引获得了正确结果。

核心原理总结

1. 索引消除排序的条件

  • 当 ORDER BY 的顺序与索引扫描结果的顺序完全一致时,可消除排序
  • 数据库可以正向或反向扫描索引来匹配不同的排序需求

2. 不同场景下的匹配规则

复制代码
ORDER BY 子句	可消除排序的索引	扫描方向
A DESC, B DESC	(A ASC, B ASC)	反向扫描
A ASC, B ASC	(A ASC, B ASC)	正向扫描
A DESC, B ASC	(A DESC, B ASC)	正向扫描

3. 达梦数据库的执行计划关键操作符

  • SORT3:显式排序操作,消耗内存和CPU
  • SSEK2:索引范围扫描,scan_type 显示扫描方向
  • BLKUP2:通过索引回表取数据

实践建议

  • 分析执行计划:关注 SORT 操作符的出现,这是优化的信号
  • 创建复合索引:将 WHERE 条件和 ORDER BY 的列都考虑进索引
  • 匹配排序方向:对于混合排序(ASC/DESC混合),创建对应方向的索引
  • 权衡索引数量:虽然专用索引性能最佳,但要考虑维护成本

欢迎访问达梦技术分享社区 ECO

https://eco.dameng.com

相关推荐
aqiu1111114 小时前
【算法刷题】蓝桥杯:怎么倒茶(贪心算法 + 结构体排序)
贪心·排序
OuO-24 小时前
笔试强训 Day 43:kotori 和抽卡(二)、ruby 和薯条、循环汉诺塔
数学·前缀和·二分查找·动态规划·排序·滑动窗口·循环汉诺塔
Tisfy5 天前
LeetCode 3731.找出缺失的元素:哈希 / 排序
算法·leetcode·哈希算法·排序·哈希表
Tisfy14 天前
LeetCode 3016.输入单词需要的最少按键次数 II:排序(贪心)
linux·算法·leetcode·题解·贪心·排序·计数
Tisfy17 天前
LeetCode 3517.最小回文排列 I:排序(Python两行版) / 计数(O(n)时间+O(C)空间+字符串原地修改)
c语言·python·leetcode·字符串·排序·计数排序·回文
txzrxz19 天前
拓补排序讲解
c++·算法·图论·排序
汉克老师1 个月前
GESP2026年6月认证C++八级( 第三部分编程题(1、线网建设))精讲
c++·最小生成树·排序·kruskal·并查集·gesp8级
Tisfy1 个月前
LeetCode 1288.删除被覆盖区间:排序(非二重循环暴力)
算法·leetcode·题解·排序
hairenwangmiao2 个月前
c++排序(第一章----桶排序与sort排序)
数据结构·c++·排序
hairenwangmiao2 个月前
B4041 [GESP202409 四级] 区间排序
算法·排序