[英]Postgresql ORDER BY - choosing right index
有表100 T(user, timestamp,...)
有100毫升+記錄(PostgreSQL 9.1)。
表單的查詢
SELECT *
FROM T
WHERE user='abcd'
ORDER BY timestamp
LIMIT 1
當有大約100000個用戶記錄時,使用timestamp
索引而不是用戶索引。
使用時間戳索引總是會得到較差的結果(20秒以上),因為它最終會掃描所有記錄。 通過更改查詢以使用ORDER BY DATE(timestamp)
來繞過timestamp
索引將導致查詢求助於用戶索引並給出小於100毫秒的結果。
為什么postgresql忽略user
索引並且正在使用timestamp
索引(時間戳索引需要查看所有記錄)? 是否有任何postgresql配置參數可以更改,以使查詢使用用戶名索引本身?
好問題,我剛才解決了這個問題。
你應該在你的統計數據中查看user='abcd'
值的數量,如下所示:
SELECT attname, null_frac, ag_width, n_distinct,
most_common_vals, most_common_freqs, histogram_bounds
FROM pg_stats
WHERE table_name='T';
我的猜測是 - 這個值經常發生,你會在most_common_vals
輸出中找到它。 從most_common_freqs
挑選相同的元素,您將獲得該值的比率,將其乘以總行數(可以從pg_class
獲得)以獲得估計具有'abcd'
值的行數 。
Planner假設所有值都具有線性分布。 實際上,事情當然是不同的。 此外,目前還沒有相關的統計數據 ( 盡管正在朝這個方向開展一些工作 )。
所以,讓我們取user='abcd'
值,在相應的most_common_freqs
條目中具有0.001
比率(每個問題)。 這意味着每1000行會出現一次值(假設為線性分布)。 看來,如果我們以任何方式掃描表格,我們將在大約1000行中擊中我們的user='abcd'
。 聽起來應該快! 計划程序“認為”相同並在timestamp
列上選擇索引。
但事實並非如此。 如果我們假設您的表T
包含用戶活動的日志,並且user='abcd'
在過去3周休假,則這意味着我們必須從timestamp
索引中讀取相當多的行(在我們真正達到我們想要的行之前,我們需要3周的數據。 嗯,你作為DBA知道這一點,但計划者假設線性分布。
您必須欺騙規划人員使用您需要的東西,因為您對數據有更多了解。
在子查詢中使用OFFSET 0
技巧 :
SELECT * FROM ( SELECT * FROM T WHERE user='abcd' OFFSET 0 ) ORDER BY timestamp LIMIT 1;
這個技巧可以保護查詢不被內聯,因此內部部分可以自己執行。
使用CTE
(命名子查詢):
WITH s AS ( SELECT * FROM T WHERE user='abcd' ) SELECT * FROM s ORDER BY timestamp LIMIT 1;
每個文件:
WITH查詢的一個有用屬性是,每次執行父查詢時,它們僅被評估一次 ,即使父查詢或兄弟WITH查詢多次引用它們也是如此。
對countrgated查詢使用count(*)
:
SELECT min(session_id), count(*) -- instead of simply `min(session_id)` FROM T WHERE user='abcd' ORDER BY timestamp LIMIT 1;
這不是真的適用,但我想提一下。
請考慮升級到9.3。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.