2016-12-16 120 views
2

我有以下查詢:上Postgres SQL查詢忽略索引?

SELECT a.id, a.col2, b.id, b.col2, c.id, c.col2 
FROM a 
    JOIN b on b.fk_a_id = a.id 
    JOIN c on c.fk_a_id = a.id 
    INNER JOIN d on d.fk_c_id = c.id 
WHERE a.owner_id NOT IN (1, 3, 100, 41) 
GROUP BY a.id, b.id, c.id 
ORDER BY a.created_date desc 
LIMIT __ OFFSET __ 

指標: a.id,a.owner_id,b.id,c.id

然而,沒有我的指標正在此查詢使用。我有另一個類似的查詢,其中有一個額外的表連接,正如我所期望的那樣使用索引關於爲什麼這個查詢沒有使用索引的任何想法?

編輯包括解釋:

"Limit (cost=7.88..7.89 rows=4 width=243) (actual time=175.824..175.825 rows=10 loops=1)" 
" -> Sort (cost=7.88..7.89 rows=4 width=243) (actual time=175.822..175.822 rows=10 loops=1)" 
"  Sort Key: a.created_date DESC" 
"  Sort Method: quicksort Memory: 27kB" 
"  -> HashAggregate (cost=7.78..7.84 rows=4 width=243) (actual time=175.771..175.778 rows=10 loops=1)" 
"    Group Key: a.id, b.id, c.id" 
"    -> Hash Join (cost=5.12..7.75 rows=4 width=243) (actual time=0.072..0.099 rows=20 loops=1)" 
"     Hash Cond: (a.id = b.fk_a_id)" 
"     -> Hash Join (cost=2.85..5.43 rows=4 width=163) (actual time=0.041..0.063 rows=20 loops=1)" 
"       Hash Cond: (a.id = d.fk_a_id)" 
"       -> Seq Scan on table a (cost=0.00..2.44 rows=27 width=126) (actual time=0.008..0.025 rows=28 loops=1)" 
"        Filter: (owner_id <> ALL ('{1,3,100,41}'::bigint[]))" 
"        Rows Removed by Filter: 1" 
"       -> Hash (cost=2.76..2.76 rows=7 width=53) (actual time=0.027..0.027 rows=3 loops=1)" 
"        Buckets: 1024 Batches: 1 Memory Usage: 9kB" 
"        -> Hash Join (cost=1.16..2.76 rows=7 width=53) (actual time=0.019..0.023 rows=3 loops=1)" 
"          Hash Cond: (c.id = d.fk_c_id)" 
"          -> Seq Scan on table c (cost=0.00..1.39 rows=39 width=45) (actual time=0.002..0.004 rows=39 loops=1)" 
"          -> Hash (cost=1.07..1.07 rows=7 width=8) (actual time=0.007..0.007 rows=3 loops=1)" 
"           Buckets: 1024 Batches: 1 Memory Usage: 9kB" 
"           -> Seq Scan on table d (cost=0.00..1.07 rows=7 width=8) (actual time=0.003..0.004 rows=3 loops=1)" 
"     -> Hash (cost=2.12..2.12 rows=12 width=88) (actual time=0.022..0.022 rows=12 loops=1)" 
"       Buckets: 1024 Batches: 1 Memory Usage: 9kB" 
"       -> Seq Scan on table b (cost=0.00..2.12 rows=12 width=88) (actual time=0.005..0.013 rows=12 loops=1)" 
"Planning time: 210.946 ms" 
"Execution time: 175.987 ms" 
+0

'EXPLAIN'查詢併發布結果。 – Stavr00

+2

哦,我知道爲什麼! Postgres優化器認爲全表掃描是執行查詢的最高性能方式。爲什麼它認爲,我不知道。優化器可以訪問大量我沒有的信息。 。 。表格大小,估計分佈,涉及的確切數據類型等等。 –

+0

我剛剛編輯,包括EXPLAIN – Dayna

回答

0

有ONY上表A中的標準:WHERE a.owner_id NOT IN (1, 3, 100, 41)。對我來說,聽起來像「選擇除了幾個以外的所有記錄」。通過索引讀取所有記錄並且仍然以大部分記錄結束將是很多工作。簡單地閱讀表格並即時忽略一些記錄的速度會更快。

然後,對於那些許多許多A記錄,我們可能會匹配很多很多的B,C和D記錄。同樣,我們最好不要讀索引加上大部分表數據,而只是把數據放入桶中(散列連接)。這似乎最快。

因此,優化器選擇不爲查詢使用索引似乎是一個好主意。實踐證明,它是做好:-)

我看到索引,以加快這唯一的辦法將覆蓋索引,即包含所有需要的列的索引:

  • 一個(owner_id,ID, CREATED_DATE,COL2)
  • b(fk_a_id,ID,COL2)
  • C(fk_a_id,ID,COL2)
  • d(fk_c_id)

然後我們止跌不必閱讀索引加上表格,而是僅索引。

順便說一句:因爲你不從D中選擇任何東西,你要麼檢查是否存在,那麼你應該使用EXISTSIN而不是加入以提高可讀性。或者你不知道;那麼你可以從你的查詢中完全消除它。

+0

我對此很新。我在我正在測試的本地數據庫上執行VACUUM,並且索引正在使用中? – Dayna

0

索引用於(快速)在「多行」中查找「少數幾行」。這不是一個神奇的銀彈,讓一切變得更快。

表中沒有足夠的行來使索引查找有效。而且你幾乎獲得了所有這些,而不僅僅是一小部分。

如果你看看這個計劃,你會發現實際的數據檢索永遠不會超過0.1毫秒。 (這是毫秒秒的十分之一)。對於表cd的Seq掃描僅需要0.004ms - 沒有索引只會加速4行。

這樣做通過索引與隨機I/O爲20或30行肯定會更慢。根據表中列的數量,即使「最大」表的39行可能存儲在一個塊中 - 這意味着要讀取所有行,數據庫只需要在使用Seq時執行單個I/O操作掃描。

計劃的最慢的部分是HashAggregate讀取數據的,所以不使用索引的選擇似乎是正確的。

那是什麼樣的硬件?合計20行的175毫秒似乎非常慢 - 計劃時間爲210毫秒。對於這樣一個簡單的陳述,計劃時間應該更像1ms。