sql >> Databáze >  >> RDS >> PostgreSQL

PostgreSQL guts:Co je to „resjunk“?

V současné době se ponořím do analyzátoru PostgreSQL, přepisovače dotazů a plánovače dotazů v rámci práce na zabezpečení na úrovni řádků pro projekt AXLE. Jak jsem si všiml, že existuje skvělá dokumentace k celkové struktuře a toku, ale málo k některým detailům, řekl jsem si, že začnu psát o některých matoucích zákoutích.

Pokud vás zdrojový kód PostgreSQL a jeho vnitřní fungování nezajímá, můžete nyní přestat číst.

resjunk

Dnešním tématem je termín „resjunk“, který odkazuje na resjunk atribut target-list. Tento termín uvidíte v celém plánovači a přepisovači, obvykle jako předpokládanou znalost. Název není příliš užitečný.

resjunk sloupce jsou popsány v src/backend/executor/execJunk.c , kde je středně podrobný komentář. Ve skutečnosti to však nevysvětluje zastřešující myšlenky.

Koncept je, že někdy PostgreSQL potřebuje sledovat informace pro n-tice, které nejsou součástí výstupu dotazu. Může to být klíč řazení, který není součástí výběrového seznamu, mezivýsledek z dílčího dotazu, který je použit jako filtr a poté zahozen, nebo to může být interní sloupec jako ctid která není uživatelům vystavena.

Uzly plánu mají cílové seznamy – to jsou seznamy sloupců vydaných tímto uzlem plánu. Pro jednoduchý SELECT a, b FROM test sloupce a a b se objeví v cílovém seznamu indexu nebo uzlu plánu seqscan pro dotaz. Můžete to sami pozorovat povolením protokolování plánu podle následujícího oříznutého výstupu:

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)
      }
   )
   ....
   }

Toto je podrobný plán pro:

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

V něm uvidíte, že SELECT má dvě položky v cílovém seznamu, jednu pro každý sloupec. Ani resjunk protože oba jsou výstupem dotazu.

Co když přidáme řazení podle sloupce c , který není v SELECT -list, uvidíme nový sloupec přidaný do cílového seznamu a označený jako resjunk:

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)
      }
   )
   ....
   }

pro plán dotazů:

                          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)

Takže c je označeno resjunk protože je to klíč řazení, který není součástí konečného výstupu plánu.

Uvidíte také ctid označeno resjunk v UPDATE a DELETE plány z podobných důvodů – čtená část plánu načte řádky k úpravě a jejich n-ticová ID; tyto jsou vtaženy do nejvzdálenější MODIFYTABLE uzel plánu, který aktualizuje řádek, aby byl označen jako odstraněný, a pokud se jedná o aktualizaci, vloží novou verzi řádku.

Výzkum vedoucí k těmto výsledkům byl financován ze sedmého rámcového programu Evropské unie (FP7/2007-2013) na základě grantové dohody č. 318633


  1. Jak vyhledávací_cesta ovlivňuje rozlišení identifikátoru a aktuální schéma

  2. Funkce pro získání počtu dnů v týdnu mezi dvěma daty kromě svátků

  3. Jak může vaše malá firma těžit z cloud computingu

  4. Formát data MySQL – co potřebujete vědět