¿Cómo se distribuye el SPOOL en Teradata?: VERBOSEEXPLAIN

Teradata utiliza el así llamado ‘spool‘ (más específicamente ‘spool files‘) como mecanismo para almacenar los resultados intermedios de las ejecuciones de los comandos SQL. Como todo el mundo debería saber, los motores de bases de datos siempre efectuan los comandos en forma de pasos en los que se comparan dos tablas cada vez. Si ejecutamos un ‘SELECT’ en el que intervienen varias tablas, éste se efectuará como una serie de comparaciones entre dos. Por supuesto, el resultado de un paso suele ser uno de los dos intervinientes en el siguiente o posteriores, y además estas comparaciones entre dos tablas (o, más exactamente, dos ‘resultsets‘) pueden llegar a hacerse en paralelo cuando es posible evitar una dependencia que ‘serialice‘ la ejecución.

A esto hay que sumarle la naturaleza ‘paralela’ de Teradata y su arquitectura ‘shared nothing‘: cada AMP lleva a cabo sus tareas de forma independiente del resto. Entonces, cuando se genera un ‘spool file‘ ¿cómo se distribuye entre los AMPs?. ¿Cuál es la clave ‘hash‘ que se utiliza para partir en trocitos el ‘spool file‘ y enviar cada uno a un AMP?

EXPLAIN nos suele dar información valiosa al respecto, pero a veces se queda corta y hay partes que no aparecen tan claras. Pero para remediar esto está el comando (indocumentado) “DIAGNOSTIC VERBOSEEXPLAIN ON FOR SESSION” que incluye información adicional en los EXPLAINs acerca de los ‘spool files‘ y su distribución por ‘hash‘ hacia los AMPs.

Su funcionamiento es sencillo:

 BTEQ -- Enter your SQL request or BTEQ command:
DIAGNOSTIC VERBOSEEXPLAIN ON FOR SESSION;

 *** Null statement accepted.
 *** Total elapsed time was 1 second.

A partir de ahí, los EXPLAINs que todos conocemos y queremos cambiarán un poco:

EXPLAIN                                                                         
SELECT *                                                                        
  FROM CARLOS.PRUEBA01 a,                                                   
       CARLOS.PRUEBA02 b,                                                   
       CARLOS.PRUEBA03 c                                                    
 WHERE a.ID_N=b.ID_N                                                            
   AND b.ID_N=c.ID_N                                                            
;                                                                               

 *** Help information returned. 40 rows.                                        
 *** Total elapsed time was 1 second.                                           

Explanation                                                                     
--------------------------------------------------------------------------------
  1) First, we lock a distinct CARLOS."pseudo table" for read on a          
     RowHash to prevent global deadlock for CARLOS.c.                       
  2) Next, we lock a distinct CARLOS."pseudo table" for read on a           
     RowHash to prevent global deadlock for CARLOS.a.                       
  3) We lock a distinct CARLOS."pseudo table" for read on a RowHash         
     to prevent global deadlock for CARLOS.b.                               
  4) We lock CARLOS.c for read, we lock CARLOS.a for read, and          
     we lock CARLOS.b for read.                                             
  5) We execute the following steps in parallel.                                
       1) We do an all-AMPs JOIN step from CARLOS.c by way of a             
          RowHash match scan with no residual conditions, which is              
          joined to CARLOS.a by way of a RowHash match scan with no         
          residual conditions.  CARLOS.c and CARLOS.a are               
          joined using a merge join, with a join condition of (                 
          "CARLOS.a.ID_N = CARLOS.c.ID_N").  The result goes            
          into Spool 2 (all_amps), which is redistributed by hash code          
          to all AMPs with hash fields ("CARLOS.a.ID_N                      
          ,CARLOS.c.ID_N").  Then we do a SORT to order Spool 2 by          
          row hash.  The size of Spool 2 is estimated with low                  
          confidence to be 20 rows (1,220 bytes).  The estimated time           
          for this step is 0.01 seconds.                                        
       2) We do an all-AMPs RETRIEVE step from CARLOS.b by way of           
          an all-rows scan with no residual conditions into Spool 3             
          (all_amps), which is redistributed by hash code to all AMPs           
          with hash fields ("CARLOS.b.ID_N ,CARLOS.b.ID_N").            
          Then we do a SORT to order Spool 3 by row hash.  The size of          
          Spool 3 is estimated with low confidence to be 20 rows (560           
          bytes).  The estimated time for this step is 0.00 seconds.            
  6) We do an all-AMPs JOIN step from Spool 2 (Last Use) by way of a            
     RowHash match scan, which is joined to Spool 3 (Last Use) by way           
     of a RowHash match scan.  Spool 2 and Spool 3 are joined using a           
     merge join, with a join condition of ("(Spool_2.ID_N =                     
     Spool_3.ID_N) AND (Spool_2.ID_N = Spool_3.ID_N)").  The result             
     goes into Spool 1 (group_amps), which is built locally on the AMPs         
     with Field1 ("UniqueId").  The size of Spool 1 is estimated with           
     low confidence to be 20 rows (3,480 bytes).  The estimated time            
     for this step is 0.01 seconds.                                             
  7) Finally, we send out an END TRANSACTION step to all AMPs involved          
     in processing the request.                                                 
  -> The contents of Spool 1 are sent back to the user as the result of         
     statement 1.  The total estimated time is 0.02 seconds.

En resumen, a partir del “DIAGNOSTIC VERBOSEEXPLAIN” se especificarán las columnas para los ‘JOINs’ de los ‘spool files‘ y se especificarán los nombres de columna de la distribución de ‘hash‘ para los ‘spool files‘.

Una cosa: para volver a los EXPLAINs normales la sintaxis no es la obvia “DIAGNOSTIC VERBOSEEXPLAIN OFF FOR SESSION” (eso sería demasiado fácil), sino “DIAGNOSTIC VERBOSEEXPLAIN NOT ON FOR SESSION”:

 BTEQ -- Enter your SQL request or BTEQ command:
DIAGNOSTIC VERBOSEEXPLAIN OFF FOR SESSION;

DIAGNOSTIC VERBOSEEXPLAIN OFF FOR SESSION;
                              $
 *** Failure 3706 Syntax error: expected something between the word 'VERBOSEEXPLAIN' and the 'OFF' keyword.
                Statement# 1, Info =31
 *** Total elapsed time was 1 second.

 BTEQ -- Enter your SQL request or BTEQ command:
DIAGNOSTIC VERBOSEEXPLAIN NOT ON FOR SESSION;

 *** Null statement accepted.
 *** Total elapsed time was 1 second.

Para los intrépidos sin miedo a nada, también está la orden (sin documentar tampoco) “DIAGNOSTIC HELPSTATS ON FOR SESSION”, que hace que Teradata incluya diferentes recomendaciones de captura de estadísticas en el EXPLAIN en la forma “BEGIN RECOMMENDED STATS ->”

Saludos.

Carlos.

Deja un comentario

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s

A %d blogueros les gusta esto: