2014-04-22 83 views
2

任何人都可以解釋爲什麼PostgreSQL的工作這麼:PostgreSQL如何執行查詢?

如果我執行這個查詢

SELECT 
* 
FROM project_archive_doc as PAD, project_archive_doc as PAD2 
WHERE 
PAD.id = PAD2.id 

這將是簡單JOINEXPLAIN會是這樣的:

Hash Join (cost=6.85..13.91 rows=171 width=150) 
    Hash Cond: (pad.id = pad2.id) 
    -> Seq Scan on project_archive_doc pad (cost=0.00..4.71 rows=171 width=75) 
    -> Hash (cost=4.71..4.71 rows=171 width=75) 
     -> Seq Scan on project_archive_doc pad2 (cost=0.00..4.71 rows=171 width=75) 

但是,如果我將執行此查詢:

SELECT * 
FROM project_archive_doc as PAD 
WHERE 
PAD.id = (
      SELECT PAD2.id 
      FROM project_archive_doc as PAD2 
      WHERE 
      PAD2.project_id = PAD.project_id 
      ORDER BY PAD2.created_at 
      LIMIT 1) 

不會有聯接和EXPLAIN樣子:

Seq Scan on project_archive_doc pad (cost=0.00..886.22 rows=1 width=75)" 
    Filter: (id = (SubPlan 1)) 
    SubPlan 1 
    -> Limit (cost=5.15..5.15 rows=1 width=8) 
      -> Sort (cost=5.15..5.15 rows=1 width=8) 
       Sort Key: pad2.created_at 
       -> Seq Scan on project_archive_doc pad2 (cost=0.00..5.14 rows=1 width=8) 
         Filter: (project_id = pad.project_id) 

爲什麼是這樣,是否有關於這個的任何文件或物品?

+1

附加where子句'PAD2.project_id = PAD.project_id'加上'LIMIT 1'使優化器相信很少的行將滿足條件(估計=一行),所以它選擇exaxtly提取這一行。如果桌子變大,情況可能會改變。那就是:計劃可能會改變,結果將永遠是一排。優化器(大部分)總是正確的... – joop

+0

@joop,「結果將永遠是一行」你只談論子查詢嗎?因爲整個查詢返回多個行。 –

+1

@DenisNikanorov這些查詢完全不同。你爲什麼要比較它們? –

回答

2

沒有表格定義和數據,很難具體針對這種情況。一般來說,PostgreSQL就像大多數SQL數據庫一樣,它不會將SQL作爲查詢如何執行的分步程序。這更像是描述你想要的結果,以及你希望數據庫如何產生結果的暗示。

PostgreSQL可以自由地執行查詢,但只要它產生你想要的結果,它可以最有效地這樣做。

通常它有幾個關於如何產生特定結果的選擇。它會根據成本估算來選擇它們。

它也可以「理解」編寫特定查詢的幾種不同方式是等價的,並將其轉換爲另一種效率更高的方法。例如,它可以將IN (SELECT ...)轉換爲聯接,因爲它可以證明它們是等效的。

但是,對查詢有時顯然很小的更改會從根本上改變其含義,並限制PostgreSQL可以進行的優化/轉換。在子查詢內部添加LIMITOFFSET可防止PostgreSQL從變平,即將其與外部查詢相結合,將其轉換爲連接。它還可以防止PostgreSQL在子查詢和外部查詢之間移動WHERE子句條目,因爲這會改變查詢的含義。如果沒有LIMITOFFSET子句,它可以執行這兩個操作,因爲它們不會更改查詢的含義。

還有some info on the planner here