sql >> Database >  >> RDS >> Oracle

Ontbrekende STOPKEY per partitie in Oracle-plan voor paging op lokale index

Wanneer u bindvariabelen gebruikt, wordt Oracle gedwongen om te gebruiken dynamische partitie snoeien in plaats van snoeien van statische partities . Het resultaat hiervan is dat Oracle tijdens het parseren niet weet welke partities worden benaderd, omdat dit verandert op basis van uw invoervariabelen.

Dit betekent dat wanneer we letterlijke waarden gebruiken (in plaats van bindvariabelen), we weten welke partities worden benaderd door uw lokale index. Daarom is de count stopkey kan worden toegepast op de uitvoer van de index voordat we de partities snoeien.

Bij gebruik van bindvariabelen, de partition range iterator moet uitzoeken tot welke partities u toegang hebt. Vervolgens wordt er gecontroleerd of de eerste van uw variabelen in de tussenbewerkingen daadwerkelijk een lagere waarde heeft dan de tweede (het filter operatie in het tweede plan).

Dit kan eenvoudig worden gereproduceerd, zoals blijkt uit de volgende testcase:

create table tab (
  x date,
  y integer,
  filler varchar2(100)
) partition by range(x) (
  partition p1 values less than (date'2013-01-01'),
  partition p2 values less than (date'2013-02-01'),
  partition p3 values less than (date'2013-03-01'),
  partition p4 values less than (date'2013-04-01'),
  partition p5 values less than (date'2013-05-01'),
  partition p6 values less than (date'2013-06-01')
);


insert into tab (x, y)
  select add_months(trunc(sysdate, 'y'), mod(rownum, 5)), rownum, dbms_random.string('x', 50)
  from   dual 
  connect by level <= 1000;

create index i on tab(x desc, y desc) local;

exec dbms_stats.gather_table_stats(user, 'tab', cascade => true);

explain plan for 
SELECT * FROM (
  SELECT rowid FROM tab
  where  x between date'2013-01-01' and date'2013-02-02'
  and    y between 50 and 100
  order  by x desc, y desc
)
where rownum <= 5;

SELECT * FROM table(dbms_xplan.display(null, null, 'BASIC +ROWS +PARTITION'));

--------------------------------------------------------------------                                                                                                                                                                                                                                         
| Id  | Operation                   | Name | Rows  | Pstart| Pstop |                                                                                                                                                                                                                                         
--------------------------------------------------------------------                                                                                                                                                                                                                                         
|   0 | SELECT STATEMENT            |      |     1 |       |       |                                                                                                                                                                                                                                         
|   1 |  COUNT STOPKEY              |      |       |       |       |                                                                                                                                                                                                                                         
|   2 |   VIEW                      |      |     1 |       |       |                                                                                                                                                                                                                                         
|   3 |    SORT ORDER BY STOPKEY    |      |     1 |       |       |                                                                                                                                                                                                                                         
|   4 |     PARTITION RANGE ITERATOR|      |     1 |     2 |     3 |                                                                                                                                                                                                                                         
|   5 |      COUNT STOPKEY          |      |       |       |       |                                                                                                                                                                                                                                         
|   6 |       INDEX RANGE SCAN      | I    |     1 |     2 |     3 |                                                                                                                                                                                                                                         
-------------------------------------------------------------------- 

explain plan for 
SELECT * FROM (
  SELECT rowid FROM tab
  where  x between to_date(:st, 'dd/mm/yyyy') and to_date(:en, 'dd/mm/yyyy')
  and    y between :a and :b
  order  by x desc, y desc
)
where rownum <= 5;

SELECT * FROM table(dbms_xplan.display(null, null, 'BASIC +ROWS +PARTITION'));

---------------------------------------------------------------------                                                                                                                                                                                                                                        
| Id  | Operation                    | Name | Rows  | Pstart| Pstop |                                                                                                                                                                                                                                        
---------------------------------------------------------------------                                                                                                                                                                                                                                        
|   0 | SELECT STATEMENT             |      |     1 |       |       |                                                                                                                                                                                                                                        
|   1 |  COUNT STOPKEY               |      |       |       |       |                                                                                                                                                                                                                                        
|   2 |   VIEW                       |      |     1 |       |       |                                                                                                                                                                                                                                        
|   3 |    SORT ORDER BY STOPKEY     |      |     1 |       |       |                                                                                                                                                                                                                                        
|   4 |     FILTER                   |      |       |       |       |                                                                                                                                                                                                                                        
|   5 |      PARTITION RANGE ITERATOR|      |     1 |   KEY |   KEY |                                                                                                                                                                                                                                        
|   6 |       INDEX RANGE SCAN       | I    |     1 |   KEY |   KEY |                                                                                                                                                                                                                                        
--------------------------------------------------------------------- 

Net als in uw voorbeeld, kan de tweede query alleen de partities filteren op een key tijdens het parseren, in plaats van de exacte partities zoals in het eerste voorbeeld.

Dit is een van die zeldzame gevallen waarin letterlijke waarden betere prestaties kunnen leveren dan bindvariabelen. Je moet onderzoeken of dit voor jou een mogelijkheid is.

Ten slotte zegt u dat u 20 rijen van elke partitie wilt. Uw zoekopdracht als standaard zal dit niet doen, het zal u alleen de eerste 20 rijen retourneren volgens uw bestelling. Voor 20 rijen/partitie moet je zoiets als dit doen:

select rd from (
    select rowid rd, 
           row_number() over (partition by trx_id order by create_ts desc) rn
    from OUT_SMS     
    where  TRX_ID between ? and ?       
       and CREATE_TS between ? and ?
    order by CREATE_TS DESC, TRX_ID DESC
) where rn <= 20

UPDATE

De reden waarom je de count stopkey niet krijgt heeft te maken met het filter operatie in regel 4 van het "slechte" plan. U kunt dit duidelijker zien als u het bovenstaande voorbeeld herhaalt, maar zonder partitionering.

Dit geeft je de volgende plannen:

----------------------------------------                                                                                                                                                                                                                                                                     
| Id  | Operation               | Name |                                                                                                                                                                                                                                                                     
----------------------------------------                                                                                                                                                                                                                                                                     
|   0 | SELECT STATEMENT        |      |                                                                                                                                                                                                                                                                     
|*  1 |  COUNT STOPKEY          |      |                                                                                                                                                                                                                                                                     
|   2 |   VIEW                  |      |                                                                                                                                                                                                                                                                     
|*  3 |    SORT ORDER BY STOPKEY|      |                                                                                                                                                                                                                                                                     
|*  4 |     TABLE ACCESS FULL   | TAB  |                                                                                                                                                                                                                                                                     
----------------------------------------                                                                                                                                                                                                                                                                     

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

   1 - filter(ROWNUM<=5)                                                                                                                                                                                                                                                                                     
   3 - filter(ROWNUM<=5)                                                                                                                                                                                                                                                                                     
   4 - filter("X">=TO_DATE(' 2013-01-01 00:00:00', 'syyyy-mm-dd                                                                                                                                                                                                                                              
              hh24:mi:ss') AND "X"<=TO_DATE(' 2013-02-02 00:00:00', 'syyyy-mm-dd                                                                                                                                                                                                                             
              hh24:mi:ss') AND "Y">=50 AND "Y"<=100)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       

----------------------------------------                                                                                                                                                                                                                                                                     
| Id  | Operation               | Name |                                                                                                                                                                                                                                                                     
----------------------------------------                                                                                                                                                                                                                                                                     
|   0 | SELECT STATEMENT        |      |                                                                                                                                                                                                                                                                     
|*  1 |  COUNT STOPKEY          |      |                                                                                                                                                                                                                                                                     
|   2 |   VIEW                  |      |                                                                                                                                                                                                                                                                     
|*  3 |    SORT ORDER BY STOPKEY|      |                                                                                                                                                                                                                                                                     
|*  4 |     FILTER              |      |                                                                                                                                                                                                                                                                     
|*  5 |      TABLE ACCESS FULL  | TAB  |                                                                                                                                                                                                                                                                     
----------------------------------------                                                                                                                                                                                                                                                                     

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

   1 - filter(ROWNUM<=5)                                                                                                                                                                                                                                                                                     
   3 - filter(ROWNUM<=5)                                                                                                                                                                                                                                                                                     
   4 - filter(TO_NUMBER(:A)<=TO_NUMBER(:B) AND                                                                                                                                                                                                                                                               
              TO_DATE(:ST,'dd/mm/yyyy')<=TO_DATE(:EN,'dd/mm/yyyy'))                                                                                                                                                                                                                                          
   5 - filter("Y">=TO_NUMBER(:A) AND "Y"<=TO_NUMBER(:B) AND                                                                                                                                                                                                                                                  
              "X">=TO_DATE(:ST,'dd/mm/yyyy') AND "X"<=TO_DATE(:EN,'dd/mm/yyyy'))   

Zoals je kunt zien, is er een extra filter bewerking wanneer u bindvariabelen gebruikt die verschijnen vóór de sort order by stopkey . Dit gebeurt na toegang tot de index. Hiermee wordt gecontroleerd of de waarden voor de variabelen het mogelijk maken om gegevens te retourneren (de eerste variabele in uw tussenliggende heeft eigenlijk een lagere waarde dan de tweede). Dit is niet nodig bij het gebruik van letterlijke waarden, omdat de optimizer al weet dat 50 minder is dan 100 (in dit geval). Het weet echter niet of :a kleiner is dan :b tijdens de parse-tijd.

Waarom dit precies is weet ik niet. Het kan een opzettelijk ontwerp van Oracle zijn - het heeft geen zin om de stopkey-controle uit te voeren als de waarden die zijn ingesteld voor de variabelen resulteren in nul rijen - of gewoon een vergissing.



  1. Unieke beperking met voorwaarden in MYSQL

  2. Type komt niet overeen:kan niet converteren van int naar ResultSet

  3. To-do lijst applicatie met PHP en MySQL database

  4. ROLLBACK-gebeurtenistriggers in postgresql