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

Particionamiento dividido rápido

Tengo una tabla particionada para algunos registros de aplicaciones. Hace unos años, particioné la tabla con una partición por mes. A medida que nos acercamos a 2016, es hora de que agregue particiones para el nuevo año. La tabla particionada tiene, como sus dos últimas particiones, la partición de diciembre de 2015 y una partición que usa MAXVALUE. Nunca planeo tener datos en la partición MAXVALUE. Solo está ahí para facilitar las operaciones de SPLIT PARTITION.

En el pasado, agregaba particiones con comandos similares a los siguientes:

ALTER TABLE usage_tracking
SPLIT PARTITION usage_tracking_pmax AT (TO_DATE('02/01/2016 00:00:00','MM/DD/YYYY HH24:MI:SS))
INTO (PARTITION usage_tracking_p201601, PARTITION usage_tracking_pmax);
ALTER TABLE usage_tracking
SPLIT PARTITION usage_tracking_pmax AT (TO_DATE('03/01/2016 00:00:00','MM/DD/YYYY HH24:MI:SS'))
INTO (PARTITION usage_tracking_p201602, PARTITION usage_tracking_pmax);

Las instrucciones SQL anteriores dividirán la partición MAXVALUE en dos particiones. Hay 12 de estos comandos, uno para cada mes.

Este año, cuando traté de ejecutar el script para 2016 en un entorno que no es de producción, me sorprendió descubrir que estos comandos tardaron unos 30 minutos en completarse cada uno. En años anteriores, se completaban en segundos. Recuerde que USAGE_TRACKING_PMAX está vacío, por lo que no es necesario mover datos a una partición adecuada.

Al analizar la actividad de mi sesión realizando SPLIT, pude ver claramente los eventos de espera del archivo db que se rastrearon en esta tabla particionada. Era obvio que la operación SPLIT estaba leyendo la partición máxima, aunque estaba vacía.

Los años anteriores funcionaron bien, pero esta base de datos se actualizó recientemente a Oracle 12c. Encontré información sobre cómo realizar una operación de partición dividida rápida en MOS Note 1268714.1 que dice que esto se aplica a Oracle 10.2.0.3 y versiones posteriores, pero no tuve ningún problema en 11.2.0.4. Probablemente fue pura suerte y no tengo una base de datos 11g para comprobar esto, ya que todas las mías se han actualizado. Como tal, en lugar de centrarme en lo que cambió, simplemente abordaré el problema y continuaré con mi día.

Según la nota de MOS, para realizar una partición dividida rápida en esta partición vacía, debo asegurarme de tener estadísticas en la partición vacía.

Confirmé que NUM_ROWS era 0 para esta partición vacía. Así que no tuve que calcular estadísticas en la partición. Mi primera operación de SPLIT PARTITION fue muy rápida, solo unos segundos. La partición estaba vacía y Oracle lo sabía. Lo que me sorprendió fue que la nueva partición, USAGE_TRACKING_P201601 y USAGE_TRACKING_PMAX pasaron a valores NULL para las estadísticas. Esto significaba que llevaría mucho tiempo realizar la operación DIVIDIR PARTICIÓN para la segunda partición nueva. Aquí hay un ejemplo de lo que quiero decir. Primero, podemos ver 0 filas en la partición de valor máximo.

SQL> select num_rows from dba_tab_partitions
  2  where partition_name='USAGE_TRACKING_PMAX';
 
  NUM_ROWS
----------
         0

Ahora dividiré esa partición.

SQL> ALTER TABLE usage_tracking
  2  SPLIT PARTITION usage_tracking_pmax AT ( TO_DATE('02/01/2016 00:00:00','MM/DD/YYYY HH24:MI:SS') )
  3  INTO (PARTITION usage_tracking_p201601, PARTITION usage_tracking_pmax);
 
Table altered.
Elapsed: 00:00:03.13

Observe ahora que las dos últimas particiones ahora no tienen estadísticas.

SQL> select num_rows from dba_tab_partitions
  2  where partition_name='USAGE_TRACKING_PMAX';
 
  NUM_ROWS
----------
 
 
SQL> select num_rows from dba_tab_partitions
  2  where partition_name='USAGE_TRACKING_P201601';
 
  NUM_ROWS
----------
 
 

Sin estadísticas, la siguiente partición dividida para crear la partición de febrero de 2016 lleva mucho tiempo.

SQL> ALTER TABLE nau_system.usage_tracking
  2  SPLIT PARTITION usage_tracking_pmax AT (TO_DATE('03/01/2016 00:00:00','MM/DD/YYYY HH24:MI:SS'))
  3  INTO (PARTITION usage_tracking_p201602, PARTITION usage_tracking_pmax);
 
Table altered.
Elapsed: 00:27:41.09

Como dice la nota de MOS, necesitamos las estadísticas de la partición para realizar una operación de división rápida. La solución es calcular las estadísticas en la partición y luego usar un comando ALTER TABLE para crear todas las particiones a la vez.

BEGIN
 DBMS_STATS.gather_table_stats (tabname=>'USAGE_TRACKING',
 partname => 'USAGE_TRACKING_PMAX',
 granularity => 'PARTITION');
 END;
 /
ALTER TABLE usage_tracking
SPLIT PARTITION usage_tracking_pmax INTO
 (PARTITION usage_tracking_p201601 VALUES LESS THAN (TO_DATE('02/01/2016 00:00:00','MM/DD/YYYY HH24:MI:SS')),
  PARTITION usage_tracking_p201602 VALUES LESS THAN (TO_DATE('03/01/2016 00:00:00','MM/DD/YYYY HH24:MI:SS')),
  PARTITION usage_tracking_p201603 VALUES LESS THAN (TO_DATE('04/01/2016 00:00:00','MM/DD/YYYY HH24:MI:SS')),
  PARTITION usage_tracking_p201604 VALUES LESS THAN (TO_DATE('05/01/2016 00:00:00','MM/DD/YYYY HH24:MI:SS')),
  PARTITION usage_tracking_p201605 VALUES LESS THAN (TO_DATE('06/01/2016 00:00:00','MM/DD/YYYY HH24:MI:SS')),
  PARTITION usage_tracking_p201606 VALUES LESS THAN (TO_DATE('07/01/2016 00:00:00','MM/DD/YYYY HH24:MI:SS')),
  PARTITION usage_tracking_p201607 VALUES LESS THAN (TO_DATE('08/01/2016 00:00:00','MM/DD/YYYY HH24:MI:SS')),
  PARTITION usage_tracking_p201608 VALUES LESS THAN (TO_DATE('09/01/2016 00:00:00','MM/DD/YYYY HH24:MI:SS')),
  PARTITION usage_tracking_p201609 VALUES LESS THAN (TO_DATE('10/01/2016 00:00:00','MM/DD/YYYY HH24:MI:SS') ),
  PARTITION usage_tracking_p201610 VALUES LESS THAN (TO_DATE('11/01/2016 00:00:00','MM/DD/YYYY HH24:MI:SS') ),
  PARTITION usage_tracking_p201611 VALUES LESS THAN (TO_DATE('12/01/2016 00:00:00','MM/DD/YYYY HH24:MI:SS') ),
  PARTITION usage_tracking_p201612 VALUES LESS THAN (TO_DATE('01/01/2017 00:00:00','MM/DD/YYYY HH24:MI:SS') ),
  PARTITION usage_tracking_pmax);

Si hubiera dejado la secuencia de comandos para realizar 12 operaciones individuales de PARTICIÓN DIVIDIDA, habría tenido que volver a calcular las estadísticas en la partición máxima entre cada una. Usar un comando fue más eficiente.