sql >> Database teknologi >  >> RDS >> Oracle

Mangler STOPKEY pr. partition i Oracle-planen til personsøgning efter lokalt indeks

Når du bruger bindevariabler, er Oracle tvunget til at bruge dynamisk partitionsbeskæring i stedet for statisk partitionsbeskæring . Resultatet af dette er, at Oracle ikke ved parsetidspunktet, hvilke partitioner der vil blive tilgået, da dette ændres baseret på dine inputvariabler.

Det betyder, at når vi bruger bogstavelige værdier (i stedet for bindevariabler), ved vi, hvilke partitioner der vil blive tilgået af dit lokale indeks. Derfor count stopkey kan anvendes på outputtet af indekset, før vi beskærer partitionerne.

Når du bruger bindevariabler, partition range iterator skal finde ud af, hvilke partitioner du har adgang til. Den har derefter en kontrol for at sikre, at den første af dine variabler i mellem-handlingerne faktisk har en lavere værdi end den anden (filter operation i den anden plan).

Dette kan nemt reproduceres, som følgende testcase viser:

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 |                                                                                                                                                                                                                                        
--------------------------------------------------------------------- 
 

Som i dit eksempel kan den anden forespørgsel kun filtrere partitionerne til en key på parsetid, snarere end de nøjagtige partitioner som i det første eksempel.

Dette er et af de sjældne tilfælde, hvor bogstavelige værdier kan give bedre ydeevne end bindevariabler. Du bør undersøge, om dette er en mulighed for dig.

Til sidst siger du, at du vil have 20 rækker fra hver partition. Din forespørgsel som stands vil ikke gøre dette, den vil bare returnere dig de første 20 rækker i henhold til din bestilling. For 20 rækker/partition skal du gøre noget som dette:

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
 

OPDATERING

Årsagen til, at du ikke får count stopkey er at gøre med filter drift i linje 4 i den "dårlige" plan. Du kan se dette tydeligere, hvis du gentager eksemplet ovenfor, men uden partitionering.

Dette giver dig følgende planer:

---------------------------------------- | 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'))

Som du kan se, er der et ekstra filter operation, når du bruger bindevariabler, der vises før sort order by stopkey . Dette sker efter adgang til indekset. Dette er at kontrollere, at værdierne for variablerne vil tillade, at data returneres (den første variabel i din mellem har faktisk en lavere værdi end den anden). Dette er ikke nødvendigt, når du bruger bogstaver, fordi optimeringsværktøjet allerede ved, at 50 er mindre end 100 (i dette tilfælde). Den ved dog ikke, om :a er mindre end :b på parsetidspunktet.

Hvorfor det præcist er det ved jeg ikke. Det kan være bevidst design af Oracle - det nytter ikke noget at foretage stoptasten, hvis værdierne for variablerne resulterer i nul rækker - eller bare en forglemmelse.



  1. Sådan administrerer du privilegier med roller i MySQL

  2. SQL-funktion som standardparameterværdi?

  3. MySQL Connector til Python

  4. Sådan finder du minimumsværdien af ​​en kolonne i SQL