2017-04-26 46 views
0

我有如下表選擇主鍵:爲什麼Postgres的喜歡做連續掃描VS索引掃描

create table log 
(
    id bigint default nextval('log_id_seq'::regclass) not null 
     constraint log_pkey 
      primary key, 
    level integer, 
    category varchar(255), 
    log_time timestamp, 
    prefix text, 
    message text 
); 

它包含樣3萬行的。

我比較以下查詢:

EXPLAIN SELECT id 
     FROM log 
     WHERE log_time < now() - INTERVAL '3 month' 
     LIMIT 100000 

這將產生以下計劃:

Limit (cost=0.00..19498.87 rows=100000 width=8) 
    -> Seq Scan on log (cost=0.00..422740.48 rows=2168025 width=8) 
     Filter: (log_time < (now() - '3 mons'::interval)) 

而且相同的查詢與ORDER BY ID指令補充說:

EXPLAIN SELECT id 
     FROM log 
     WHERE log_time < now() - INTERVAL '3 month' 
     ORDER BY id ASC 
     LIMIT 100000 

收益率爲

Limit (cost=0.43..25694.15 rows=100000 width=8) 
    -> Index Scan using log_pkey on log (cost=0.43..557048.28 rows=2168031 width=8) 
     Filter: (log_time < (now() - '3 mons'::interval)) 

我有以下問題:

  • 缺少ORDER BY的指令允許Postgres的不關心行的順序。他們也可以交付排序。爲什麼它不使用沒有ORDER BY的索引?

    • Postgres如何在這樣的查詢中首先使用索引? WHERE查詢的子句包含非索引列,並且要讀取該列,將需要進行順序數據庫掃描,但帶有ORDER BY的查詢不指示該查詢。
  • Postgres的手冊頁說:

    對於需要掃描表的大部分的查詢,明確的排序是可能的,因爲它需要較少的磁盤I比使用索引快/ O由於以下順序訪問模式

能否請您澄清這個說法我嗎?索引總是有序的。讀取有序結構總是更快,它總是一個順序訪問(至少在頁面掃描方面)比讀取無序數據,然後手動排序。

回答

4

您能否爲我澄清一下這句話?索引總是有序的。讀取有序結構總是更快,它總是一個順序訪問(至少在頁面掃描方面)比讀取無序數據,然後手動排序。

該索引是按順序讀取的,但是,postgres需要後續讀取表中的行。也就是說,在大多數情況下,如果一個索引標識了100行,那麼postgres將需要對該表執行多達100個隨機讀取。

在內部,postgres計劃者權衡順序和隨機讀取不同,隨機讀取通常更昂貴。設置seq_page_costrandom_page_cost確定那些。如果你願意,還有other settings you can view and tinker with,不過我建議你在修改時保持非常保守。

讓我們回到你剛纔的問題:

缺少ORDER BY的指令允許Postgres的不關心行的順序。他們也可以交付排序。爲什麼它不使用沒有ORDER BY的索引?

原因是這樣的。正如你後面提到的那樣,索引不包括約束列,所以使用索引沒有任何意義。相反,計劃者基本上是說:「讀整個表格,找出哪些行符合約束條件,然後按照我們找到的任何順序返回前10萬行」。

排序改變了事情。在這種情況下,計劃者說「我們需要按這個字段進行排序,並且我們有一個已經排序的索引,所以按照索引順序從表中讀取行,檢查約束,直到我們有100000個,並且返回該集合「。

你會注意到,費用估計(如「0.43..25694.15」)是第二個查詢高得多 - 策劃者認爲,這樣做很多是從索引掃描隨機讀取要花費比顯著更多隻需一次閱讀整個表格,無需分類。

希望有幫助,並讓我知道你是否還有其他問題。