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

  • تقييمات الاستعداد المفتوح للدولة ليوم 27/8/20

    تُظهر هذه التقييمات بيانات على مستوى الولاية يمكن أن تساعد في تقييم مدى استعداد كل ولاية لإعادة فتحها. ألاسكا • ألاباما • أركنساس • أريزونا • كاليفورنيا • كولورادو • كونيتيكت • مقاطعة كولومبيا • ديلاوير • فلوريدا • جورجيا • هاواي • أيوا • أيداهو • إلينوي • إنديانا • كانساس • كنتاكي •…

  • 獎勵應用程式 Freecash 是如何透過詐騙登上應用程式商店榜首的

    一款名為 Freecash 的資料收集應用程式似乎欺騙了用戶,因為它迅速上升到 App Store 和 Google Play 的排行榜前列,並在該排行榜上停留了數月,直到最近被禁止。 如果您今年使用過 TikTok,您很可能遇到過 Freecash 的廣告。該應用程式被宣傳為一種只需滾動 TikTok 就能賺錢的方式,並在近幾個月躍居應用程式商店榜首,在美國應用程式商店中排名第二。 事實上,根據網路安全公司 Malwarebytes 稱,Freecash 向用戶付費玩手機遊戲,同時收集大量敏感資料。 Malwarebytes 的一份報告指出,該應用程式可能會收集有關用戶種族、宗教、性生活、性取向、健康和其他生物識別信息,並補充說該應用程式本質上是一個數據經紀人,旨在將遊戲開發商與願意安裝並花錢購買手機遊戲的用戶相匹配。 Freecash 上推廣的遊戲包括《大富翁圍棋》和《迪士尼紙牌》等。 《連線》1 月的一份報告發現 Freecash 使用欺騙性行銷手段並誘使用戶在遊戲中花錢,作為回應,TikTok 撤下了 Freecash 的一些廣告,稱該公司違反了有關財務虛假陳述的規定。當時,自由現金否認參與其中,稱這些廣告是由第三方附屬公司而非其自身製作的。 週一,在 TechCrunch 聯繫蘋果公司徵求意見後,蘋果將 Freecash 從其 App Store 下架。截至週一下午,該應用程式仍在 Google Play 商店中列出。 (此後已被刪除)。 螢幕截圖圖片來源:自由現金網站截圖 當聯繫到擁有 Freecash 的德國公司 Almedia 發表評論時,該公司否認了為其平台帶來人為流量或使用欺騙性行銷技術的指控。 Techcrunch 活動 加州舊金山 | 2026年10月13-15日 Almedia 公關經理…

  • ਹੁਣ ਮੇਰਾ ਮੌਕਾ ਹੈ ਤੁਹਾਨੂੰ ਇਹ ਦੱਸਣ ਦਾ ਕਿ ਮੈਂ ਹਾਰਵਰਡ ਗਿਆ ਸੀ

    ਮੂਲ ਤੱਥ: ਮੈਂ ਹਾਰਵਰਡ ਤੋਂ ਪੀਐਚਡੀ ਕੀਤੀ ਹੈ। ਨਾਲ ਹੀ, ਇੱਕ ਮਾਸਟਰ ਡਿਗਰੀ. ਓਹ, ਅਤੇ ਤਰੀਕੇ ਨਾਲ, ਇਹ ਇੱਕ ਡਬਲ ਪੀਐਚਡੀ ਦੀ ਤਰ੍ਹਾਂ ਹੈ ਕਿਉਂਕਿ ਪ੍ਰੋਗਰਾਮ ਮੈਂ ਦੋ ਵੱਖ-ਵੱਖ ਖੇਤਰਾਂ ਵਿੱਚ ਸੰਯੁਕਤ ਸੀ, ਹਰੇਕ (ਮੇਰੀ ਪਸੰਦ ਦੀ) ਵਿੱਚੋਂ ਕਈ ਲੋੜਾਂ ਵਿੱਚੋਂ ਸਿਰਫ ਇੱਕ ਨੂੰ ਹਟਾ ਰਿਹਾ ਸੀ, ਪਰ ਮੈਂ ਅਸਲ ਵਿੱਚ ਸਾਰੀਆਂ ਜ਼ਰੂਰਤਾਂ ਨੂੰ ਪੂਰਾ…

  • Poza mądrością

    Październik 2021 Gdybyś zapytał ludzi, co jest specjalnego w Einsteinie, większość odpowiedziałaby, że był naprawdę mądry. Nawet ci, którzy próbowali udzielić Ci bardziej wyrafinowanej odpowiedzi, prawdopodobnie pomyśleliby o tym jako pierwsi. Jeszcze kilka lat temu sam udzieliłbym tej samej odpowiedzi. Ale nie to było wyjątkowe w Einsteinie. To, co go wyróżniało, to to, że miał…

Deixe um comentário

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