达梦数据库-学习-10-SQL 注入 HINT 规则(固定执行计划)
目录
一、环境信息
二、简述
三、参数介绍
四、存过介绍
1、SF_INJECT_HINT
(1)声明
(2)存过说明
(3)注意
(4)参数含义
(5)返回值
2、SF_ALTER_HINT
(1)声明
(2)存过说明
(3)注意
(4)参数含义
(5)返回值
3、SF_DEINJECT_HINT
(1)声明
(2)存过说明
(3)注意
(4)参数含义
(5)返回值
五、视图介绍
1、SYSINJECTHINT
六、虚机实验
1、开启参数
2、测试SQL
3、注入HINT
4、查看视图
5、验证SQL
6、设置当前会话不生效
7、查看视图
8、测试SQL
9、会话级修改参数SQLTUNE_CATEGORY
10、验证SQL
11、删除注入HINT
12、验证是否删除
一、环境信息
名称 | 值 |
CPU | 12th Gen Intel(R) Core(TM) i7-12700H |
操作系统 | CentOS Linux release 7.9.2009 (Core) |
内存 | 2G |
逻辑核数 | 2 |
DM版本 | 1 DM Database Server 64 V8 2 DB Version: 0x7000c 3 03134284194-20240703-234060-20108 4 Msg Version: 12 5 Gsu level(5) cnt: 0 |
二、简述
在客户现场我们经常遇到生产环境慢SQL的问题,生产环境不可改应用(把等价改写和的路子堵死了),加索引计划中不走,指定HINT后计划变优,但不可改应用,所以这个方法也被毙掉了。SQL 注入 HINT 规则的优势就来了,可以在不修改SQL的情况下,注入HINT来影响执行计划。
三、参数介绍
参数名 | 默认值 | 级别 | 描述 |
ENABLE_INJECT_HINT | 0 | 动态会 话级 | 是否启用 SQL 指定 HINT 的功能。 0:不启用; 1:启用; |
SQLTUNE_CATEGORY | DEFAULT | 动态会话级 | 限制本会话中被允许使用的 SQL 配置(包括为 SQL 注入的 HINT 规则)的生效类别。 当 SQL 配置存在生效类别限制且和本会话的 SQLTUNE_CATEGORY 不一致时,该 SQL 配置在本会话不生效 |
四、存过介绍
1、SF_INJECT_HINT
(1)声明
VARCHAR
SF_INJECT_HINT (
sql_text text,
hint_text text,
name varchar(128),
description varchar(256),
validate boolean,
fuzzy boolean,
need_clear boolean
)
(2)存过说明
为
SQL
注入
HINT
规则。
(3)注意
SF_INJECT_HINT
方法创建的
HINT
规则无生效类别限制,如果需要为该 HINT
规则设置生效类别,可通过
SF_ALTER_HINT
过程修改实现。
(4)参数含义
参数名 | 含义 |
sql_text | 待注入 HINT 规则的 SQL 语句。 |
hint_text | 待注入的 HINT 规则,必须指定为非 NULL 值。 |
name | HINT 规则的名称,指定为 NULL 值时系统为其命名。 |
description | 对 HINT 规则的详细描述。 |
validate | HINT 规则是否生效。TRUE 是;FALSE 否。 |
fuzzy | 指定 SQL 的匹配规则为精准匹配或模糊匹配。 值为 TRUE 或 NULL时,为模糊匹配; 值为 FALSE 时,为精准匹配。 精准匹配时,待注入 HINT 规则的 SQL 语句 必 须 为 语 法 正 确 的 INSERT/DELETE/UPDATE/SELECT/MERGE INTO 语 句 ( 语 句 以EXPLAIN/EXPLAIN FOR 开头时,去掉 EXPLAIN/EXPLAIN FOR 后的语句必须完全正确),精准匹配要求 SQL 语句完全匹配,不支持 SQL 语句中的子查询匹配; 模糊匹配时,待注入 HINT规则的 SQL 语句应为非 NULL 值。 |
need_clear | 是否同步清空所有缓存的计划。 值为 TRUE 或 NULL 时,清空缓存的计划; 值为 FALSE 时,不清空缓存的计划,需要手动清除对应 SQL 的 计划,指定的 hint 才能生效。 |
(5)返回值
执行成功返回名称,执行失败报错误信息。
2、SF_ALTER_HINT
(1)声明
INT
SF_ALTER_HINT (
name varchar(128),
attribute_name varchar(12),
attribute_value varchar(256),
need_clear boolean
)
(2)存过说明
修改
HINT
规则的属性。
(3)注意
无。
(4)参数含义
参数名 | 含义 |
name | 要修改的规则名称,必须指定为非 NULL 值。 |
attribute_name | 要修改的属性名,必须指定为非 NULL 值。 支持的可修改的属性名和属性值包括: 属性名 NAME,属性值为修改后的规则名; 属性名 DESCRIPTION,属性值为修改后的规则描述; 属性名 STATUS,属性值为 ENABLED/DISABLED; 属性名 CATEGORY,属性值为修改后的 HINT 的生效类别(由于 SF_INJECT_HINT 方法仅能注入无类别限制的 HINT,若需要注入带生效类别的 HINT,则还需要再调用一次 SF_ALTER_HINT 更改其生效类别)。 |
attribute_value | 设置的属性值,必须指定为非 NULL 值。 |
need_clear | 是否同步清空所有缓存的计划。 值为 TRUE 或 NULL 时,清空缓存的计划; 值为 FALSE 时,不清空缓存的计划,需要手动清除对应 SQL 的计划,否则 SQL 仍使用老计划。 |
(5)返回值
执行成功返回
0
,执行失败返回错误码。
3、SF_DEINJECT_HINT
(1)声明
INT
SF_DEINJECT_HINT (
name varchar(128),
need_clear boolean
)
(2)存过说明
删除
SQL
中已注入的
HINT
规则。
(3)注意
无。
(4)参数含义
参数名 | 含义 |
name | 要删除的规则名称,必须指定为非 NULL 值。 |
need_clear | 是否同步清空所有缓存的计划。 值为 TRUE 或 NULL 时,清空缓存的计划; 值为 FALSE 时,不清空缓存的计划,需要手动清除对应 SQL 的计划,否则 SQL 仍使用老计划。 |
(5)返回值
执行成功返回
0
,执行失败返回错误码。
五、视图介绍
1、SYSINJECTHINT
SQL> DESC SYSINJECTHINT;
行号 NAME TYPE$ NULLABLE
---------- ----------- --------------- --------
1 NAME VARCHAR(128) N
2 DESCRIPTION VARCHAR(256) Y
3 VALIDATE VARCHAR(5) Y
4 SQL_TEXT TEXT N
5 HINT_TEXT TEXT N
6 CREATOR VARCHAR(128) Y
7 CRTDATE DATETIME(6) Y
8 INFO1 INTEGER Y
9 INFO2 VARBINARY(128) Y
10 INFO3 VARBINARY(1024) Y
10 rows got
已用时间: 13.896(毫秒). 执行号:1018.
字段名 | 描述 |
NAME | 规则名称 |
DESCRIPTION | 规则的详细描述 |
VALIDATE | 规则是否生效,取值 TRUE/FALSE |
SQL_TEXT | 规则中的 SQL 语句 |
HINT_TEXT | 为 SQL 语句注入的 HINT 规则内容 |
CREATOR | 规则创建人 |
CRTDATE | 规则创建时间 |
INFO1 | 是否为模糊匹配。1 是;0 否,精确匹配 |
INFO2 | HINT 规则的生效类别。可使用 BINTOCHAR函数将该字段转换为 VARCHAR 类型显示 |
INFO3 | 保留字段 |
六、虚机实验
1、开启参数
SQL> CALL SP_SET_PARA_VALUE(1,'ENABLE_INJECT_HINT',1);
DMSQL 过程已成功完成
已用时间: 12.612(毫秒). 执行号:2003.
SQL> SELECT * FROM V$DM_INI WHERE PARA_NAME = 'ENABLE_INJECT_HINT';
行号 PARA_NAME PARA_VALUE MIN_VALUE MAX_VALUE DEFAULT_VALUE MPP_CHK SESS_VALUE FILE_VALUE DESCRIPTION PARA_TYPE SYNC_FLAG
---------- ------------------ ---------- --------- --------- ------------- ------- ---------- ---------- ------------------ --------- ---------
SYNC_LEVEL
----------
1 ENABLE_INJECT_HINT 1 0 1 0 N 1 1 enable inject hint SESSION ALL_SYNC
CAN_SYNC
已用时间: 7.387(毫秒). 执行号:2004.
2、测试SQL
SQL> EXPLAIN SELECT * FROM ZXJ.TEST T1 JOIN ZXJ.TEST T2 ON T1.A = T2.A;
1 #NSET2: [4, 29405, 8]
2 #PRJT2: [4, 29405, 8]; exp_num(2), is_atom(FALSE)
3 #HASH2 INNER JOIN: [4, 29405, 8]; KEY_NUM(1); KEY(T1.A=T2.A) KEY_NULL_EQU(0)
4 #CSCN2: [1, 10000, 4]; INDEX33555476(TEST as T1); btr_scan(1)
5 #CSCN2: [1, 10000, 4]; INDEX33555476(TEST as T2); btr_scan(1)
已用时间: 0.829(毫秒). 执行号:0.
我们可以才看出,在没有干预的情况下,优化器选的是哈希内连接。
3、注入HINT
SQL> CALL
SF_INJECT_HINT (
'SELECT * FROM ZXJ.TEST T1 JOIN ZXJ.TEST T2 ON T1.A = T2.A;',
'USE_NL(T1,T2)',
NULL,
'',
TRUE,
FALSE,
TRUE
);2 3 4 5 6 7 8 9 10
DMSQL 过程已成功完成
已用时间: 19.472(毫秒). 执行号:2006.
4、查看视图
SQL> SELECT * FROM SYSINJECTHINT;
行号 NAME DESCRIPTION VALIDATE SQL_TEXT HINT_TEXT CREATOR
---------- ---------------------------- ----------- -------- ---------------------------------------------------------- ------------- -------
CRTDATE INFO1 INFO2 INFO3
-------------------------- ----------- ---------- ----------
1 INJECT_HINT_ad9ccfdb7ec1745f TRUE SELECT * FROM ZXJ.TEST T1 JOIN ZXJ.TEST T2 ON T1.A = T2.A; USE_NL(T1,T2) SYSDBA
2025-02-14 17:28:19.701426 0 NULL NULL
已用时间: 3.337(毫秒). 执行号:2007.
5、验证SQL
SQL> EXPLAIN SELECT * FROM ZXJ.TEST T1 JOIN ZXJ.TEST T2 ON T1.A = T2.A;
1 #NSET2: [17551877, 29405, 8]
2 #PRJT2: [17551877, 29405, 8]; exp_num(2), is_atom(FALSE)
3 #SLCT2: [17551877, 29405, 8]; T1.A = T2.A
4 #NEST LOOP INNER JOIN2: [17551877, 29405, 8]
5 #CSCN2: [1, 10000, 4]; INDEX33555476(TEST as T1); btr_scan(1)
6 #CSCN2: [1, 10000, 4]; INDEX33555476(TEST as T2); btr_scan(1)
已用时间: 0.809(毫秒). 执行号:0.
我们可以发现计划中两表的连接方式变为了嵌套循环连接,说明我们的SQL注入HINT配置成功。
6、设置当前会话不生效
CALL
SF_ALTER_HINT (
'INJECT_HINT_ad9ccfdb7ec1745f',
'CATEGORY',
'SUN',
TRUE
);
7、查看视图
SQL> SELECT NAME,DESCRIPTION,"VALIDATE",SQL_TEXT,HINT_TEXT,CREATOR,CRTDATE,INFO1,BINTOCHAR(INFO2) FROM SYSINJECTHINT;
行号 NAME DESCRIPTION VALIDATE SQL_TEXT HINT_TEXT CREATOR
---------- ---------------------------- ----------- -------- ---------------------------------------------------------- ------------- -------
CRTDATE INFO1 BINTOCHAR(INFO2)
-------------------------- ----------- ----------------
1 INJECT_HINT_ad9ccfdb7ec1745f TRUE SELECT * FROM ZXJ.TEST T1 JOIN ZXJ.TEST T2 ON T1.A = T2.A; USE_NL(T1,T2) SYSDBA
2025-02-14 17:28:19.701426 0 SUN
已用时间: 6.296(毫秒). 执行号:2010.
8、测试SQL
SQL> EXPLAIN SELECT * FROM ZXJ.TEST T1 JOIN ZXJ.TEST T2 ON T1.A = T2.A;
1 #NSET2: [4, 29405, 8]
2 #PRJT2: [4, 29405, 8]; exp_num(2), is_atom(FALSE)
3 #HASH2 INNER JOIN: [4, 29405, 8]; KEY_NUM(1); KEY(T1.A=T2.A) KEY_NULL_EQU(0)
4 #CSCN2: [1, 10000, 4]; INDEX33555476(TEST as T1); btr_scan(1)
5 #CSCN2: [1, 10000, 4]; INDEX33555476(TEST as T2); btr_scan(1)
已用时间: 0.868(毫秒). 执行号:0.
SQL> SELECT * FROM V$DM_INI WHERE PARA_NAME = 'SQLTUNE_CATEGORY';
行号 PARA_NAME PARA_VALUE MIN_VALUE MAX_VALUE DEFAULT_VALUE MPP_CHK SESS_VALUE FILE_VALUE
---------- ---------------- ---------- --------- --------- ------------- ------- ---------- ----------
DESCRIPTION PARA_TYPE SYNC_FLAG SYNC_LEVEL
------------------------------------------------------------ --------- --------- ----------
1 SQLTUNE_CATEGORY DEFAULT NULL NULL NULL N DEFAULT DEFAULT
The category of SQL profiles that take effect in the session SESSION ALL_SYNC CAN_SYNC
已用时间: 8.464(毫秒). 执行号:2011.
由于本会话的参数SQLTUNE_CATEGORY的值DEFAULT与设置的值SUN不一致,所以此SQL注入HINT不生效。
9、会话级修改参数SQLTUNE_CATEGORY
SQL> CALL SF_SET_SESSION_PARA_VALUE('SQLTUNE_CATEGORY','SUN');
DMSQL 过程已成功完成
已用时间: 2.563(毫秒). 执行号:2012.
SQL> SELECT * FROM V$DM_INI WHERE PARA_NAME = 'SQLTUNE_CATEGORY';
行号 PARA_NAME PARA_VALUE MIN_VALUE MAX_VALUE DEFAULT_VALUE MPP_CHK SESS_VALUE FILE_VALUE
---------- ---------------- ---------- --------- --------- ------------- ------- ---------- ----------
DESCRIPTION PARA_TYPE SYNC_FLAG SYNC_LEVEL
------------------------------------------------------------ --------- --------- ----------
1 SQLTUNE_CATEGORY DEFAULT NULL NULL NULL N SUN DEFAULT
The category of SQL profiles that take effect in the session SESSION ALL_SYNC CAN_SYNC
已用时间: 7.108(毫秒). 执行号:2013.
这次参数SQLTUNE_CATEGORY的会话值SUN与设置的值SUN不一致了。
10、验证SQL
SQL> EXPLAIN SELECT * FROM ZXJ.TEST T1 JOIN ZXJ.TEST T2 ON T1.A = T2.A;
1 #NSET2: [17551877, 29405, 8]
2 #PRJT2: [17551877, 29405, 8]; exp_num(2), is_atom(FALSE)
3 #SLCT2: [17551877, 29405, 8]; T1.A = T2.A
4 #NEST LOOP INNER JOIN2: [17551877, 29405, 8]
5 #CSCN2: [1, 10000, 4]; INDEX33555476(TEST as T1); btr_scan(1)
6 #CSCN2: [1, 10000, 4]; INDEX33555476(TEST as T2); btr_scan(1)
已用时间: 0.789(毫秒). 执行号:0.
又变回来了。
11、删除注入HINT
SQL> CALL
SF_DEINJECT_HINT (
'INJECT_HINT_ad9ccfdb7ec1745f',
TRUE
);2 3 4 5
DMSQL 过程已成功完成
已用时间: 5.053(毫秒). 执行号:2014.
12、验证是否删除
SQL> EXPLAIN SELECT * FROM ZXJ.TEST T1 JOIN ZXJ.TEST T2 ON T1.A = T2.A;
1 #NSET2: [4, 29405, 8]
2 #PRJT2: [4, 29405, 8]; exp_num(2), is_atom(FALSE)
3 #HASH2 INNER JOIN: [4, 29405, 8]; KEY_NUM(1); KEY(T1.A=T2.A) KEY_NULL_EQU(0)
4 #CSCN2: [1, 10000, 4]; INDEX33555476(TEST as T1); btr_scan(1)
5 #CSCN2: [1, 10000, 4]; INDEX33555476(TEST as T2); btr_scan(1)
已用时间: 0.812(毫秒). 执行号:0.
SQL> SELECT NAME,DESCRIPTION,"VALIDATE",SQL_TEXT,HINT_TEXT,CREATOR,CRTDATE,INFO1,BINTOCHAR(INFO2) FROM SYSINJECTHINT;
未选定行
已用时间: 1.033(毫秒). 执行号:2015.
我们可以看出计划变回最先的了,系统视图中也看不到了。