【发布时间】:2017-02-18 21:04:30
【问题描述】:
我必须改进这个查询:
SELECT sub.SDDOCO
FROM(
SELECT SDSHAN, SDDOCO, SDMCU, SDLITM, SDIR03, SDVR01
FROM PRODDTA.F4211
UNION ALL
SELECT SDSHAN, SDDOCO, SDMCU, SDLITM, SDIR03, SDVR01
FROM PRODDTA.F42119
)sub
INNER JOIN PRODDTA.F0101 tab
ON sub.SDSHAN = tab.ABAN8
WHERE
sub.SDMCU LIKE CONCAT(CONCAT('%',nvl(:pMCU,SDMCU)),'%')
AND sub.SDLITM LIKE CONCAT(CONCAT('%',nvl(:pLITM,SDLITM)),'%')
AND sub.SDIR03 LIKE CONCAT(CONCAT('%',nvl(:pIR03,SDIR03)),'%')
AND tab.ABALKY LIKE CONCAT(CONCAT('%',nvl(:pALKY,ABALKY)),'%')
AND sub.SDVR01 LIKE CONCAT(CONCAT('%',nvl(:pVR01,SDVR01)),'%')
我以这种方式修改了 WHERE 条件:
((:pMCU IS NOT NULL AND sub.SDMCU LIKE '%' || :pMCU || '%') OR :pMCU IS NULL)
AND ((:pLITM IS NOT NULL AND sub.SDLITM LIKE '%' || :pLITM || '%') OR :pLITM IS NULL)
AND ((:pIR03 IS NOT NULL AND sub.SDIR03 LIKE '%' || :pIR03 || '%') OR :pIR03 IS NULL)
AND ((:pVR01 IS NOT NULL AND sub.SDVR01 LIKE '%' || :pVR01 || '%') OR :pVR01 IS NULL)
AND ((:pALKY IS NOT NULL AND tab.ABALKY LIKE '%' || :pALKY || '%') OR :pALKY IS NULL)
在this link,您可以阅读这两个查询的执行计划。 哪一个更好? 有什么改进查询的建议吗? 我需要有结果的所有记录
编辑: 其中“F4211”表有 71,758 条记录,F42119 有 4,606,154 条记录
EDIT:F0101 表有 634,187 条记录。 当所有参数设置为 NULL 时,结果是在不合理的时间(几分钟)内记录了 4,677,925 条记录。 没有 where 子句的查询在 58 秒内需要 4,677,925 条记录
编辑: 插入代码片段我超过了最大字符数:( 对发布执行计划有何建议?
编辑: 这是执行计划:
"PLAN_TABLE_OUTPUT"
"Plan hash value: 3925457500"
" "
"-----------------------------------------------------------------------------------------------------------"
"| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |"
"-----------------------------------------------------------------------------------------------------------"
"| 0 | SELECT STATEMENT | | 2 | 1224 | 614K (1)| 00:00:24 |"
"| 1 | NESTED LOOPS | | 2 | 1224 | 614K (1)| 00:00:24 |"
"| 2 | VIEW | index$_join$_004 | 31721 | 1455K| 11379 (1)| 00:00:01 |"
"|* 3 | HASH JOIN | | | | | |"
"| 4 | INDEX FAST FULL SCAN | F0101_0 | 31721 | 1455K| 2414 (1)| 00:00:01 |"
"|* 5 | INDEX FAST FULL SCAN | F0101_3 | 31721 | 1455K| 8390 (1)| 00:00:01 |"
"| 6 | VIEW | | 1 | 565 | 19 (0)| 00:00:01 |"
"| 7 | UNION ALL PUSHED PREDICATE | | | | | |"
"|* 8 | TABLE ACCESS BY INDEX ROWID BATCHED| F4211 | 1 | 417 | 9 (0)| 00:00:01 |"
"|* 9 | INDEX RANGE SCAN | F4211_4 | 6 | | 3 (0)| 00:00:01 |"
"|* 10 | TABLE ACCESS BY INDEX ROWID BATCHED| F42119 | 1 | 422 | 10 (0)| 00:00:01 |"
"|* 11 | INDEX RANGE SCAN | F42119_9 | 10 | | 3 (0)| 00:00:01 |"
"-----------------------------------------------------------------------------------------------------------"
" "
"Predicate Information (identified by operation id):"
"---------------------------------------------------"
" "
" 3 - access(ROWID=ROWID)"
" 5 - filter(""GGG"".""ABALKY"" LIKE U'%'||NVL(:PALKY,""GGG"".""ABALKY"")||U'%')"
" 8 - filter(""SDMCU"" LIKE U'%'||NVL(:PMCU,""SDMCU"")||U'%' AND ""SDLITM"" LIKE "
" U'%'||NVL(:PLITM,""SDLITM"")||U'%' AND ""SDIR03"" LIKE U'%'||NVL(:PIR03,""SDIR03"")||U'%' AND ""SDVR01"" "
" LIKE U'%'||NVL(:PVR01,""SDVR01"")||U'%')"
" 9 - access(""SDSHAN""=""GGG"".""ABAN8"")"
" 10 - filter(""SDMCU"" LIKE U'%'||NVL(:PMCU,""SDMCU"")||U'%' AND ""SDLITM"" LIKE "
" U'%'||NVL(:PLITM,""SDLITM"")||U'%' AND ""SDIR03"" LIKE U'%'||NVL(:PIR03,""SDIR03"")||U'%' AND ""SDVR01"" "
" LIKE U'%'||NVL(:PVR01,""SDVR01"")||U'%')"
" 11 - access(""SDSHAN""=""GGG"".""ABAN8"")"
【问题讨论】:
-
(1) 您可能无法轻松改进此查询。 (2) 您应该限定所有列名,以便我们知道它们的来源。
-
@GordonLinoff thx,我已经对列进行了限定
-
表格有多少行?您是否需要同时使用所有行(ALL ROWS / FIRST ROWS)?
-
现在查询运行了多长时间?结果集有多少行?
-
尽可能避免在
like条件中使用'%'。然后,Opromizer 可以使用可能的索引。没有更多的事情要做。如果您需要在文本中按特定词进行选择,请使用全文索引。
标签: oracle plsql query-optimization sql-execution-plan nvl