【问题标题】:Oracle Optimization: which execution plan is better?Oracle 优化:哪个执行计划更好?
【发布时间】: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


【解决方案1】:

1 Oracle 有很好的工具来提高查询性能,例如 DBMS_SQLTUNE https://docs.oracle.com/database/121/TGSQL/tgsql_sqltune.htm#TGSQL586 一开始你可以创建调优任务

declare
  l_task_name varchar2(4000);
begin
 l_task_name := DBMS_SQLTUNE.CREATE_TUNING_TASK(
      sql_text => q'!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)),'%')!'
, bind_list   => sql_binds( anydata.ConvertVarchar2('ABC'), 
            anydata.ConvertVarchar2('BCD'),
            anydata.ConvertVarchar2('CDE'),
            anydata.ConvertVarchar2('DEF'),
            anydata.ConvertVarchar2('EFG'))
, task_name   => 'TEST_TUNING_SQL_SO' 
, description => 'Task to tune a query from StackOverflow');
end;
/

你可以执行之后

begin
  DBMS_SQLTUNE.EXECUTE_TUNING_TASK (
   task_name => 'TEST_TUNING_SQL_SO');
end;
/

并检索报告并执行建议

select DBMS_SQLTUNE.REPORT_TUNING_TASK(
   task_name => 'TEST_TUNING_SQL_SO') from dual;

2 如何发布计划

您可以以文本格式(不是 HTML)生成它。并尝试仅添加包含谓词信息的计划表。如果不需要,您可以排除任何附加信息。

【讨论】:

  • (1) - thks,但我收到此错误:ORA-13616:当前用户尚未被授予 ADVISOR 权限。 (2) - SqlDeveloper 不生成文本计划。
  • (2) SQLPLUS EXPLAIN PLAN FOR SELECT * FROM dual;SELECT * FROM table(DBMS_XPLAN.DISPLAY); 之后的简单示例我认为它也适用于 SQL 开发人员
  • 你能收集查询表的_table_stats 吗?例如 `begin DBMS_STATS.GATHER_TABLE_STATS ('PRODDTA', 'F4211') ;结尾。并检查计划是否改变?
猜你喜欢
  • 2014-09-18
  • 1970-01-01
  • 2019-08-12
  • 2019-10-20
  • 1970-01-01
  • 1970-01-01
  • 2013-09-22
  • 2021-02-18
  • 2016-01-01
相关资源
最近更新 更多