« Aviso...Graficar información de crecimiento de tablespaces »

¿Qué es un INDEX SKIP SCAN?



Siempre hemos escuchado que el no ocupar la cabecera del índice hará que simplemente no ocupemos el índice (índices compuestos) ... pues bien esto se mantuvo por harto tiempo, hasta la versión 9i de Oracle.




Quizás es algo que quedo en la retina y que casi siempre forzábamos haciendo un típico "campo1 > 0" para que realmente ocupará el índice, pero eso es lo más malo y erróneo que podemos hacer... teniendo en cuenta que hacer un FULL sobre una tabla no es siempre malo.


Un INDEX SKIP SCAN permite usar sólo una parte del índice cuando no estamos utilizando su cabecera, esto es muy provechoso ya que de todas formas no estamos haciendo un FULL sobre la tabla, todo esto es analizado por el CBO , con lo cual "siempre" elige el mejor plan de ejecución, es más , CBO podría dejar fuera de acción la cabecera de un índice y solamente ocupar "su cuerpo". Esta opción solamente está disponible para índices del tipo B*Tree


Para graficar de mejor forma el comportamiento de un INDEX SKIP SCAN , va un ejemplo


- Creamos una tabla
create table at2(a varchar2(3),b varchar2(10),c varchar2(5));


- La cargamos de información

begin
  for i in 1..1000 loop
      insert into at2 values('M', i, 'M');
      insert into at2 values('F', i, 'F');
  end loop;
end;
/


- Creamos un índice sobre la tabla

create index at2_i on at2(a,b,c);


- Analizamos la tabla con el método "FOR ALL COLUMNS SIZE 1" que significa, tomar estadísticas básicas del objeto, sin necesidad de histogramas, datos estadísticos como mínimo, máximo ,cantidad de valores distintos, etc.

exec dbms_stats.gather_table_stats(OWNNAME => NULL, TABNAME => 'at2', 
 CASCADE => TRUE, method_opt => 'FOR ALL COLUMNS SIZE 1');


- Seteamos el trace de la consulta y ejecutamos la query , pero ocupando el segundo campo del índice

SQL- set autotrace on exp stat

SQL> select * from at2 where b='352';

A   B          C
--- ---------- -----
F   352        F
M   352        M


Execution Plan
----------------------------------------------------------
Plan hash value: 1279236776

--------------------------------------------------------------------------
| Id  | Operation        | Name  | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------
|   0 | SELECT STATEMENT |       |     2 |    16 |     3   (0)| 00:00:01 |
|*  1 |  INDEX SKIP SCAN | AT2_I |     2 |    16 |     3   (0)| 00:00:01 |
--------------------------------------------------------------------------

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

   1 - access("B"='352')
       filter("B"='352')


Statistics
----------------------------------------------------------
          1  recursive calls
          0  db block gets
          7  consistent gets
          0  physical reads
          0  redo size
        728  bytes sent via SQL*Net to client
        524  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
          2  rows processed


Ciertas cosas que mencionar...

- Aparece claramente en el plan de ejecución lo siguiente "INDEX SKIP SCAN" , pues está es la sentencia que buscábamos, pues el plan de ejecución indica que lo mejor es ocupar el índice AT2_I , a pesar de que ocupemos sólo el segundo campo .

- Hay que tener en cuenta la estadística el valor de "consistent gets" que en este caso es 8 y que representa la cantidad de veces que se obtiene información desde un bloque Oracle que se encuentra en memoria (Buffer Cache)


Ahora bien, si ejecutamos la misma consulta , pero le indicamos que no ocuparemos el índice, pues la cantidad de "consistents gets" sube, por ende no es lo óptimo.. y esto se desprende del FULL SCAN que está haciendo sobre la tabla.

SQL- select /*+ no_index (at2) */ * from at2 where b='352'

A   B          C
--- ---------- -----
M   352        M
F   352        F


Execution Plan
----------------------------------------------------------
Plan hash value: 2725892949

--------------------------------------------------------------------------
| Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |      |     2 |    16 |     3   (0)| 00:00:01 |
|*  1 |  TABLE ACCESS FULL| AT2  |     2 |    16 |     3   (0)| 00:00:01 |
--------------------------------------------------------------------------

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

   1 - filter("B"='352')


Statistics
----------------------------------------------------------
          0  recursive calls
          0  db block gets
          8  consistent gets
          0  physical reads
          0  redo size
        728  bytes sent via SQL*Net to client
        524  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
          2  rows processed



Referencias
[Metalink] : Index Skip Scan Feature [ID 212391.1]
Index Skip Scan Oracle 10g

Espero les sea de utilidad

by Ligarius
26.12.12. 06:17:36. 672 words, 6189 views. Categories: Tuning / Performance ,