注册
SF_INJECT_HINT——达梦数据库中强制优化器使用指定执行策略
专栏/技术分享/ 文章详情 /

SF_INJECT_HINT——达梦数据库中强制优化器使用指定执行策略

LyC_Dd 2025/09/19 472 1 0
摘要

SF_INJECT_HINT——达梦数据库中强制优化器使用指定执行策略

概述

本文介绍了在达梦数据库中使用 SF_INJECT_HINT 为 SQL 语句 注入 HINT 规则,并提供了简单的实践例子。

背景

在达梦数据库中,SQL 注入 HINT 规则可以让我们在不修改原始 SQL 的情况下,强制优化器使用指定的执行策略。在实际生产环境中,这对于解决一些特殊问题非常有用。在索引失效、连接顺序不当等场景下,也可以通过注入 HINT 指定索引或连接方式来快速解决性能瓶颈问题。

HINT是什么

HINT(优化器提示)是一种嵌入在 SQL 语句中的指令,用于告诉数据库优化器按照指定的方式生成执行计划。通常,HINT 可以指定访问路径(如使用哪个索引)、连接顺序、并行度、访问策略等。在达梦数据库中,我们可以通过 SF_INJECT_HINT 实现无需改 SQL 源码而向指定查询注入这类 HINT,使该 SQL 语句按照注入的执行策略运行。

HINT的优

  • 无需修改 SQL 语句:使用注入 HINT 规则可以在不改动应用程序或存储过程源码的前提下,改变查询的执行计划。这对于无法轻易重写或部署 SQL 的场景十分关键,如业务系统中存在慢 SQL 而又不能立即上线修改时。

  • 强力控制执行计划:HINT 可用于指定索引、连接类型、排序方式等。例如,通过注入 INDEX(TEST,IDX_TEST_ID) HINT,即可让优化器强制使用 IDX_TEST_ID 索引扫描,从而显著提升查询性能。再比如上文提到的,将 SORT_FLAG(0) 注入到问题 SQL 中,就可以避免全局排序区的不足。

  • 全局生效,可灵活启用/禁用:注入的 HINT 规则一经创建,就全局有效,对后续所有匹配的会话均生效。且通过 SYSINJECTHINT 视图可以查看所有已注入规则,通过 SF_ALTER_HINT 可以修改规则属性,SF_DEINJECT_HINT 可随时删除规则,使管理更灵活。

💡 提示

语句匹配一个hint之后,后续再重新打hint都不生效,不管是否精准匹配,一个sql只能对应匹配一个规则

HINT的劣

  • 执行计划依赖提示:过度依赖 HINT 会导致查询执行计划僵化,失去了成本优化器自动调整的优势。若数据量、统计信息或表结构发生较大变化,原有的 HINT 可能不再合适,需要人工修改甚至去掉。

  • 维护成本高:如果 HINT 写在代码中,那么数据变化或业务变更后往往需要再次改代码,维护成本大。使用注入 HINT 虽然不用改源码,但也需要定期检查和清理不再需要的规则,以免规则过多造成混乱。

  • 全局影响需谨慎:注入 HINT 是全局生效的,如果规则设置不当可能影响其他 SQL。比如精确匹配(exact)和模糊匹配(fuzzy)规则同时存在时,会优先使用精确匹配,且在同一分类下每条 SQL 只能有一个精确匹配规则,否则会报错。因此在注入时必须保证 SQL 文本完全匹配并全局唯一,否则规则可能不生效。

快速上手

开启注入功能

DM.INI 参数 ENABLE_INJECT_HINT 默认为 0,也就是默认不启用注入功能,我们可以通过达梦数据库将其设置为 1,长期启用INJECT_HINT功能。

20250908173833imagepng

修改参数后重启数据库生效

我们也可以设置会话参数开启 HINT 注入功能

sp_set_para_value(1, 'ENABLE_INJECT_HINT', 1);

参数 ENABLE_INJECT_HINT=1 表示启用 HINT 注入功能。

搭建测试环境

在达梦8中搭建一个员工信息表 employee_info ,并使用sqlark生成10w条数据(可选)

CREATE TABLE employee_info ( emp_id INT, emp_name VARCHAR(100), dept VARCHAR(50), salary DECIMAL(10,2) ); -- 创建员工信息表

表内容如下图

20250908231038imagepng

创建索引并收集统计信息

CREATE INDEX idx_emp_id ON employee_info(emp_id); --建立索引 stat 100 on employee_info(emp_id); --收集统计信息

查看默认执行计划

在注入 HINT 前,我们查看默认的执行计划

explain SELECT * FROM employee_info WHERE emp_id > 1;

20250908231248imagepng

可以看到默认情况下会进行全表扫描(未使用索引)。

通过 SF_INJECT_HINT 为 SQL 注入 HINT 规则(强制使用索引)

💡 提示
SF_INJECT_HINT拥有多种定义语法,使用不同的参数会匹配不同的定义,这里我们采用定义 2,详细参考:《DM8_SQL语言使用手册》16. 为 SQL 注入 HINT 规则

SF_INJECT_HINT( 'SELECT * FROM employee_info WHERE emp_id > 1;', --sql_text text 'INDEX(EMPLOYEE_INFO,IDX_EMP_ID)', --hint_text text 'INJECT_EMP_INDEX', --name varchar(128) '强制 employee_info 查询使用 emp_id 索引以优化性能', --description varchar(256) TRUE, --validate boolean TRUE --fuzzy boolean );

参数说明

sql_text:待注入 HINT 规则的 SQL 语句。
hint_text:待注入的 HINT 规则,必须指定为非 NULL 值。
name:HINT 规则的名称,指定为 NULL 值时系统为其命名。
description:对 HINT 规则的详细描述。
validate:HINT 规则是否生效。TRUE 是;FALSE 否。
fuzzy:指定 SQL 的匹配规则为精准匹配或模糊匹配,该参数值不能为 NULL。该参数类型为 BOOLEAN 时,使用定义
2 或定义 3 的语法,值为 TRUE 时,为模糊匹配;值为 FALSE 时,为精准匹配。

此处缺省参数

need_clear:是否同步清空所有缓存的计划,该参数值不能为 NULL。缺省时默认不清空缓存计划。

验证效果

再次查看执行计划

explain SELECT * FROM employee_info WHERE emp_id > 1;

20250908231355imagepng

此时应看到使用了索引扫描,在部分场景下查询语句速度将提升。

我们还可以通过 SYSINJECTHINT 视图查看 SQL 语句及其注入的 HINT 规则信息。

select * from SYSINJECTHINT;

20250908231618imagepng

使用 SF_ALTER_HINT 修改指定 HINT 规则的属性

让指定的 HINT 规则失效

SF_ALTER_HINT('INJECT_NAME', 'STATUS', 'DISABLED');

修改规则名,且不清空缓存的计划

SF_ALTER_HINT('INJECT_NAME', 'NAME', 'INJECT_NAME_NEW', FALSE);

使用 SF_DEINJECT_HINT 删除 SQL 的 HINT 规则。

为 SQL 删除已注入的 HINT 规则

SF_DEINJECT_HINT('INJECT_NAME');

为 SQL 删除已注入的 HINT 规则,且不清空缓存的计划:

SF_DEINJECT_HINT('INJECT_NAME', FALSE);

小结

注入 HINT 规则能灵活应对性能突发问题,但也需要谨慎运用。最佳实践是在充分评估数据分布和查询特性的基础上使用,定期审视和清理规则,并结合统计信息收集、物理结构优化等手段共同提升数据库性能。

参考阅读

SQL 调优 23.6 使用优化器提示 | 达梦技术文档

inject的用法 | 和优化器做朋友 | 达梦技术社区

评论
后发表回复

作者

文章

阅读量

获赞

扫一扫
联系客服