Opérations PostgreSQL que vous ne pouvez pas EXPLIQUER · Felix Geisendörfer

Opérations PostgreSQL que vous ne pouvez pas EXPLIQUER · Felix Geisendörfer


Opérations PostgreSQL que vous ne pouvez pas EXPLIQUER · Felix Geisendörfer

Publié :

Je m’intéresse actuellement aux composants internes de PostgreSQL pendant mon temps libre, notamment en essayant de comprendre le planificateur et l’exécuteur de requêtes. C’est une expérience profondément humiliante, mais je suis parfois ravi de pouvoir répondre à des questions simples sur lesquelles je fais des recherches.

L’une de ces questions est de savoir comment PostgreSQL s’exécute ORDER BY clauses à l’intérieur des expressions agrégées.

# CREATE TABLE foo AS
SELECT * FROM generate_series(1, 3) i;
SELECT 3
# SELECT * FROM foo;
 i
---
 1
 2
 3
(3 rows)

Considérons un tableau simple contenant 3 lignes d’une colonne int allant de 1 à 3 :

Supposons maintenant que nous souhaitions convertir ces lignes en un tableau json. Cela peut être accompli en utilisant la fonction d’agrégation json_agg :

# SELECT json_agg(i) FROM foo;
 json_agg
-----------
 (1, 2, 3)
(1 row)

Mais que se passe-t-il si nous voulons classer les éléments du tableau par ordre décroissant ? Pas de problème, nous pouvons simplement utiliser le support order-by-clause disponible pour toutes les expressions agrégées :

# SELECT json_agg(i ORDER BY i DESC) FROM foo;
 json_agg
-----------
 (3, 2, 1)
(1 row)

Si vous êtes comme moi, vous imaginerez probablement le EXPLAIN sortie pour cette requête devant contenir trois nœuds : un Seq Scanun Sortet un Aggregate. Cependant, lorsque nous courons EXPLAINil s’avère qu’il n’y a pas Sort nœud.

# EXPLAIN SELECT json_agg(i ORDER BY i DESC) FROM foo;
                         QUERY PLAN
-------------------------------------------------------------
 Aggregate  (cost=41.88..41.89 rows=1 width=32)
   ->  Seq Scan on foo  (cost=0.00..35.50 rows=2550 width=4)
(2 rows)

En fait, le plan reste même inchangé même si nous modifions l’ordre de tri ou supprimons entièrement la clause :

# EXPLAIN SELECT json_agg(i ORDER BY i ASC) FROM foo;
                         QUERY PLAN
-------------------------------------------------------------
 Aggregate  (cost=41.88..41.89 rows=1 width=32)
   ->  Seq Scan on foo  (cost=0.00..35.50 rows=2550 width=4)
(2 rows)

# EXPLAIN SELECT json_agg(i) FROM foo;
                         QUERY PLAN
-------------------------------------------------------------
 Aggregate  (cost=41.88..41.89 rows=1 width=32)
   ->  Seq Scan on foo  (cost=0.00..35.50 rows=2550 width=4)
(2 rows)

Mais comment est-ce possible ? S’il n’y a pas Sort nœud, comment l’agrégat effectue-t-il son tri ?

Eh bien, il s’avère que les nœuds du plan agrégé peuvent effectuer leur propre tri. Ces types n’apparaissent pas explicitement dans EXPLAINmais nous pouvons les tracer en utilisant l’option développeur trace_sort :

# SET trace_sort=true;
SET
# SET client_min_messages='log';
SET
# SELECT json_agg(i ORDER BY i DESC) FROM foo;
LOG:  begin datum sort: workMem = 4096, randomAccess = f
LOG:  performsort starting: CPU 0.00s/0.00u sec elapsed 0.00 sec
LOG:  performsort done: CPU 0.00s/0.00u sec elapsed 0.00 sec
LOG:  internal sort ended, 25 KB used: CPU 0.00s/0.00u sec elapsed 0.00 sec
 json_agg
-----------
 (3, 2, 1)
(1 row)

Une autre façon de voir que le tri fait partie du plan est d’utiliser l’option debug_print_plan, mais le résultat n’est pas pour les âmes sensibles. Plus précisément, vous devez rechercher le :aggorder champ ci-dessous :

# SET debug_print_plan=true;
SET
# SELECT json_agg(i ORDER BY i DESC) FROM foo;
LOG:  plan:
DETAIL:     {PLANNEDSTMT
   :commandType 1
   :queryId 0
   :hasReturning false
   :hasModifyingCTE false
   :canSetTag true
   :transientPlan false
   :dependsOnRole false
   :parallelModeNeeded false
   :planTree
      {AGG
      :startup_cost 41.88
      :total_cost 41.89
      :plan_rows 1
      :plan_width 32
      :parallel_aware false
      :plan_node_id 0
      :targetlist (
         {TARGETENTRY
         :expr
            {AGGREF
            :aggfnoid 3175
            :aggtype 114
            :aggcollid 0
            :inputcollid 0
            :aggtranstype 2281
            :aggargtypes (o 23)
            :aggdirectargs <>
            :args (
               {TARGETENTRY
               :expr
                  {VAR
                  :varno 65001
                  :varattno 1
                  :vartype 23
                  :vartypmod -1
                  :varcollid 0
                  :varlevelsup 0
                  :varnoold 1
                  :varoattno 1
                  :location 16
                  }
               :resno 1
               :resname <>
               :ressortgroupref 1
               :resorigtbl 0
               :resorigcol 0
               :resjunk false
               }
            )
            :aggorder (
               {SORTGROUPCLAUSE
               :tleSortGroupRef 1
               :eqop 96
               :sortop 521
               :nulls_first true
               :hashable true
               }
            )
            :aggdistinct <>
            :aggfilter <>
            :aggstar false
            :aggvariadic false
            :aggkind n
            :agglevelsup 0
            :aggsplit 0
            :location 7
            }
         :resno 1
         :resname json_agg
         :ressortgroupref 0
         :resorigtbl 0
         :resorigcol 0
         :resjunk false
         }
      )
      :qual <>
      :lefttree
         {SEQSCAN
         :startup_cost 0.00
         :total_cost 35.50
         :plan_rows 2550
         :plan_width 4
         :parallel_aware false
         :plan_node_id 1
         :targetlist (
            {TARGETENTRY
            :expr
               {VAR
               :varno 1
               :varattno 1
               :vartype 23
               :vartypmod -1
               :varcollid 0
               :varlevelsup 0
               :varnoold 1
               :varoattno 1
               :location -1
               }
            :resno 1
            :resname <>
            :ressortgroupref 0
            :resorigtbl 0
            :resorigcol 0
            :resjunk false
            }
         )
         :qual <>
         :lefttree <>
         :righttree <>
         :initPlan <>
         :extParam (b)
         :allParam (b)
         :scanrelid 1
         }
      :righttree <>
      :initPlan <>
      :extParam (b)
      :allParam (b)
      :aggstrategy 0
      :aggsplit 0
      :numCols 0
      :grpColIdx
      :grpOperators
      :numGroups 1
      :aggParams (b)
      :groupingSets <>
      :chain <>
      }
   :rtable (
      {RTE
      :alias <>
      :eref
         {ALIAS
         :aliasname foo
         :colnames ("i")
         }
      :rtekind 0
      :relid 404407
      :relkind r
      :tablesample <>
      :lateral false
      :inh false
      :inFromCl true
      :requiredPerms 2
      :checkAsUser 0
      :selectedCols (b 9)
      :insertedCols (b)
      :updatedCols (b)
      :securityQuals <>
      }
   )
   :resultRelations <>
   :utilityStmt <>
   :subplans <>
   :rewindPlanIDs (b)
   :rowMarks <>
   :relationOids (o 404407)
   :invalItems <>
   :nParamExec 0
   }

LOG:  begin datum sort: workMem = 4096, randomAccess = f
LOG:  performsort starting: CPU 0.00s/0.00u sec elapsed 0.00 sec
LOG:  performsort done: CPU 0.00s/0.00u sec elapsed 0.00 sec
LOG:  internal sort ended, 25 KB used: CPU 0.00s/0.00u sec elapsed 0.00 sec
 json_agg
-----------
 (3, 2, 1)
(1 row)

En conclusion : Tandis que EXPLAIN est une arme puissante pour ceux qui cherchent à comprendre les performances des requêtes, vous devez être conscient du fait qu’il y a des choses que vous ne pouvez pas EXPLAIN :).

La recherche pour cet article a été effectuée à l’aide de PostgreSQL 9.6.3 et LLDB, mais devrait également s’appliquer aux versions récentes ainsi qu’au prochain PostgreSQL 10.

# SELECT version();
                                                   version
--------------------------------------------------------------------------------------------------------------
 PostgreSQL 9.6.3 on x86_64-apple-darwin14.5.0, compiled by Apple LLVM version 7.0.0 (clang-700.1.76), 64-bit
(1 row)

— Félix Geisendörfer


Abonnez-vous à ce blog via RSS ou E-Mail ou recevez de petites mises à jour de ma part via Gazouillement.





Source link

Postagens Similares

  • Pininfarina B95 Gotham at South OC Cars and Coffee

    {“@context”:”http:\/\/schema.org\/”,”@id”:”https:\/\/johnchow.com\/pininfarina-b95-gotham-at-south-oc-cars-and-coffee\/#arve-youtube-ly7nrl50xju-2″,”type”:”VideoObject”,”embedURL”:”https:\/\/www.youtube-nocookie.com\/embed\/Ly7nRL50XJU?feature=oembed&iv_load_policy=3&modestbranding=1&rel=0&autohide=1&playsinline=0&autoplay=0″} While Batman has the Batmobile, Bruce Wayne has the Pininfarina B95 Gotham. A visionary collaboration between Automobili Pininfarina and Wayne Enterprises to build a car befitting its billionaire CEO. This 1900 hp hypercar transcends mere speed, offering an exhilarating experience of daylight freedom, encased in a luxurious design inspired by the vibrant streets of…

  • Перестаньте объяснять, что это такое

    📅 05 ноября 2025 г. | ⏱️ ~1 минута чтения Вы когда-нибудь искали решение технической проблемы только для того, чтобы получить эссе на 1000 слов о том, в чем дело? Да, я тоже. Вы знаете упражнение. Ты Google «как исправить конфликт Git»и каждый результат занимает пять абзацев, объясняющих, что такое Git. Приятель, я здесь, потому…

  • 用 Go 編寫的 Parrot AR 無人機 2.0​​ 固件 Felix Geisendörfer

    GoDrone – 用 Go 編寫的 Parrot AR 無人機 2.0​​ 固件 · Felix Geisendörfer 發表: 2013 年 12 月 25 日 大家聖誕快樂(或者牛頓聖誕,如果你願意的話)。 今天,我很高興發布我最喜歡的副項目 GoDrone 的第一個版本。 GoDrone 是 Parrot AR Drone 2.0 的免費軟件替代固件。是的,這有望使其成為 Go 垃圾收集器的第一個機器人可視化工具:)。 此時,固件已經足夠好,可以飛行並提供基本的姿態穩定(使用簡單的互補濾波器+PID控制器),所以我真的很想從任何喜歡冒險的AR無人機所有者那裡得到反饋。我為 OSX/Linux/Windows 提供二進制安裝程序: http://www.godrone.io/en/latest/index.html 但您也可以選擇從源安裝。 根據最初的反饋,我很樂意將 GoDrone 變成官方固件的可行替代品,並為機器人軟件的開髮帶來一些新鮮空氣。我特別想展示的是,網絡技術在為機器人提供用戶界面的成本和用戶體驗方面可以與本地移動/桌面應用程序相媲美,而且我還想推廣使用高級語言在 Linux 驅動的機器人中進行固件開發的想法。 如果您有興趣,請確保加入郵件列表/在 IRC 中打個招呼: http://www.godrone.io/en/latest/user/community_support.html ——菲利克斯·蓋森多夫 通過 RSS 或電子郵件訂閱此博客,或者通過以下方式獲取我的小更新 嘰嘰喳喳。 請啟用 JavaScript 以查看…

  • RE: మీ SSG కోసం మీకు పెద్ద సాంకేతికత ఎందుకు అవసరం?

    📅 20 నవంబర్ 2025 | ⏱️ ~1 నిమిషం చదివారు లోరెన్ స్టీఫెన్స్ ద్వారా స్వీయ-హోస్టింగ్ మరియు స్థానిక నిర్మాణాలు వాటి ఆకర్షణను కలిగి ఉన్నప్పటికీ, Netlify వంటి సేవల యొక్క సరళత మరియు సున్నా-నిర్వహణ స్వభావం తరచుగా వాటిని చిన్న వ్యక్తిగత సైట్‌లకు మరింత ఆచరణాత్మక ఎంపికగా మారుస్తాయని లోరెన్ వాదిస్తూ ప్రతిస్పందనను పోస్ట్ చేసారు. పోస్ట్ చదవండి 👉🏻 నేను నిన్న వ్రాసిన సమస్యను పూర్తిగా భిన్నమైన దృక్కోణం నుండి సంప్రదించినందున నేను…

Deixe um comentário

O seu endereço de email não será publicado. Campos obrigatórios marcados com *