我对甲骨文非常缺乏经验。这里发生了什么事?
查询A:
SELECT COUNT(*)
FROM MUHSCHEMA.MUH_TABLE
WHERE MUH_DATE = TO_DATE(
TRIM(
'''' FROM SYS.DBMS_ASSERT.ENQUOTE_LITERAL('09/30/2020')),
'mm/dd/yyyy'
);查询B:
SELECT COUNT(*)
FROM MUHSCHEMA.MUH_TABLE
WHERE MUH_DATE = TO_DATE('09/30/2020', 'mm/dd/yyyy');查询A大约需要22分钟。查询B大约需要28秒。而且,似乎使用或不使用ENQUOTE_LITERAL的两个TO_DATE调用都会返回相同的内容。
为什么查询A花了这么长时间?
查询A计划:
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | Pstart| Pstop |
----------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 9 | 411K (2)| 00:00:17 | | |
| 1 | SORT AGGREGATE | | 1 | 9 | | | | |
| 2 | VIEW | A_TABLE | 71M| 610M| 411K (2)| 00:00:17 | | |
| 3 | UNION-ALL | | | | | | | |
| 4 | PARTITION RANGE ALL | | 28M| 214M| 42669 (15)| 00:00:02 | 1 |1048575|
| 5 | PARTITION LIST ALL | | 28M| 214M| 42669 (15)| 00:00:02 | 1 | 25 |
|* 6 | INDEX FAST FULL SCAN| A_TABLE. | 28M| 214M| 42669 (15)| 00:00:02 | 1 |1048575|
| 7 | PARTITION RANGE ALL | | 42M| 327M| 368K (1)| 00:00:15 | 1 |1048575|
| 8 | PARTITION LIST ALL | | 42M| 327M| 368K (1)| 00:00:15 | 1 | 25 |
|* 9 | INDEX RANGE SCAN | A_TABLE. | 42M| 327M| 368K (1)| 00:00:15 | 1 |1048575|
----------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
" 6 - filter(""MUH_DATE""=TO_DATE(TRIM('''' FROM ""DBMS_ASSERT"".""ENQUOTE_LITERAL""('09/30/2020')),'mm/dd/yy"
yy'))
" 9 - access(""MUH_DATE""=TO_DATE(TRIM('''' FROM ""DBMS_ASSERT"".""ENQUOTE_LITERAL""('09/30/2020')),'mm/dd/yy"
yy'))查询B计划:
----------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | Pstart| Pstop |
----------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 9 | 36612 (1)| 00:00:02 | | |
| 1 | SORT AGGREGATE | | 1 | 9 | | | | |
| 2 | VIEW | A_TABLE. | 28M| 241M| 36612 (1)| 00:00:02 | | |
| 3 | UNION-ALL | | | | | | | |
| 4 | PARTITION RANGE SINGLE| | 28M| 214M| 36608 (1)| 00:00:02 | 250 | 250 |
| 5 | PARTITION LIST ALL | | 28M| 214M| 36608 (1)| 00:00:02 | 1 | 25 |
|* 6 | INDEX FAST FULL SCAN| A_TABLE | 28M| 214M| 36608 (1)| 00:00:02 | 6226 | 6250 |
| 7 | PARTITION RANGE SINGLE| | 1 | 8 | 4 (0)| 00:00:01 | 93 | 93 |
| 8 | PARTITION LIST ALL | | 1 | 8 | 4 (0)| 00:00:01 | 1 | 25 |
|* 9 | INDEX RANGE SCAN | A_TABLE. | 1 | 8 | 4 (0)| 00:00:01 | 2301 | 2325 |
----------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
" 6 - filter(""MUH_DATE""=TO_DATE(' 2020-09-30 00:00:00', 'syyyy-mm-dd hh24:mi:ss'))"
" 9 - access(""MUH_DATE""=TO_DATE(' 2020-09-30 00:00:00', 'syyyy-mm-dd hh24:mi:ss'))"发布于 2021-04-22 03:09:22
值'09/30/2020‘来自web请求
那么,无论处理web请求的是什么,几乎肯定都会支持参数化查询和绑定变量。不要试图使用字符串连接构建查询,然后使用DBMS_ASSERT来阻止SQL注入,只需使用绑定变量即可。
匿名绑定变量通常具有?占位符(但您应该检查处理web请求的任何服务的语法):
SELECT COUNT(*)
FROM MUHSCHEMA.MUH_TABLE
WHERE MUH_DATE = TO_DATE( ?, 'mm/dd/yyyy');或命名的绑定变量通常以:为前缀,如下所示:
SELECT COUNT(*)
FROM MUHSCHEMA.MUH_TABLE
WHERE MUH_DATE = TO_DATE( :variable_name, 'mm/dd/yyyy');更好的是,如果您可以将字符串转换为处理web请求的日期,则可以将日期值传递给绑定变量,而不需要使用TO_DATE
SELECT COUNT(*)
FROM MUHSCHEMA.MUH_TABLE
WHERE MUH_DATE = :date_variable_name;,我们在讨论oracle如何将看似相似的两个查询转换成两个截然不同的实现。
如果要执行全表扫描,并尝试在每一行上使用DBMS_ASSERT.ENQUOTE_LITERAL,则重复执行此操作将花费大量时间。解决方案可能是使用索引,但更好的解决方案是根本不使用DBMS_ASSERT.ENQUOTE_LITERAL,并通过绑定变量将值作为DATE数据类型传递到查询中。
您在注释中引用的How to write SQL injection proof PL/SQL文档说明在第31页:
规则6:除非不能,否则请使用编译时固定的SQL语句文本。
绑定变量允许您使用编译时固定的SQL语句;无论变量的值是什么,语句都不需要更改,并且可以确保查询不会受到SQL注入的攻击。
https://stackoverflow.com/questions/67198180
复制相似问题