1

我在执行以下查询 ( Q1) 时遇到性能问题:

select
    z_out.*,
    a_out.id
from orders a_out, test z_out
where a_out.id=z_out.id and a_out.created>trunc(sysdate) and rownum<10

orders包含数百万行;orders.id是主键并被orders.craeted索引。

观点是:

create or replace view test as 
select/*+qb_name(q_outer)*/
    id,
    min(value) keep (dense_rank first order by id) as value
from (
    select/*+qb_name(q_inner)*/
        id, 
        case
            when substr(id, -1)<'5' 
                --and exists(select 1 from dual@db2)
                then 'YYY'
        end as attr_1
    from orders a1
) a2, small_table b2
where b2.attr_1 in (nvl(a2.attr_1, '#'), '*')
group by id

其中small_table b2包含大约 200 条记录(所有列都是varchar2)。

ExecutingQ1有很好的性能和以下执行计划:

Plan hash value: 2906430222                                                                                                  

-----------------------------------------------------------------------------------------------------------------------------
| Id  | Operation                             | Name                | Rows  | Bytes | Cost (%CPU)| Time     | Pstart| Pstop |
-----------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                      |                     |     1 |   274 |    64   (0)| 00:00:01 |       |       |
|*  1 |  COUNT STOPKEY                        |                     |       |       |            |          |       |       |
|   2 |   NESTED LOOPS                        |                     |     1 |   274 |    64   (0)| 00:00:01 |       |       |
|   3 |    PARTITION LIST ALL                 |                     |     1 |    22 |    59   (0)| 00:00:01 |     1 |     2 |
|   4 |     PARTITION RANGE ALL               |                     |     1 |    22 |    59   (0)| 00:00:01 |     1 |  LAST |
|   5 |      TABLE ACCESS BY LOCAL INDEX ROWID| ORDERS              |     1 |    22 |    59   (0)| 00:00:01 |     1 |    29 |
|*  6 |       INDEX RANGE SCAN                | IDX_ORDERS_CREATED  |     1 |       |    57   (0)| 00:00:01 |     1 |    29 |
|   7 |    VIEW PUSHED PREDICATE              | TEST                |     1 |   252 |     5   (0)| 00:00:01 |       |       |
|*  8 |     FILTER                            |                     |       |       |            |          |       |       |
|   9 |      SORT AGGREGATE                   |                     |     1 |    55 |            |          |       |       |
|  10 |       NESTED LOOPS                    |                     |   259 | 14245 |     5   (0)| 00:00:01 |       |       |
|* 11 |        INDEX UNIQUE SCAN              | PK_ID               |     1 |    14 |     2   (0)| 00:00:01 |       |       |
|* 12 |        INDEX STORAGE FAST FULL SCAN   | IDX_MN_AN_AD_ALL    |   259 | 10619 |     3   (0)| 00:00:01 |       |       |
-----------------------------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):                                                                          
---------------------------------------------------                                                                          

   1 - filter(ROWNUM<10)                                                                                                     
   6 - access("A_OUT"."CREATED">TRUNC(SYSDATE@!))                                                                     
   8 - filter(COUNT(*)>0)                                                                                                    
  11 - access("ID"="A_OUT"."ID")                                                                                       
  12 - storage("B2"."ATTR_1"=NVL(CASE  WHEN SUBSTR("ID",(-1))<'5' THEN 'YYY' END ,'#') OR "B2"."ATTR_1"='*')              
       filter("B2"."ATTR_1"=NVL(CASE  WHEN SUBSTR("ID",(-1))<'5' THEN 'YYY' END ,'#') OR "B2"."ATTR_1"='*')               

Q1--and exists(select 1 from dual@db2)取消注释视图中的行时会发生性能问题。新的执行计划是:

Plan hash value: 3271081243                                                                                                                   

----------------------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation                              | Name                | Rows  | Bytes | Cost (%CPU)| Time     | Pstart| Pstop | Inst   |IN-OUT|
----------------------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                       |                     |     1 |   288 |  5273K  (1)| 00:03:27 |       |       |        |      |
|*  1 |  COUNT STOPKEY                         |                     |       |       |            |          |       |       |        |      |
|*  2 |   HASH JOIN                            |                     |     1 |   288 |  5273K  (1)| 00:03:27 |       |       |        |      |
|   3 |    JOIN FILTER CREATE                  | :BF0000             |     1 |    22 |    59   (0)| 00:00:01 |       |       |        |      |
|   4 |     PARTITION LIST ALL                 |                     |     1 |    22 |    59   (0)| 00:00:01 |     1 |     2 |        |      |
|   5 |      PARTITION RANGE ALL               |                     |     1 |    22 |    59   (0)| 00:00:01 |     1 |  LAST |        |      |
|   6 |       TABLE ACCESS BY LOCAL INDEX ROWID| ORDERS              |     1 |    22 |    59   (0)| 00:00:01 |     1 |    29 |        |      |
|*  7 |        INDEX RANGE SCAN                | IDX_ORDERS_CREATED  |     1 |       |    57   (0)| 00:00:01 |     1 |    29 |        |      |
|   8 |    VIEW                                | TEST                |  3840K|   974M|  5273K  (1)| 00:03:27 |       |       |        |      |
|   9 |     SORT GROUP BY                      |                     |  3840K|   201M|  5273K  (1)| 00:03:27 |       |       |        |      |
|  10 |      JOIN FILTER USE                   | :BF0000             |   994M|    50G|  5273K  (1)| 00:03:27 |       |       |        |      |
|  11 |       NESTED LOOPS                     |                     |   994M|    50G|  5273K  (1)| 00:03:27 |       |       |        |      |
|  12 |        INDEX FULL SCAN                 | PK_ID               |  3840K|    51M| 66212   (1)| 00:00:03 |       |       |        |      |
|* 13 |        INDEX STORAGE FAST FULL SCAN    | IDX_MN_AN_AD_ALL    |   259 | 10619 |     1   (0)| 00:00:01 |       |       |        |      |
|  14 |         REMOTE                         |                     |       |       |            |          |       |       |    DB2 | R->S |
----------------------------------------------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):                                                                                           
---------------------------------------------------                                                                                           

   1 - filter(ROWNUM<10)                                                                                                                      
   2 - access("A_OUT"."ID"="Z_OUT"."ID")                                                                                                
   7 - access("A_OUT"."CREATED">TRUNC(SYSDATE@!))                                                                                      
  13 - filter("B2"."ATTR_1"=NVL(CASE  WHEN (SUBSTR("ID",(-1))<'5' AND  EXISTS (SELECT 0 FROM  "A1")) THEN 'YYY' END ,'#') OR               
              "B2"."ATTR_1"='*')                                                                                                              

Remote SQL Information (identified by operation id):                                                                                          
----------------------------------------------------                                                                                          

  14 - EXPLAIN PLAN INTO PLAN_TABLE@! FOR SELECT 0 FROM "DUAL" "A1" (accessing 'DB2' )                                                        

我希望视图被访问n次数,就像在第一个场景中一样。我尝试使用提示但没有成功。

可能有用的是,即使and exists(select 1 from dual@db2)视图中未注释该行,以下查询也具有出色的性能(我知道这与 不同Q1)。

select
    (select value from test z_out where a_out.id=z_out.id) as value,
    a_out.id
from orders a_out
where a_out.created>trunc(sysdate) and rownum<10

因此,我想n即使该行and exists(select 1 from dual@db2)未注释,该视图在被访问时也能正常工作。但我无法强制执行计划朝那个方向发展。

如果需要提示,我只想将它们添加到视图 DDL 中(如果可能的话),这样使用视图的人就不必担心了。

==================================================== ===============

编辑:执行了以下操作:

alter session set statistics_level = 'ALL';
-- Q1 (the query I'm having problems with)
select * from table (dbms_xplan.display_cursor (format=>'ALLSTATS LAST'));

Plan hash value: 3271081243                                                                                                                                 

------------------------------------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation                              | Name                | Starts | E-Rows | A-Rows |   A-Time   | Buffers | Reads  |  OMem |  1Mem | Used-Mem |
------------------------------------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                       |                     |      1 |        |      0 |00:00:00.01 |       0 |      0 |       |       |          |
|*  1 |  COUNT STOPKEY                         |                     |      1 |        |      0 |00:00:00.01 |       0 |      0 |       |       |          |
|*  2 |   HASH JOIN                            |                     |      1 |      1 |      0 |00:00:00.01 |       0 |      0 |  3789K|  3789K| 1078K (0)|
|   3 |    JOIN FILTER CREATE                  | :BF0000             |      1 |      1 |  25602 |00:00:00.22 |   23345 |    161 |       |       |          |
|   4 |     PARTITION LIST ALL                 |                     |      1 |      1 |  25602 |00:00:00.21 |   23345 |    161 |       |       |          |
|   5 |      PARTITION RANGE ALL               |                     |      2 |      1 |  25602 |00:00:00.21 |   23345 |    161 |       |       |          |
|   6 |       TABLE ACCESS BY LOCAL INDEX ROWID| ORDERS              |     29 |      1 |  25602 |00:00:00.20 |   23345 |    161 |       |       |          |
|*  7 |        INDEX RANGE SCAN                | IDX_CREATED         |     13 |      1 |  25602 |00:00:00.12 |     474 |    161 |  1025K|  1025K|          |
|   8 |    VIEW                                | TEST                |      1 |   3820K|      0 |00:00:00.01 |       0 |      0 |       |       |          |
|   9 |     SORT GROUP BY                      |                     |      1 |   3820K|      0 |00:00:00.01 |       0 |      0 | 73728 | 73728 |          |
|  10 |      JOIN FILTER USE                   | :BF0000             |      1 |    989M|    106M|00:03:38.87 |      60M|  52960 |       |       |          |
|  11 |       NESTED LOOPS                     |                     |      1 |    989M|    328M|00:03:04.11 |      60M|  52960 |       |       |          |
|  12 |        INDEX FULL SCAN                 | PK_ID               |      1 |   3820K|   1245K|00:00:21.04 |     200K|  52959 |  1025K|  1025K|          |
|* 13 |        INDEX STORAGE FAST FULL SCAN    | IDX_MN_AN_AD_ALL    |   1245K|    259 |    328M|00:02:12.09 |      60M|      1 |  1025K|  1025K|          |
|  14 |         REMOTE                         |                     |      1 |        |      1 |00:00:00.01 |       0 |      0 |       |       |          |
------------------------------------------------------------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):                                                                                                         
---------------------------------------------------                                                                                                         

   1 - filter(ROWNUM<10)                                                                                                                                    
   2 - access("A_OUT"."ID"="Z_OUT"."ID")                                                                                                              
   7 - access("A_OUT"."CREATED">TRUNC(SYSDATE@!))                                                                                                    
  13 - filter(("B2"."ATTR_1"=NVL(CASE  WHEN (SUBSTR("ID",(-1))<'5' AND  IS NOT NULL) THEN 'YYY' END ,'#') OR "B2"."ATTR_1"='*'))                         

注意:如果视图中未注释,Q1性能会阻止查询完成。and exists(select 1 from dual@db2)要获得之前的执行计划,我必须更改会话、运行Q1、停止Q1(大约 4 分钟后),然后计算计划。

以下执行计划以相同的方式生成,但视图已--and exists(select 1 from dual@db2)注释行(性能良好)。

Plan hash value: 2906430222                                                                                            

-----------------------------------------------------------------------------------------------------------------------
| Id  | Operation                             | Name                | Starts | E-Rows | A-Rows |   A-Time   | Buffers |
-----------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                      |                     |      1 |        |      9 |00:00:00.01 |     223 |
|*  1 |  COUNT STOPKEY                        |                     |      1 |        |      9 |00:00:00.01 |     223 |
|   2 |   NESTED LOOPS                        |                     |      1 |      1 |      9 |00:00:00.01 |     223 |
|   3 |    PARTITION LIST ALL                 |                     |      1 |      1 |      9 |00:00:00.01 |      41 |
|   4 |     PARTITION RANGE ALL               |                     |      1 |      1 |      9 |00:00:00.01 |      41 |
|   5 |      TABLE ACCESS BY LOCAL INDEX ROWID| ORDERS              |     14 |      1 |      9 |00:00:00.01 |      41 |
|*  6 |       INDEX RANGE SCAN                | IDX_CREATED         |     12 |      1 |      9 |00:00:00.01 |      33 |
|   7 |    VIEW PUSHED PREDICATE              | TEST                |      9 |      1 |      9 |00:00:00.01 |     182 |
|*  8 |     FILTER                            |                     |      9 |        |      9 |00:00:00.01 |     182 |
|   9 |      SORT AGGREGATE                   |                     |      9 |      1 |      9 |00:00:00.01 |     182 |
|  10 |       NESTED LOOPS                    |                     |      9 |    259 |   2376 |00:00:00.01 |     182 |
|* 11 |        INDEX UNIQUE SCAN              | PK_ID               |      9 |      1 |      9 |00:00:00.01 |      20 |
|* 12 |        INDEX STORAGE FAST FULL SCAN   | IDX_MN_AN_AD_ALL    |      9 |    259 |   2376 |00:00:00.01 |     162 |
-----------------------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):                                                                    
---------------------------------------------------                                                                    

   1 - filter(ROWNUM<10)                                                                                               
   6 - access("A_OUT"."CREATED">TRUNC(SYSDATE@!))                                                               
   8 - filter(COUNT(*)>0)                                                                                              
  11 - access("ID"="A_OUT"."ID")                                                                                 
  12 - storage(("B2"."ATTR_1"=NVL(CASE  WHEN SUBSTR("ID",(-1))<'5' THEN 'YYY' END ,'#') OR                          
              "B2"."ATTR_1"='*'))                                                                                      
       filter(("B2"."ATTR_1"=NVL(CASE  WHEN SUBSTR("ID",(-1))<'5' THEN 'YYY' END ,'#') OR                           
              "B2"."ATTR_1"='*'))       
4

0 回答 0