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

  • O Apicultor e o Mapa Cognitivo

    Eu assisti recentemente O apicultorum thriller de vingança estrelado por Jason Statham como Adam Clay, um agente aposentado de uma poderosa organização clandestina conhecida como “Apicultores” que existe além da CIA. A trama começa quando a senhoria e amiga idosa de Clay, Eloise Parker, é vítima de um sofisticado golpe de phishing que drena suas…

  • Відсоток позитивних результатів тесту (позитивність) 23.07.20

    Відсоток тестів на віруси, які показали позитивні результати («позитивні»), є показником відсотка від загальної кількості інфекцій, які виявляються за допомогою тестування. Чим вищий позитивний результат, тим нижчий відсоток загальних інфекцій, які виявляються, усі інші фактори залишаються незмінними. Більшість станів починали з високого рівня позитивності (у деяких випадках 30-40%), а багато з них знизилися до 5%…

  • 不,AI不是泡沫

    而是聽論點 有一個流行的論點是這樣的: 人1:“ AI是泡沫。” 人2:“不,不是。氣泡是當事實被炒作的時候,事實證明是錯誤的。” 人1:“不,這只是意味著它像.com Bubble一樣充氣。我們仍然有互聯網嗎?” 這 聽起來 就像一個很好的論點,但我認為不是。 在野外這個論點的完美例子。 從最近的LinkedIn互動中 請注意,我們在這裡使用“氣泡”一詞。這意味著什麼? 在很多情況下,我會同意他們的看法。 認為AI是泡沫的人 可以 說: 它是“過熱的”,或者 它是“誇大的” 或任何其他指示明顯炒作的術語 但是他們不使用這些術語。他們說的是“泡泡”。 那麼,這實際上是什麼意思? 泡沫的最單一特徵是什麼?喜歡…在現實生活中。 氣泡彈出。 這就是氣泡的整個事情。當您進入大自然時,您會看到膨脹和收縮和生存的氣泡嗎? 不,他們彈出。這就像他們的主要事情。 這是我提供的有關氣泡的清潔解釋以及是否適用任何東西。 泡沫是一種虛假的信念,其中大量投資將很快被證明是錯誤的。 .com的東西是一個泡沫,它彈出了。 但是錯誤的信念不是 Internet™ 會炸毀並流行。那就是困惑的地方。 .com泡沫是錯誤的信念,即如果您將掙扎的業務帶到互聯網上,您將立即變得富有。 那 是彈出的信念。 因此,整個AI泡沫討論的技巧是找到虛假的主張。 什麼是 錯誤的 人們對人們擁有的AI的信念,他們會過度投資,這會追溯地被視為愚蠢之後嗎? 儘管並非所有這些投資都崩潰了。 是否就像每個人都相信您是否只是“添加AI”的示例,它們會立即成為百萬富翁?或許。也許一兩年。但是這些人中的大多數已經與現實相撞。 該泡沫在2023/2024中大部分都彈出。 兩個Marcusii。 不,我認為大多數反伊人喜歡馬庫斯(Hutchins和Gary Marcus) 實際上 視為泡泡蛋白,是以下位置(我持有的位置,順便說一句): 現代AI(或AI代或您想稱之為的任何東西)將導致業務完成方式的基本變化 它將在未來3 – 10年內取代數千萬的知識工作者 它將迫使我們不僅重新考慮當前的勞動力經濟,而且重新考慮人類工作和實用性的整個概念 如果您與認為AI是泡沫的人交談,這就是他們通常的意思。 因此,問題並不是大量的星空的AI投資者是否不知道發生了什麼,這會損失金錢。它已經發生了,現在正在發生,並且將繼續。這將是過於過早或其他不明智的投資的血液。每個人都知道。那不是真正的論點。 辯論是關於這項技術是否將改變商業,經濟和社會。…

  • 獎勵應用程式 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 公關經理…

  • JS Bulmaca

    JS Bulmaca ipucunun = değerlendirme(cevap) olduğu bir bulmaca JS Crossword’a hoş geldiniz! Her ipucu, cevabının bir JS değerlendirmesidir – örneğin, 7 ile çözülebilir 3+4 Ve (object Object) ile çözülebilir ()+{}. Bu bulmaca daha az bilinen ve lanetli bazı JS özelliklerini kullanıyor, bu yüzden onu zaten JavaScript’e biraz aşina olan kişilere tavsiye ederim. Aşağıdaki karakterleri kullanmanıza…

Deixe um comentário

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