【DB筆試面試258】在Oracle中,執行計劃里的access和filter有什麼區別(上)?

  • 2019 年 10 月 11 日
  • 筆記

題目如下所示:

在Oracle中,執行計劃里的access和filter有什麼區別?

答案如下所示:

如下所示:

Predicate Information (identified by operation id):  ---------------------------------------------------     4 - access("A"."EMPNO"="B"."MGR")         filter("A"."EMPNO"="B"."MGR")     5 - filter("B"."MGR" IS NOT NULL)  

一般而言,access表示這個謂詞條件的值將會影響數據的訪問路徑(表還是索引);filter表示謂詞條件的值不會影響數據的訪問路勁,只起到過濾的作用。NOT IN或MIN函數等容易產生filter操作。

對於filter而言如果只有一個子節點,那麼就是簡單過濾操作(獨立操作)。如果有兩個或更多子節點,那麼就是類似Nested Loops操作,只不過與Nested Loops差別在於,filter內部會構建HASH表,對於重複匹配的,不會再次進行循環查找,而是利用已有結果,提高效率。但是一旦重複匹配的較少,循環次數多,那麼,filter操作將是嚴重影響性能的操作,可能會導致目標SQL幾天都執行不完。

下面看看各種情況下的FILTER操作:

(一)單子節點:

LHR@orclasm > set autot on  LHR@orclasm > SELECT T.JOB, COUNT(1) FROM SCOTT.EMP T GROUP BY T.JOB  HAVING COUNT(1)>3;    JOB         COUNT(1)  --------- ----------  CLERK              4  SALESMAN           4      Execution Plan  ----------------------------------------------------------  Plan hash value: 2138686577    ----------------------------------------------------------------------------  | Id  | Operation           | Name | Rows  | Bytes | Cost (%CPU)| Time     |  ----------------------------------------------------------------------------  |   0 | SELECT STATEMENT    |      |     1 |     8 |     4  (25)| 00:00:01 |  |*  1 |  FILTER             |      |       |       |            |          |  |   2 |   HASH GROUP BY     |      |     1 |     8 |     4  (25)| 00:00:01 |  |   3 |    TABLE ACCESS FULL| EMP  |    14 |   112 |     3   (0)| 00:00:01 |  ----------------------------------------------------------------------------    Predicate Information (identified by operation id):  ---------------------------------------------------       1 - filter(COUNT(*)>3)      Statistics  ----------------------------------------------------------           25  recursive calls            4  db block gets            6  consistent gets            0  physical reads         1544  redo size          660  bytes sent via SQL*Net to client          519  bytes received via SQL*Net from client            2  SQL*Net roundtrips to/from client            0  sorts (memory)            0  sorts (disk)            2  rows processed  

很顯然ID1的filter操作只有一個子節點ID2,在這種情況下的filter操作也就是單純的過濾操作。

(二)多子節點:

filter多子節點往往就是性能殺手,主要出現在子查詢無法UNNEST查詢轉換,經常遇到的情況就是NOT IN子查詢、子查詢和OR連用、複雜子查詢等情況。

DROP TABLE T_20170703_LHR_01 PURGE;  DROP TABLE T_20170703_LHR_02 PURGE;  DROP TABLE T_20170703_LHR_03 PURGE;  CREATE TABLE T_20170703_LHR_01 AS SELECT OBJECT_ID,OBJECT_NAME,OBJECT_TYPE FROM DBA_OBJECTS;  CREATE TABLE T_20170703_LHR_02 AS SELECT OBJECT_ID,OBJECT_NAME FROM USER_OBJECTS;  CREATE TABLE T_20170703_LHR_03 AS SELECT OBJECT_ID,OBJECT_NAME FROM USER_OBJECTS WHERE ROWNUM <=1000;  CREATE INDEX IND_T1_OBJ_ID_1 ON T_20170703_LHR_01(OBJECT_ID);  CREATE INDEX IND_T2_OBJ_ID_1 ON T_20170703_LHR_02(OBJECT_ID);  CREATE INDEX IND_T3_OBJ_ID_1 ON T_20170703_LHR_03(OBJECT_ID);  EXEC DBMS_STATS.GATHER_TABLE_STATS(USER,'t_20170703_LHR_01');  EXEC DBMS_STATS.GATHER_TABLE_STATS(USER,'t_20170703_LHR_02');  EXEC DBMS_STATS.GATHER_TABLE_STATS(USER,'t_20170703_LHR_03');    ALTER SESSION SET STATISTICS_LEVEL=ALL;  SELECT COUNT(1)    FROM T_20170703_LHR_01   T1   WHERE T1.OBJECT_TYPE = 'TABLE'      OR EXISTS (SELECT 1 FROM T_20170703_LHR_02 T2 WHERE T1.OBJECT_ID = T2.OBJECT_ID)      OR EXISTS (SELECT 1 FROM T_20170703_LHR_03 T3 WHERE T1.OBJECT_ID = T3.OBJECT_ID);  SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(NULL,NULL,'allstats last'));    SELECT COUNT(1)    FROM (SELECT T1.*            FROM T_20170703_LHR_01 T1           WHERE T1.OBJECT_TYPE = 'TABLE'          UNION ALL (SELECT T1.*                      FROM T_20170703_LHR_01 T1, T_20170703_LHR_02 T2                     WHERE T1.OBJECT_ID = T2.OBJECT_ID                       AND T1.OBJECT_TYPE <> 'TABLE'                    UNION                    SELECT T1.*                      FROM T_20170703_LHR_01 T1, T_20170703_LHR_03 T3                     WHERE T1.OBJECT_ID = T3.OBJECT_ID                       AND T1.OBJECT_TYPE <> 'TABLE'));  SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(NULL,NULL,'allstats last'));      WITH TMP_T1 AS   (SELECT T1.* FROM T_20170703_LHR_01 T1)  SELECT COUNT(1)    FROM (SELECT T1.*            FROM TMP_T1 T1           WHERE T1.OBJECT_TYPE = 'TABLE'          UNION ALL (SELECT T1.*                      FROM TMP_T1 T1, T_20170703_LHR_02 T2                     WHERE T1.OBJECT_ID = T2.OBJECT_ID                       AND T1.OBJECT_TYPE <> 'TABLE'                    UNION                    SELECT T1.*                      FROM TMP_T1 T1, T_20170703_LHR_03 T3                     WHERE T1.OBJECT_ID = T3.OBJECT_ID                       AND T1.OBJECT_TYPE <> 'TABLE'));  SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(NULL,NULL,'allstats last'));  

具體執行計劃:

LHR@orclasm > ALTER SESSION SET STATISTICS_LEVEL=ALL;    Session altered.    LHR@orclasm > SELECT COUNT(1)    2    FROM T_20170703_LHR_01   T1    3   WHERE T1.OBJECT_TYPE = 'TABLE'    4      OR EXISTS (SELECT 1 FROM T_20170703_LHR_02 T2 WHERE T1.OBJECT_ID = T2.OBJECT_ID)    5      OR EXISTS (SELECT 1 FROM T_20170703_LHR_03 T3 WHERE T1.OBJECT_ID = T3.OBJECT_ID);      COUNT(1)  ----------        5060    LHR@orclasm > SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(NULL,NULL,'allstats last'));    PLAN_TABLE_OUTPUT  ------------------------------------------------------------------------------------  SQL_ID  5894cbw5v4mpj, child number 0  -------------------------------------  SELECT COUNT(1)   FROM T_20170703_LHR_01   T1  WHERE T1.OBJECT_TYPE =  'TABLE'     OR EXISTS (SELECT 1 FROM T_20170703_LHR_02 T2 WHERE  T1.OBJECT_ID = T2.OBJECT_ID)     OR EXISTS (SELECT 1 FROM  T_20170703_LHR_03 T3 WHERE T1.OBJECT_ID = T3.OBJECT_ID)    Plan hash value: 1566256780    ---------------------------------------------------------------------------------------------------  | Id  | Operation           | Name              | Starts | E-Rows | A-Rows |   A-Time   | Buffers |  ---------------------------------------------------------------------------------------------------  |   0 | SELECT STATEMENT    |                   |      1 |        |      1 |00:00:00.17 |     149K|  |   1 |  SORT AGGREGATE     |                   |      1 |      1 |      1 |00:00:00.17 |     149K|  |*  2 |   FILTER            |                   |      1 |        |   5060 |00:00:00.17 |     149K|  |   3 |    TABLE ACCESS FULL| T_20170703_LHR_01 |      1 |  78271 |  78271 |00:00:00.01 |     469 |  |*  4 |    INDEX RANGE SCAN | IND_T2_OBJ_ID_1   |  74941 |      1 |   1741 |00:00:00.05 |   75356 |  |*  5 |    INDEX RANGE SCAN | IND_T3_OBJ_ID_1   |  73200 |      1 |      0 |00:00:00.05 |   73308 |  ---------------------------------------------------------------------------------------------------    Predicate Information (identified by operation id):  ---------------------------------------------------       2 - filter(("T1"."OBJECT_TYPE"='TABLE' OR  IS NOT NULL OR  IS NOT NULL))     4 - access("T2"."OBJECT_ID"=:B1)     5 - access("T3"."OBJECT_ID"=:B1)      27 rows selected.    LHR@orclasm >  LHR@orclasm >  LHR@orclasm > SELECT COUNT(1)    2    FROM (SELECT T1.*    3            FROM T_20170703_LHR_01 T1    4           WHERE T1.OBJECT_TYPE = 'TABLE'    5          UNION ALL (SELECT T1.*    6                      FROM T_20170703_LHR_01 T1, T_20170703_LHR_02 T2    7                     WHERE T1.OBJECT_ID = T2.OBJECT_ID    8                       AND T1.OBJECT_TYPE <> 'TABLE'    9                    UNION   10                    SELECT T1.*   11                      FROM T_20170703_LHR_01 T1, T_20170703_LHR_03 T3   12                     WHERE T1.OBJECT_ID = T3.OBJECT_ID   13                       AND T1.OBJECT_TYPE <> 'TABLE'));      COUNT(1)  ----------        5060    LHR@orclasm > SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(NULL,NULL,'allstats last'));    PLAN_TABLE_OUTPUT  -----------------------------------------------------------------------------------  SQL_ID  5n0xpnt0gzb0d, child number 0  -------------------------------------  SELECT COUNT(1)   FROM (SELECT T1.*           FROM T_20170703_LHR_01 T1           WHERE T1.OBJECT_TYPE = 'TABLE'         UNION ALL (SELECT T1.*                     FROM T_20170703_LHR_01 T1, T_20170703_LHR_02 T2                WHERE T1.OBJECT_ID = T2.OBJECT_ID  AND T1.OBJECT_TYPE <> 'TABLE'                   UNION  SELECT T1.*                     FROM T_20170703_LHR_01 T1,  T_20170703_LHR_03 T3                    WHERE T1.OBJECT_ID =  T3.OBJECT_ID                      AND T1.OBJECT_TYPE <> 'TABLE'))    Plan hash value: 3651740877    -------------------------------------------------------------------------------------------------------------------------------------  | Id  | Operation                  | Name              | Starts | E-Rows | A-Rows |   A-Time   | Buffers |  OMem |  1Mem | Used-Mem |  -------------------------------------------------------------------------------------------------------------------------------------  |   0 | SELECT STATEMENT           |                   |      1 |        |      1 |00:00:00.05 |    1423 |       |       |          |  |   1 |  SORT AGGREGATE            |                   |      1 |      1 |      1 |00:00:00.05 |    1423 |       |       |          |  |   2 |   VIEW                     |                   |      1 |   4641 |   5060 |00:00:00.05 |    1423 |       |       |          |  |   3 |    UNION-ALL               |                   |      1 |        |   5060 |00:00:00.05 |    1423 |       |       |          |  |*  4 |     TABLE ACCESS FULL      | T_20170703_LHR_01 |      1 |   1631 |   3319 |00:00:00.01 |     469 |       |       |          |  |   5 |     SORT UNIQUE            |                   |      1 |   4641 |   1741 |00:00:00.05 |     954 |   178K|   178K|  158K (0)|  |   6 |      UNION-ALL             |                   |      1 |        |   2634 |00:00:00.05 |     954 |       |       |          |  |*  7 |       HASH JOIN            |                   |      1 |   2010 |   1741 |00:00:00.03 |     479 |  1452K|  1452K| 1667K (0)|  |   8 |        INDEX FAST FULL SCAN| IND_T2_OBJ_ID_1   |      1 |   2012 |   2010 |00:00:00.01 |      10 |       |       |          |  |*  9 |        TABLE ACCESS FULL   | T_20170703_LHR_01 |      1 |  76640 |  74952 |00:00:00.01 |     469 |       |       |          |  |* 10 |       HASH JOIN            |                   |      1 |   1000 |    893 |00:00:00.02 |     475 |  1452K|  1452K| 1571K (0)|  |  11 |        INDEX FAST FULL SCAN| IND_T3_OBJ_ID_1   |      1 |   1000 |   1000 |00:00:00.01 |       6 |       |       |          |  |* 12 |        TABLE ACCESS FULL   | T_20170703_LHR_01 |      1 |  76640 |  74952 |00:00:00.01 |     469 |       |       |          |  -------------------------------------------------------------------------------------------------------------------------------------    Predicate Information (identified by operation id):  ---------------------------------------------------       4 - filter("T1"."OBJECT_TYPE"='TABLE')     7 - access("T1"."OBJECT_ID"="T2"."OBJECT_ID")     9 - filter("T1"."OBJECT_TYPE"<>'TABLE')    10 - access("T1"."OBJECT_ID"="T3"."OBJECT_ID")    12 - filter("T1"."OBJECT_TYPE"<>'TABLE')      40 rows selected.  

DB筆試面試歷史連接

http://mp.weixin.qq.com/s/Vm5PqNcDcITkOr9cQg6T7w

About Me:小麥苗

● 本文作者:小麥苗,只專註於數據庫的技術,更注重技術的運用

● 作者博客地址:http://blog.itpub.net/26736162/abstract/1/

● 本系列題目來源於作者的學習筆記,部分整理自網絡,若有侵權或不當之處還請諒解

● 版權所有,歡迎分享本文,轉載請保留出處

● QQ:646634621 QQ群:230161599

● 題目解答若有不當之處,還望各位朋友批評指正,共同進步