PostgreSQL
 sql >> база данни >  >> RDS >> PostgreSQL

PostgreSQL вътрешности:Какво е „resjunk“?

В момента се задълбочавам в анализатора на PostgreSQL, преписването на заявки и планирането на заявки, като част от работата по сигурността на ниво ред за проекта AXLE. Тъй като забелязах, че има страхотна документация за цялостната структура и поток, но не много за някои от детайлите, реших да започна да публикувам за някои от по-объркващите ъгли.

Ако не се интересувате от изходния код на PostgreSQL и неговата вътрешна работа, можете да спрете да четете сега.

изброяване

Днешната тема е терминът „resjunk“, който се отнася до resjunk атрибут на целевия списък. Ще видите този термин в целия плановик и пренаписване, обикновено като предполагаемо знание. Името не е особено полезно.

изхвърляне колоните са описани в src/backend/executor/execJunk.c , където има умерено подробен коментар. Това обаче всъщност не обяснява всеобхватните идеи.

Концепцията е, че понякога PostgreSQL трябва да следи информацията за всеки кортеж, която не е част от изхода на заявката. Може да е ключ за сортиране, който не е част от списъка за избор, междинен резултат от подзаявка, която се използва като филтър, след което се отхвърля, или може да е вътрешна колона като ctid която не е изложена на потребителите.

Възлите на плана имат целеви списъци – това са списъци на колоните, изведени от този възел на плана. За прост тест SELECT a, b FROM колоните a и b ще се появи в целевия списък на възела на index или seqscan план за заявката. Можете сами да наблюдавате това, като активирате записването на плана според следния изрязан изход:

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

Това е подробният план за:

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

В него ще видите, че SELECT има два записа в целевия списък, по един за всяка колона. Нито resjunk тъй като и двете се извеждат от заявката.

Ами ако добавим сортиране по колона c , което не е в SELECT -list, ще видим нова колона, добавена към целевия списък и маркирана като препращане:

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

за плана на заявката:

                          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)

Така че c е маркиран като отпаднала защото това е ключ за сортиране, който не е част от крайния изход на плана.

Ще видите също ctid с маркировка отпаднала в АКТУАЛИЗИРАНЕ и ИЗТРИВАНЕ планове по подобни причини – прочетената част на плана извлича редовете за модифициране и техните идентификатори на кортежи; те се изтеглят в най-външната МОДИФИКАЦИЯ възел на плана, който актуализира реда, за да го маркира като изтрит и, ако е актуализация, вмъква нова версия на реда.

Изследванията, довели до тези резултати, са получили финансиране от Седмата рамкова програма на Европейския съюз (FP7/2007-2013) по споразумение за отпускане на безвъзмездни средства № 318633


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Django, mod_wsgi, psycopg2 Неправилно конфигуриран:Грешка при зареждане на модул psycopg2:Няма модул с име _psycopg

  2. Плъзгаща се средна въз основа на времеви печати в PostgreSQL

  3. Защо функциите PL/pgSQL могат да имат страничен ефект, докато SQL функциите не могат?

  4. Как да получите време за създаване на база данни в PostgreSQL 9.0?

  5. Как мога да променя съществуващата колона като идентичност в PostgreSQL 11.1