注册
达梦性能优化
技术分享/ 文章详情 /

达梦性能优化

少年 2025/08/08 110 0 0

一、系统层面

性能分析需从三个核心维度逐层排查,定位问题根源:

1. 操作系统层

聚焦 CPU、内存、I/O 等基础资源使用情况,常用监控工具及作用如下:
top:实时监控 CPU 使用率与进程状态,按Shift+P可按 CPU 使用率排序。
image.png

指标分类 关键指标 含义解读(结合数据库性能分析场景) 示例数据
系统基础 时间 当前系统时间,用于定位性能问题发生时刻 15:00:08
负载平均值 过去 1/5/15 分钟系统平均负载,反映整体压力(如>CPU 核心数需警惕) load average: 0.06, 0.06, 0.08
CPU 核心 % Cpu(s) 核心占比 us(用户态,数据库进程常用)、sy(内核态,I/O 等消耗)<br>理想比例:us > sy,sy 持续高表明系统调用过多 %Cpu(s): 0.3 us, 0.5 sy
内存核心 总内存 / 已用 / 可用 物理内存总量、已占用(含缓存)、实际可分配给数据库的量<br>当可用内存 < 10% 总内存时需预警 Mem: 2884.3 total / 1597.2 used / 274.5 avail
交换空间 已用 Swap 虚拟内存使用量(过高可能引发数据库性能波动)<br>Swap使用率 > 20% 会导致显著性能下降 Swap used: 3342.6
进程关键 PID + COMMAND 进程 ID 与名称(重点关注 dmserver 等数据库进程) PID 309756(dmserver)
% CPU(进程) 单个进程 CPU 占用(如 dmserver 持续 > 80% 需排查 SQL 或索引问题) dmserver: 0.3% CPU
% MEM(进程) 进程内存占用(数据库进程内存不足会触发磁盘交换)<br>持续增长可能预示内存泄漏 dmserver: 0.1% MEM

内存 avail 过低且 Swap 高用,说明物理内存紧张,可能导致数据库缓存失效、性能下降。

iostat/dstat:分析磁盘 I/O 使用情况,前者可查看读写速率等指标,后者能更直观地收集 CPU、I/O 等信息并每秒刷新。
image.png

指标分类 关键指标 含义解读(结合数据库场景) 示例数据
CPU 关联 %iowait CPU 等待磁盘 I/O 完成的时间占比,高值说明磁盘慢 0.28%
磁盘设备 Device 磁盘设备名(如 sda 是系统盘 / 数据库盘需关注) sda、loop0
tps 每秒向磁盘发起的 I/O 请求数(数据库读写压力) sda: 105.05
kB_read/s 每秒从磁盘读取的数据量(读性能瓶颈参考) sda: 1799.14 KB/s
kB_wrtn/s 每秒向磁盘写入的数据量(写性能瓶颈参考) sda: 711.82 KB/s

场景化分析:
•若 %iowait 持续>10% + sda 的 tps 高,说明数据库所在磁盘 I/O 拥堵,可能导致 SQL 执行变慢(如查询需读磁盘、事务写落盘延迟);
•若 kB_read/s 长期接近磁盘最大读速,需检查数据库是否有大量全表扫描(没走索引),或考虑升级存储(SSD 替换机械盘)。
核心用于快速判断 “磁盘 I/O 是否拖慢数据库” ,抓住磁盘读写请求、吞吐量、CPU 等待这几个核心点即可初步排查 。

•free:查看内存使用情况,了解已用、空闲及缓存内存等数据。
•nmon:用于长期监控系统整体资源情况,例如执行./nmon -f -t -s 10 -c 1435可实现持续 8 小时、每 10 秒采集一次数据的监控。
•perf top:定位系统热点函数,如libdmdta.50中的高频操作,辅助找到性能瓶颈底层原因。
•使用 vmstat 命令对磁盘 I/O 性能进行分析:

[root@dm8 ~]# vmstat 1 5
image.png
如果 b 的值为 2~3 倍 CPU 数量,bi 和 bo 的值很大(有时 bi 和 bo 值很小,但 in 和 cs 很大,也会引起磁盘 IO 负载重),wa 的值持续很高,如高于 40,id 也持续高于 70,这些现象都表明系统的 IO 可能出现性能问题。
可以进一步通过 iostat 命令分析,如下所示:
结果分析
image.png
检查 %util(服务 IO 的时间占总时间的百分比),如果这个值接近 100%,表示 IO 的请求很多(表示任务服务的所有时间几乎都用在 IO 上),这种现象表明磁盘 IO 性能出现瓶颈。
检查r_await(读请求平均等待 + 处理耗时)、w_await(写请求平均等待 + 处理耗时 )这些细分指标的,传统的 await(整体 I/O 请求平均耗时)可通过 r_await、w_await 结合读写比例大致推算,或者理解为这里用细分的读写等待来呈现更细粒度的 I/O 延迟情况。
检查aqu-sz:表示 IO 排队的现象,如果排队过长会影响 IO 的响应时间。
r/s+w/s:可以计算当前系统的 iops(可以结合硬盘的测试或者硬件参数来衡量是否超过磁盘的 iops 最大值)。
通过 iostat 了解到如果磁盘 I/O 出现性能瓶颈,可以借助 pidstat ,定位出导致瓶颈的进程,分析进程的 I/O 行为,结合应用程序的原理,分析这些 I/O 的来源。

2.网络性能诊断

网络性能对数据库也有很大的影响,数据库服务器和 Web 服务器之间会进行网络传输,网络延迟和带宽大小都是影响因素。
相关命令:ifconfig
ifconfig 是 linux 中用于显示或配置网络设备(网络接口卡)的命令。在某系统中输入此命令后显示结果如下所示:
ifconfig
image.png

ethtool ens33
image.png
结果解读:
Supported link modes 为网卡支持的连接模式。
speed 和 duplex 字段为当前网络速率和模式。
分析方法
使用 ping 命令测试网络的连通性和响应时间。
ping 发送 ICMP echo 数据包来探测网络的连通性,除了能直观地看出网络的连通状况外,还能获得本次连接的往返时间(RTT 时间),丢包情况,以及访问的域名所对应的 IP 地址(使用 DNS 域名解析)。

ping -c 4 baidu.com ##参数 -c 表示指定发包数。

image.png
解析 ping baidu.com 结果
执行 ping -c 4 baidu.com ,解析到百度某台服务器的 IP 地址为 182.61.201.211 。
RTT(往返时间)相关统计:
最小 RTT(rtt min):6.839 ms
平均 RTT(rtt avg):10.783 ms
最大 RTT(rtt max):20.902 ms
算术平均差(rtt mdev,反映延迟波动程度 ):5.853 ms

解析 ping 10.127.17.131 结果(补充说明 )
执行 ping -c 4 10.127.17.131 ,目标为内网 IP 10.127.17.131 ,其 RTT 统计:
最小 RTT:0.043 ms
平均 RTT:2.604 ms
最大 RTT:10.230 ms
算术平均差:4.402 ms

3. 数据库层

从架构、参数和会话三个方面优化数据库运行状态:
•架构优化:根据业务类型选择合适架构,事务型业务采用读写分离,分析型业务采用 MPP 集群。
•参数调优(关键参数示例):
image.png
•会话监控:
◦查看活跃会话:SELECT COUNT(*) FROM VSESSIONS WHERE STATE='ACTIVE'。 ◦分析阻塞查询:通过VLOCK和V$SESSIONS关联查询,定位阻塞源头。

4.SQL 记录配置

下载安装DMLOG工具
image.png

[dmdba@dameng DMLOG8.181]$ vi dmlog.properties
image.png

[root@dm8 DMLOG8.181]# java -jar Dmlog_DM_8.18.jar
运行过程如下图所示,执行完成后会按当前时间生成对应 RESULT_$DATE 文件夹,并将所有统计信息都存放该目录中。
image.png
image.png

的 RESULT_$DATE 结果文件夹下有根据配置的执行时间和执行次数上限值命名的 excel 文件(xls)、报错的 SQL 文件(txt)、长度超过 30000 的 SQL 文件 (txt),echart 散点图及 90% 平均次数和平均耗时的 SQL 统计图 (html)。

SP_SET_PARA_VALUE(1,'SVR_LOG',1);
image.png
配置数据文件目录下的 sqllog.ini 文件。
image.png

如果对 sqllog.ini 进行了修改,可通过调用以下函数即时生效,无需重启数据库。
SP_REFRESH_SVR_LOG_CONFIG();
image.png
配置成功以后可以通过
sqllog.ini 文件配置成功后可在 dmsql 指定目录下生成 dmsql 开头的 log 日志文件。日志内容如下所示
image.png
执行

[root@dm8 DMLOG8.181]# nohup java -jar -Xms256m -Xmx4096m Dmlog_DM_8.18.jar > ./sql_realtime_parse2.log 2>&1 &

image.png

二、SQL 分析方法

1. 执行计划

简单来说,执行计划就是一条 SQL 语句在数据库中的执行过程或访问路径的描述。SQL 语言是种功能强大且非过程性的编程语言,比如以下这条 SQL 语句:

EXPLAIN SELECT * FROM ADMINS;

image.png
执行计划的每行即为一个计划节点,主要包含三部分信息。
第一部分 NEST2、PRJT2、CSCN2 为操作符及数据库具体执行了什么操作。
第二部分的三元组为该计划节点的执行代价,具体含义为[代价,记录行数,字节数]。
第三部分为操作符的补充信息。
例如:第三个计划节点表示操作符是 CSCN2(即全表扫描),代价估算是 1 ms,扫描的记录行数是 1行,输出字节数是 125个。
各计划节点的执行顺序为:缩进越多的越先执行,同样缩进的上面的先执行,下面的后执行,上下的优先级高于内外。缩进最深的,最先执行;缩进深度相同的,先上后下。口诀:最右最上先执行。

2. 查看执行计划

达梦数据库可通过两种方式查看执行计划。
方式一:通过 DM 数据库配套管理工具查看。
方式二:使用 explain 命令查看。
以下对两种查看方式进行介绍。

(1)管理工具查看执行计划

在 DM 配套管理工具中,选中待查看执行计划的 SQL 语句,点击工具栏中的按钮,或使用快捷键 F9,即可查看执行计划。

(2)使用 explain 命令查看执行计划

在待查看执行计划的 SQL 语句前加 explain 执行 SQL 语句即可查看预估的执行计划:

EXPLAIN SELECT * FROM TEST2;-- 文本模式查看执行计划

(3)使用 disql 命令行查真实执行计划

set autotrace traceonly SELECT * FROM TEST2;

image.png
重点关注 logical reads(逻辑读)和 physical reads(物理读)相应的指标值,并结合 rows processed 返回处理行数多少来分析。如果返回行数少(并且 bytes sent to client 总量不大),应尽可能减少 IO 开销,让执行计划选择正确的索引路径。 Sort(disk) 一般因排序( hash join 发生归并、order by、group by 场景)区内存不足,如果数据库服务器物理内存充足,可以适当上调排序区内存,尽量避免操作刷盘,否则会影响执行性能。

3. 执行计划操作分析

•关键操作符及含义:
image.png

EXPLAIN SELECT * FROM TEST2;-- 文本模式查看执行计划
4.常见操作符解读
EXPLAIN SELECT * FROM TEST2;

image.png
1.NSET 是用于结果集收集的操作符,一般是查询计划的顶层节点,优化工作中无需对该操作符过多关注,一般没有优化空间。
2. PRJT:投影
PRJT 是关系的【投影】 (project) 运算,用于选择表达式项的计算。广泛用于查询,排序,函数索引创建等。优化工作中无需对该操作符过多关注,一般没有优化空间。
3.CSCN:全表扫描
CSCN2 是 CLUSTER INDEX SCAN 的缩写即通过聚集索引扫描全表,全表扫描是最简单的查询,如果没有选择谓词,或者没有索引可以利用,则系统一般只能做全表扫描。全表扫描 I/O 开销较大,在一个高并发的系统中应尽量避免全表扫描。

5.ET工具

ET 工具是 DM 数据库自带的 SQL 性能分析工具,能够统计 SQL 语句执行过程中每个操作符的实际开销,为 SQL 优化提供依据以及指导。

  1. 功能的开启/关闭
    ET 功能默认关闭,可通过配置 INI 参数中的 ENABLE_MONITOR=1、MONITOR_SQL_EXEC=1 开启该功能。
--两个参数均为动态参数,可直接调用系统函数进行修改 SP_SET_PARA_VALUE(1,'ENABLE_MONITOR',1); SP_SET_PARA_VALUE(1,'MONITOR_SQL_EXEC',1); --会话级别修改只在当前会话生效 SF_SET_SESSION_PARA_VALUE('MONITOR_SQL_EXEC',1); --关闭 ET SP_SET_PARA_VALUE(1,'ENABLE_MONITOR',0); SP_SET_PARA_VALUE(1,'MONITOR_SQL_EXEC',0);

2.查看方式
点击执行号即可打开ET查看
image.png

ET 结果说明:
OP: 操作符
TIME(us): 时间开销,单位为微秒
PERCENT: 执行时间占总时间百分比
RANK: 执行时间耗时排序
SEQ: 执行计划节点号
N_ENTER: 进入次数
当看到CSCN2操作符,说明进行了全表扫描,向上寻找SLCT2操作符,给SLCT2中的过滤条件增加索引可以消除全表扫描。通过消除全表扫描可以解决大部分的sql性能问题。
关键问题分析:
CSCN2(全表扫描)占比77.20% - 主要性能瓶颈
SLCT2(内存过滤)占比4.3% - 在内存中过滤条件
查看执行计划
image.png

创建合适的索引

CREATE INDEX IDX_STUDENT_NAME ON STUDENT_SCORES(STUDENT_NAME);

image.png

CREATE INDEX IDX_COURSE_SCORE ON STUDENT_SCORES(COURSE, SCORE);

image.png
创建复合覆盖索引

CREATE INDEX IDX_COURSE_SCORE_COVER ON STUDENT_SCORES(COURSE, SCORE, STUDENT_NAME);

image.png

从单字段到复合、再到覆盖索引,执行步骤的耗时分布和占比逐步变化,覆盖索引更贴合 “索引即数据” 的查询场景,减少了额外 IO,适合需要多字段过滤或返回的查询。可根据实际查询语句(如 WHERE 条件、SELECT 字段)选择对应索引优化性能。

6.分组的优化

案例1:基础分组查询(未优化)

– 低效查询:全表扫描+哈希分组

EXPLAIN SELECT department, COUNT(*), AVG(salary) FROM adm GROUP BY department;

image.png

image.png
执行计划分析:​​
1 #NSET2: [10, 1, 86]
2 #PRJT2: [10, 1, 86]
3 #HAGR2: [10, 1, 86]; grp_num(1) -- 哈希分组
4 #CSCN2: [1, 10000, 86] -- 全表扫描

案例2:有序分组优化(SAGR)

– 高效查询:索引扫描+有序分组

EXPLAIN SELECT /*+ USE_SAGR_GROUP */ department, COUNT(*), AVG(salary) FROM adm GROUP BY department; -- 部门字段已建索引

image.png
image.png
优化后执行计划:​​
1 #NSET2: [10, 1, 86]
2 #PRJT2: [10, 1, 86]
3 #SAGR2: [10, 1, 86]; grp_num(1) -- 有序分组
4 #SSCN: [1, 10000, 86] -- 索引扫描(IDX_ADMIN_DEPT)

案例3:分组+过滤优化

– 低效:先分组后过滤

EXPLAIN SELECT department, AVG(salary) FROM adm GROUP BY department HAVING AVG(salary) > 6000;

image.png
在执行 GROUP BY department 时,数据库需要对 adm 表中的所有数据进行分组操作。然后,再对分组后的结果使用 HAVING AVG(salary) > 6000 进行过滤。这意味着数据库要先处理表中全部数据来完成分组聚合计算(如计算每个部门的平均薪资 ),即使最终很多分组结果是要被过滤掉的。
例如,假设 adm 表中有 10 万条数据,涉及 100 个部门,数据库要先对这 10 万条数据进行分组,计算出 100 个部门的平均薪资, 然后再过滤掉不符合条件的部门, 若大部分部门平均薪资都不超过 6000,那么前面大量的分组计算其实是做了 “无用功”。
– 高效:先过滤后分组

EXPLAIN SELECT /*+ INDEX(admin IDX_ADMIN_SAL_DEPT) */ department, AVG(salary) FROM adm WHERE salary > 6000 -- 利用复合索引 GROUP BY department;

image.png
image.png

案例4:多字段分组优化

– 低效:无序分组

EXPLAIN SELECT department, access_level, COUNT(*) FROM admin GROUP BY department, access_level;

image.png
image.png
– 高效:有序分组
创建的 IDX_ADMIN_DEPT_LEVEL (department, access_level) 复合索引与 GROUP BY 的字段顺序完全匹配

CREATE INDEX IDX_ADMIN_DEPT_LEVEL ON adm(department, access_level); EXPLAIN SELECT /*+ USE_SAGR_GROUP */ department, access_level, COUNT(*) FROM adm GROUP BY department, access_level; -- 复合索引字段

image.png
image.png
用二级索引扫描替代聚簇 / 全表扫描,索引数据量小,读磁盘页数少,速度更快。
现在是 SECOND INDEX SCAN(二级索引扫即 IDX_ADMIN_DEPT_LEVEL),直接通过创建的复合索引扫描。因为索引仅包含 department、access_level 及索引键,数据量更小,扫描更快。

-- 执行查询(索引未生效) EXPLAIN SELECT * FROM ETEST.EMPLOYEES WHERE SALARY > 8000;

image.png

收集统计信息

-- 收集EMPLOYEES表统计信息 DBMS_STATS.GATHER_TABLE_STATS( 'ETEST', 'EMPLOYEES', ESTIMATE_PERCENT => 100, -- 全量收集 METHOD_OPT => 'FOR ALL INDEXED COLUMNS SIZE AUTO' );

image.png

– 查看表统计信息

-- 表统计 DBMS_STATS.TABLE_STATS_SHOW('ETEST', 'EMPLOYEES'); 未走索引,是数据量小导致之一

image.png
-- 列统计
DBMS_STATS.COLUMN_STATS_SHOW('ETEST', 'EMPLOYEES', 'SALARY');
--LOW_VALUE:列的最小值,为 3004.28 ,即最低是 3004.28 。
HIGH_VALUE:列的最大值,为 9998.54 ,即最高接近 10000 。
NUM_NULLS:列的空值数量,这里是 0 ,说明 SALARY 列没有空值。
NUM_BUCKETS:直方图的桶数量,为 1000 ,表示统计信息用 1000 个桶来描述数据分布(因 NUM_DISTINCT 是 1000,可能是等频或等值直方图 )。
SAMPLE_SIZE:统计信息采样的行数,为 1000 ,说明是对全表(1000 行)做了统计,统计结果精准。
image.png
表只有 1000 行,即使过滤后有 200 行左右符合条件(估算 ),全表扫描 1000 行的成本(读 32 个数据块 ),比走索引(扫描索引块 + 回表取数据 )的成本更低。优化器基于这些统计信息,判断全表扫描更高效,所以没选索引。
– 索引统计

DBMS_STATS.INDEX_STATS_SHOW('ETEST', 'IDX_EMP_SALARY');

image.png
清理执行计划缓存

-- 查找问题SQL缓存项 SELECT cache_item, sqlstr FROM v$cachepln WHERE sqlstr LIKE 'SELECT * FROM ETEST.EMPLOYEES%';

image.png
– 清理缓存(cache_item=140183402600088)

CALL sp_clear_plan_cache(140183402600088);

image.png

2.hint常用优化管理

HINT 说明

1、SF_INJECT_HINT函数
提供无需修改 SQL 语句但依然能按照指定的 HINT 运行语句的相关功能,使用时有以下限制:

  1. INI 参数 ENABLE_INJECT_HINT 需设置为 1;
  2. SQL 只能是语法正确的增删改查语句;
  3. SQL 会经过系统格式化,格式化之后的 SQL 和指定的规则名称必须全局唯一;
  4. HINT 一指定,则全局生效;
  5. 系统检查 SQL 匹配时,必须是整条语句完全匹配,不能是语句中子查询匹配;
  6. 可通过 SYSINJECTHINT 视图查看已指定的 SQL 语句和对应的 HINT。

2、SQL语句指定HINT
需要在SQL语句中指定HINT,如果 HINT 的语法没有写对或指定的值不正确,DM 并不会报错,而是直接忽略 HINT 继续执行。
SF_INJECT_HINT(‘sql语句’, ‘参数名(参数值)’, ‘规则名’, null,TRUE,TRUE);

**对指定 SQL 撤回已增加的 HINT** ```SQL SF_DEINJECT_HINT('规则名'); 修改已指定 HINT 的规则属性 SF_ALTER_HINT('('规则名', 'STATUS', 'DISABLED');

3.使用 hint 注入优化

在不改动原 SQL 时,可使用ENABLE_RQ_TO_NONREF_SPL(3)参数优化,
相关说明如下:
•该参数用于将相关查询表达式转化为非相关查询表达式,使相关查询表达式的执行处理由之前的平坦化方式转化为一行处理。
•取值含义:
•0 表示不启用该优化;
•1 表示对查询项中出现的相关子查询表达式进行优化处理;
•2 表示对查询项和 WHERE 表达式中出现的相关子查询表达式进行优化处理;
•4 表示相关查询采用 SPL 方式去相关性后,可作为单表过滤条件。支持组合值,
•如 3 表示同时进行 1 和 2 的优化。

4.使用用法

开启该参数

SELECT SF_GET_PARA_VALUE(1, 'ENABLE_INJECT_HINT');

image.png
SP_SET_PARA_VALUE(1, ‘ENABLE_INJECT_HINT’, 1);
image.png
原始SQL执行

-- 原始SQL(不带优化参数) SELECT s.student_id, s.name, s.class_id, (SELECT AVG(grade) FROM student_courses sc WHERE sc.student_id = s.student_id) AS avg_grade, (SELECT COUNT(*) FROM student_courses sc WHERE sc.student_id = s.student_id AND grade >= 90) AS excellent_count, (SELECT c.course_name FROM courses c WHERE c.course_id = (SELECT sc.course_id FROM student_courses sc WHERE sc.student_id = s.student_id ORDER BY sc.grade DESC LIMIT 1) ) AS best_course FROM students s WHERE s.department = '计算机' AND s.class_id IN ('CLASS2', 'CLASS3', 'CLASS4'); 消耗208毫秒

image.png

带优化参数的SQL执行 -- 带优化参数的SQL SELECT /*+ ENABLE_RQ_TO_NONREF_SPL(3) */ s.student_id, s.name, s.class_id, (SELECT AVG(grade) FROM student_courses sc WHERE sc.student_id = s.student_id) AS avg_grade, (SELECT COUNT(*) FROM student_courses sc WHERE sc.student_id = s.student_id AND grade >= 90) AS excellent_count, (SELECT c.course_name FROM courses c WHERE c.course_id = (SELECT sc.course_id FROM student_courses sc WHERE sc.student_id = s.student_id ORDER BY sc.grade DESC LIMIT 1) ) AS best_course FROM students s WHERE s.department = '计算机' AND s.class_id IN ('CLASS2', 'CLASS3', 'CLASS4');

–消耗162毫秒
image.png

5.HINT 注入方式

对指定 SQL 增加 HINT 注入的命令:

-- 启用HINT注入功能 SP_SET_PARA_VALUE(1, 'ENABLE_INJECT_HINT', 1); -- 注入优化HINT SF_INJECT_HINT('SELECT s.student_id, s.name, s.class_id, (SELECT AVG(grade) FROM student_courses sc', 'ENABLE_RQ_TO_NONREF_SPL(3)', '学生成绩查询优化', null, TRUE, TRUE); -- 查询已注入的HINT SELECT * FROM SYSINJECTHINT WHERE NAME = '学生成绩查询优化'; --通过SF_INJECT_HINT函数注入的优化规则已生效

image.png

-- 执行带注入HINT的SQL(无需修改原SQL) SELECT s.student_id, s.name, s.class_id, (SELECT AVG(grade) FROM student_courses sc WHERE sc.student_id = s.student_id) AS avg_grade, (SELECT COUNT(*) FROM student_courses sc WHERE sc.student_id = s.student_id AND grade >= 90) AS excellent_count, (SELECT c.course_name FROM courses c WHERE c.course_id = (SELECT sc.course_id FROM student_courses sc WHERE sc.student_id = s.student_id ORDER BY sc.grade DESC LIMIT 1) ) AS best_course FROM students s WHERE s.department = '计算机' AND s.class_id IN ('CLASS2', 'CLASS3', 'CLASS4'); --消耗152毫秒

image.png
可通过视图查询:select * from SYSINJECTHINT;

6.优化后执行计划
--查看原始SQL执行计划 EXPLAIN SELECT s.student_id, s.name, s.class_id, (SELECT AVG(grade) FROM student_courses sc WHERE sc.student_id = s.student_id) AS avg_grade, (SELECT COUNT(*) FROM student_courses sc WHERE sc.student_id = s.student_id AND grade >= 90) AS excellent_count, (SELECT c.course_name FROM courses c WHERE c.course_id = (SELECT sc.course_id FROM student_courses sc WHERE sc.student_id = s.student_id ORDER BY sc.grade DESC LIMIT 1) ) AS best_course FROM students s WHERE s.department = '计算机' AND s.class_id IN ('CLASS2', 'CLASS3', 'CLASS4');

image.png

--查看优化后SQL执行计划 EXPLAIN SELECT /*+ ENABLE_RQ_TO_NONREF_SPL(3) */ s.student_id, s.name, s.class_id, (SELECT AVG(grade) FROM student_courses sc WHERE sc.student_id = s.student_id) AS avg_grade, (SELECT COUNT(*) FROM student_courses sc WHERE sc.student_id = s.student_id AND grade >= 90) AS excellent_count, (SELECT c.course_name FROM courses c WHERE c.course_id = (SELECT sc.course_id FROM student_courses sc WHERE sc.student_id = s.student_id ORDER BY sc.grade DESC LIMIT 1) ) AS best_course FROM students s WHERE s.department = '计算机' AND s.class_id IN ('CLASS2', 'CLASS3', 'CLASS4');

image.png
image.png

7.清理工作
-- 删除注入的HINT SF_DEINJECT_HINT('学生成绩查询优化'); -- 确认HINT已被删除 SELECT * FROM SYSINJECTHINT WHERE NAME = '学生成绩查询优化';

达梦社区地址https://eco.dameng.com

评论
后发表回复

作者

文章

阅读量

获赞

扫一扫
联系客服