PostgreSQL 未在 FULL OUTER JOIN 中使用索引
我有這些表我想做一個
FULL OUTER JOIN
。它們都有一個索引(ts_minute, user_id, campaign_id, host_id)
(與連接條件匹配)。在以下查詢中,如果我FULL OUTER
從查詢中刪除,它的執行速度會快 10,000 倍,因為它使用索引(使用 確認EXPLAIN SELECT ...
)。問題是,我需要FULL OUTER
.select user_id, campaign_id, sum(i.cost), sum(b.bids_internal), sum(b.eligible_requests) from impr_summary_test i join bid_summary_test b USING (ts_minute, user_id, campaign_id, host_id) where ts_minute > now() - interval '5 min' group by 1, 2 order by 1,2;
也有索引
(ts_minute)
。如果能使用這個索引就好了。慢速情況下返回的行數約為 330,快速情況下返回的行數約為 220。Postgres 9.3。
我已經嘗試將其重寫為兩個單獨的子查詢,每個子查詢都有自己的(相同的)
WHERE
子句,然後JOIN
‘ing 那些結果,這確實加快了速度,但基本INNER JOIN
情況仍然比 re- 快 5 倍寫。如何通過讓它使用索引來加快速度?
bid_summary_test 中的行數:8,292,673
bid_summary_test 中匹配謂詞的行數
ts_minute > now() - interval '5 min'
:28,849impr_summary_test 中的行數:2,523,534
impr_summary_test 中匹配謂詞的行數
ts_minute > now() - interval '5 min'
:11,081
當組合兩個表時,
FULL OUTER JOIN
所有 行都包含在結果中。通常,對連接列使用索引是沒有意義的。這就是為什麼嘗試打開索引(ts_minute, user_id, campaign_id, host_id)
將毫無結果的原因。恰好第一列也適合相關謂詞 onts_minute
。見下文。該查詢還返回顯著更少的行,
[INNER] JOIN
這解釋了一些性能差異 - 但肯定不是因素 10.000。您更新的資訊確認返回的行數較少(220 對 330),但這還不是全部。在聚合之前,差異可能會大得多。您的謂詞
ts_minute
是索引支持的更好候選者。有兩個索引似乎適用於謂詞ts_minute > now() - interval '5 min'
(關於實際數據類型的未決資訊)。但是外觀是騙人的:在ts_minute
之後的結果列FULL [OUTER] JOIN
是兩個基礎表中的列的組合。它就像一個表達式,它是**不可分割**的,並且不能ts_minute
在基礎表上使用索引。您必須在允許索引支持之前應用謂詞。
FULL [OUTER] JOIN
這就是您在添加的測試中已經通過兩個單獨的子查詢偶然發現的內容。EXPLAIN
如果您檢查輸出,您會發現(僅)索引掃描或點陣圖索引掃描。由於 you
GROUP BY user_id, campaign_id
,是否在此查詢中添加列和連接條件是**無關緊要的。**僅對條件是必需的。ts_minute``host_id``ts_minute``WHERE
SELECT user_id, campaign_id , i.sum_cost, b.sum_bids_internal, b.sum_eligible_requests FROM ( SELECT user_id, campaign_id , sum(cost) AS sum_cost FROM impr_summary_test WHERE ts_minute > now() - interval '5 min' GROUP BY 1, 2 ) i FULL JOIN ( SELECT user_id, campaign_id , sum(bids_internal) AS sum_bids_internal , sum(eligible_requests) AS sum_eligible_requests FROM bid_summary_test WHERE ts_minute > now() - interval '5 min' GROUP BY 1, 2 ) b USING (user_id, campaign_id) ORDER BY 1,2;
假設每個表中只有很小百分比的行位於“最後 5 分鐘”內,那麼
ts_minute
兩個表中的索引應該會非常快。如果您的寫入模式並
autovacuum
允許僅索引掃描,則這些索引將為您提供最佳性能:CREATE INDEX ON impr_summary_test (ts_minute, user_id, campaign_id, cost); CREATE INDEX ON bid_summary_test (ts_minute, user_id, campaign_id, bids_internal, eligible_requests);
權衡高度專業化指標的成本和收益。