sql >> Base de Datos >  >> RDS >> Oracle

Falta STOPKEY por partición en el plan de Oracle para la paginación por índice local

Cuando usa variables de vinculación, Oracle se ve obligado a usar poda de partición dinámica en lugar de eliminación de partición estática . El resultado de esto es que Oracle no sabe en el momento del análisis a qué particiones se accederá, ya que esto cambia según las variables de entrada.

Esto significa que cuando usamos valores literales (en lugar de variables de vinculación), sabemos a qué particiones accederá su índice local. Por lo tanto, la count stopkey se puede aplicar a la salida del índice antes de que eliminemos las particiones.

Al usar variables de vinculación, el partition range iterator tiene que averiguar a qué particiones está accediendo. Luego tiene una verificación para asegurarse de que la primera de sus variables en las operaciones intermedias tenga un valor más bajo que la segunda (el filter operación en el segundo plan).

Esto se puede reproducir fácilmente, como muestra el siguiente caso de prueba:

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

Como en su ejemplo, la segunda consulta solo puede filtrar las particiones a una key en tiempo de análisis, en lugar de las particiones exactas como en el primer ejemplo.

Este es uno de esos raros casos en los que los valores literales pueden proporcionar un mejor rendimiento que las variables de vinculación. Debe investigar si esta es una posibilidad para usted.

Finalmente, dices que quieres 20 filas de cada partición. Su consulta tal como está no hará esto, solo le devolverá las primeras 20 filas de acuerdo con su pedido. Para 20 filas/partición, debe hacer algo como esto:

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

ACTUALIZAR

La razón por la que no está obteniendo la count stopkey tiene que ver con el filter operación en la línea 4 del plan "malo". Puede ver esto más claramente si repite el ejemplo anterior, pero sin particiones.

Esto te da los siguientes planes:

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

Como puede ver, hay un filter extra operación cuando utiliza variables de vinculación que aparecen antes del sort order by stopkey . Esto sucede después de acceder al archivo index. Esto es verificar que los valores de las variables permitirán que se devuelvan los datos (la primera variable en su medio en realidad tiene un valor más bajo que la segunda). Esto no es necesario cuando se usan literales porque el optimizador ya sabe que 50 es menor que 100 (en este caso). Sin embargo, no sabe si :a es menor que :b en el momento del análisis.

¿Por qué exactamente esto es? No lo sé. Podría ser un diseño intencional de Oracle:no tiene sentido hacer la verificación de la tecla de detención si los valores establecidos para las variables dan como resultado cero filas, o simplemente un descuido.