sql >> Base de Datos >  >> RDS >> PostgreSQL

Agallas de PostgreSQL:¿Qué es "resjunk"?

Estoy profundizando en el analizador, el reescritor de consultas y el planificador de consultas de PostgreSQL en este momento, como parte del trabajo de seguridad a nivel de fila para el proyecto AXLE. Como me di cuenta de que hay una gran documentación sobre la estructura y el flujo general, pero no mucho sobre algunos de los detalles, pensé en comenzar a publicar sobre algunos de los rincones más confusos.

Si no está interesado en el código fuente de PostgreSQL y su funcionamiento interno, puede dejar de leer ahora.

reenvío

El tema de hoy es el término “resjunk”, que se refiere a resjunk atributo de la lista de objetivos. Verá este término en todo el planificador y reescritor, generalmente como conocimiento asumido. El nombre no es muy útil.

volver a enviar las columnas se describen en src/backend/executor/execJunk.c , donde hay un comentario moderadamente detallado. Sin embargo, en realidad no explica las ideas generales.

El concepto es que, a veces, PostgreSQL necesita realizar un seguimiento de la información por tupla que no forma parte del resultado de la consulta. Puede ser una clave de clasificación que no forma parte de la lista de selección, un resultado intermedio de una subconsulta que se usa como filtro y luego se descarta, o puede ser una columna interna como ctid que no está expuesto a los usuarios.

Los nodos del plan tienen listas de destino:estas son listas de las columnas generadas por ese nodo del plan. Para una simple prueba SELECT a, b FROM las columnas a y b aparecerá en la lista de destino del nodo del plan index o seqscan para la consulta. Puede observar esto usted mismo habilitando el registro del plan, según el siguiente resultado recortado:

regress=> CREATE TABLE 
regress=> SET enable_print_plan = on;
regress=> SET client_min_messages = debug;
regress=> SELECT a, b FROM test;
LOG:  plan:
DETAIL:     {PLANNEDSTMT 
   :commandType 1 
   :queryId 0 
   ....
   :planTree 
      {SEQSCAN 
      :startup_cost 0.00 
      :total_cost 29.40 
      :plan_rows 1940 
      :plan_width 12 
      :targetlist (
         {TARGETENTRY 
         :expr 
            {VAR 
            :varno 1 
            :varattno 1 
            ...
            :location 7
            }
         ...
         :resjunk false
         }
         {TARGETENTRY 
         :expr 
            {VAR 
            :varno 1 
            :varattno 2 
            ...
            :location 10
            }
         ....
         :resjunk false
         }
      )
      :qual  
      :lefttree  
      :righttree  
      :initPlan  
      :extParam (b)
      :allParam (b)
      :scanrelid 1
      }
   :rtable (
      {RTE 
      :alias  
      :eref 
         {ALIAS 
         :aliasname test 
         :colnames ("a" "b")
         }
      ...
      :selectedCols (b 9 10)
      :modifiedCols (b)
      }
   )
   ....
   }

Ese es el plan detallado para:

                       QUERY PLAN                       
--------------------------------------------------------
 Seq Scan on test  (cost=0.00..29.40 rows=1940 width=8)

En él verás que el SELECT tiene dos entradas en la lista de objetivos, una para cada columna. Tampoco resjunk ya que ambos son generados por la consulta.

¿Qué pasa si agregamos una ordenación por columna c? , que no está en SELECT -list, veremos una nueva columna agregada a la lista de destino y marcada como basura:

regress=> SELECT a, b FROM test ORDER BY c;
LOG:  plan:
DETAIL:     {PLANNEDSTMT 
   :commandType 1 
   ....
   :planTree 
      {SORT 
      ....
      :targetlist (
         {TARGETENTRY 
         :expr 
            {VAR 
            :varno 65001 
            :varattno 1
            ...
            }
         :resno 1 
         :resname a 
         ...
         :resjunk false
         }
         {TARGETENTRY 
         :expr 
            {VAR 
            :varno 65001 
            :varattno 2 
            ...
            }
         :resno 2 
         :resname b 
         ....
         :resjunk false
         }
         {TARGETENTRY 
         :expr 
            {VAR 
            :varno 65001 
            :varattno 3 
            ...
            }
         :resno 3 
         :resname  
         ....
         :resjunk true
         }
      )
      :qual  
      :lefttree 
         {SEQSCAN 
         ...
         :targetlist (
            {TARGETENTRY 
            :expr 
               {VAR 
               :varno 1 
               :varattno 1 
               ...
               }
            :resno 1 
            ...
            :resjunk false
            }
            {TARGETENTRY 
            :expr 
               {VAR 
               :varno 1 
               :varattno 2 
               ...
               }
            :resno 2 
            ...
            :resjunk false
            }
            {TARGETENTRY 
            :expr 
               {VAR 
               :varno 1 
               :varattno 3 
               ...
               }
            :resno 3
            ...
            :resjunk true
            }
         )
         ....
      }
   :rtable (
      {RTE 
      :alias  
      :eref 
         {ALIAS 
         :aliasname test 
         :colnames ("a" "b" "c")
         }
      ....
      :selectedCols (b 9 10 11)
      :modifiedCols (b)
      }
   )
   ....
   }

para el plan de consulta:

                          QUERY PLAN                           
---------------------------------------------------------------
 Sort  (cost=135.34..140.19 rows=1940 width=12)
   Sort Key: c
   ->  Seq Scan on test  (cost=0.00..29.40 rows=1940 width=12)
(3 rows)

Así que c está marcado como rechazar porque es una clave de ordenación que no forma parte del resultado final del plan.

También verá ctid marcado como rechazar en ACTUALIZAR y ELIMINAR planes por razones similares:la parte de lectura del plan obtiene las filas para modificar y sus ID de tupla; estos se colocan en una MODIFYTABLE más externa nodo del plan que actualiza la fila para marcarla como eliminada y, si es una actualización, inserta una nueva versión de la fila.

La investigación que condujo a estos resultados ha recibido financiación del Séptimo Programa Marco de la Unión Europea (FP7/2007-2013) bajo el acuerdo de subvención n° 318633