2013-04-01 143 views
0

我說的是this feature高效查詢分區大師PostgreSQL表

我有主表:

logstore=# \d history_log 
            Table "public.history_log" 
    Column |   Type   |      
-----------+--------------------------+----------------------------------------------------------- 
id  | bigint     | NOT NULL DEFAULT nextval('history_log__id_seq'::regclass) 
tstamp | timestamp with time zone | NOT NULL DEFAULT now() 
session | character varying(40) | 
action | smallint     | NOT NULL 
userid | integer     | 
urlid  | integer     | 
Indices: 
    "history_log__id_pkey" PRIMARY KEY, btree (id) 
Triggers: 
    insert_history_log_trigger BEFORE INSERT ON history_log FOR EACH ROW EXECUTE PROCEDURE history_log_insert_trigger() 

和一組由TSTAMP列分區子表的:

logstore=# \d history_log_201304 
           Table "public.history_log_201304" 
    Column |   Type   |      
-----------+--------------------------+----------------------------------------------------------- 
id  | bigint     | NOT NULL DEFAULT nextval('history_log__id_seq'::regclass) 
tstamp | timestamp with time zone | NOT NULL DEFAULT now() 
session | character varying(40) | 
action | smallint     | NOT NULL 
userid | integer     | 
urlid  | integer     | 
Indices: 
    "history_log_201304_pkey" PRIMARY KEY, btree (id) 
    "history_log_201304_tstamp" btree (tstamp) 
    "history_log_201304_userid" btree (userid) 
Constraints: 
    "history_log_201304_tstamp_check" CHECK (tstamp >= '2013-04-01 00:00:00+04'::timestamp with time zone AND tstamp < '2013-05-01 00:00:00+04'::timestamp with time zone) 
Inherits: history_log 

那麼,什麼是我的問題 - 當我這樣做已經WHERE條件的制約查詢直接在子表上直接顯示 - 工作速度非常快。

logstore=# EXPLAIN SELECT userid FROM history_log_201304 WHERE tstamp >= (current_date - interval '3 days')::date::timestamptz AND tstamp < current_date::timestamptz AND action = 13; 
                 QUERY PLAN 
------------------------------------------------------------------------------------------------------------------------- 
Index Scan using history_log_201304_tstamp on history_log_201304 (cost=0.01..8.37 rows=1 width=4) 
    Index Cond: ((tstamp >= ((('now'::cstring)::date - '3 days'::interval))::date) AND (tstamp < ('now'::cstring)::date)) 
    Filter: (action = 13) 

但是當我嘗試做同樣的主表 - 它去序列掃描:

logstore=# EXPLAIN SELECT userid FROM history_log WHERE tstamp >= (current_date - interval '3 days')::date::timestamptz AND tstamp < current_date::timestamptz AND action = 13; 
                    QUERY PLAN 

------------------------------------------------------------------------------------------------------------------------------------ 
--------------- 
Result (cost=0.00..253099.82 rows=1353838 width=4) 
    -> Append (cost=0.00..253099.82 rows=1353838 width=4) 
     -> Seq Scan on history_log (cost=0.00..0.00 rows=1 width=4) 
       Filter: ((action = 13) AND (tstamp < ('now'::cstring)::date) AND (tstamp >= ((('now'::cstring)::date - '3 days'::inte 
rval))::date)) 
     -> Index Scan using history_log_201203_tstamp on history_log_201203 history_log (cost=0.01..9.67 rows=1 width=4) 
       Index Cond: ((tstamp >= ((('now'::cstring)::date - '3 days'::interval))::date) AND (tstamp < ('now'::cstring)::date)) 
       Filter: (action = 13) 
     -> Index Scan using history_log_201204_tstamp on history_log_201204 history_log (cost=0.01..9.85 rows=1 width=4) 
       Index Cond: ((tstamp >= ((('now'::cstring)::date - '3 days'::interval))::date) AND (tstamp < ('now'::cstring)::date)) 
       Filter: (action = 13) 
     -> Index Scan using history_log_201205_tstamp on history_log_201205 history_log (cost=0.01..10.39 rows=1 width=4) 
       Index Cond: ((tstamp >= ((('now'::cstring)::date - '3 days'::interval))::date) AND (tstamp < ('now'::cstring)::date)) 
       Filter: (action = 13) 
     -> Index Scan using history_log_201206_tstamp on history_log_201206 history_log (cost=0.01..10.32 rows=1 width=4) 
       Index Cond: ((tstamp >= ((('now'::cstring)::date - '3 days'::interval))::date) AND (tstamp < ('now'::cstring)::date)) 
       Filter: (action = 13) 
     -> Index Scan using history_log_201207_tstamp on history_log_201207 history_log (cost=0.01..10.09 rows=1 width=4) 
       Index Cond: ((tstamp >= ((('now'::cstring)::date - '3 days'::interval))::date) AND (tstamp < ('now'::cstring)::date)) 
       Filter: (action = 13) 
     -> Index Scan using history_log_201208_tstamp on history_log_201208 history_log (cost=0.01..10.35 rows=1 width=4) 
       Index Cond: ((tstamp >= ((('now'::cstring)::date - '3 days'::interval))::date) AND (tstamp < ('now'::cstring)::date)) 
       Filter: (action = 13) 
     -> Index Scan using history_log_201209_tstamp on history_log_201209 history_log (cost=0.01..10.53 rows=1 width=4) 
       Index Cond: ((tstamp >= ((('now'::cstring)::date - '3 days'::interval))::date) AND (tstamp < ('now'::cstring)::date)) 
       Filter: (action = 13) 
     -> Index Scan using history_log_201210_tstamp on history_log_201210 history_log (cost=0.01..11.83 rows=1 width=4) 
       Index Cond: ((tstamp >= ((('now'::cstring)::date - '3 days'::interval))::date) AND (tstamp < ('now'::cstring)::date)) 
       Filter: (action = 13) 
     -> Index Scan using history_log_201211_tstamp on history_log_201211 history_log (cost=0.01..11.87 rows=1 width=4) 
       Index Cond: ((tstamp >= ((('now'::cstring)::date - '3 days'::interval))::date) AND (tstamp < ('now'::cstring)::date)) 
       Filter: (action = 13) 
     -> Index Scan using history_log_201212_tstamp on history_log_201212 history_log (cost=0.01..12.40 rows=1 width=4) 
       Index Cond: ((tstamp >= ((('now'::cstring)::date - '3 days'::interval))::date) AND (tstamp < ('now'::cstring)::date)) 
       Filter: (action = 13) 
     -> Index Scan using history_log_201301_tstamp on history_log_201301 history_log (cost=0.01..12.35 rows=1 width=4) 
       Index Cond: ((tstamp >= ((('now'::cstring)::date - '3 days'::interval))::date) AND (tstamp < ('now'::cstring)::date)) 
       Filter: (action = 13) 
     -> Index Scan using history_log_201302_tstamp on history_log_201302 history_log (cost=0.01..12.35 rows=1 width=4) 
       Index Cond: ((tstamp >= ((('now'::cstring)::date - '3 days'::interval))::date) AND (tstamp < ('now'::cstring)::date)) 
       Filter: (action = 13) 
     -> Index Scan using history_log_201303_tstamp on history_log_201303 history_log (cost=0.01..252959.45 rows=1353824 width= 
4) 
       Index Cond: ((tstamp >= ((('now'::cstring)::date - '3 days'::interval))::date) AND (tstamp < ('now'::cstring)::date)) 
       Filter: (action = 13) 
     -> Index Scan using history_log_201304_tstamp on history_log_201304 history_log (cost=0.01..8.37 rows=1 width=4) 
       Index Cond: ((tstamp >= ((('now'::cstring)::date - '3 days'::interval))::date) AND (tstamp < ('now'::cstring)::date)) 
       Filter: (action = 13) 

這裏發生了什麼?爲什麼查詢主表不僅速度快?

我有constraint_exclusion設置爲on

編輯:我找到了解決方案,爲了可讀性而意外寫入。

直到今天我有錯的限制 - 我tstamp列是timestamp WITH time zone類型,制約因素基礎上timestamp WITHOUT time zone。我修正了這個問題,修復了我的查詢以進行類型轉換 - 但仍然向master表查詢花費了幾分鐘而不是秒。這是我的最後一個選擇,所以我去了。在談話我去DB併發出EXPLAIN ANALYZE所有子表得到一些實際的數字 - 這對查詢主表後成爲快!

回答

1

查詢應該是一樣快。在主表上僅執行seq掃描,其在給定正確配置的分區表的情況下應該包含的行。

考慮使用EXPLAIN ANALYZE,以便您可以查看查詢的確切時間。兩者之間的差異應該可以忽略不計。


實際的問題似乎是在子表上執行的查詢不會返回任何結果。想必你的問題可以歸結爲:爲什麼在CHECK約束不可能被滿足還是被搜索的子表?

有關於這個問題的a thread on the pgsql-bugs mailing list。您的tstamp列是timestamp with time zone。支票不能在WHERE子句中使用的表達式是一個date值,而不是一個時間戳。考慮使用CURRENT_TIMESTAMP而不是CURRENT_DATE。如果您需要從午夜到查詢,然後保持當前的查詢,但鑄造再加上tstamp列具有完全相同的類型(::timestamp with time zone)。

+0

它需要年齡。我如何檢查由於某種原因我的主表是否仍然包含行?我相信所有對它的查詢都會被代理到子表... – skaurus

+0

@skaurus查詢確實是代理的,就好像你已經在每個表(包括主表)上執行查詢並在它們之間放置了'UNION ALL'。可能花費時間的不是實際主表上的查詢,而是其他子表上的索引掃描。 – cdhowie

+0

Errm ...只是爲了給我一些實際的數字,我去了DB並向所有childs表發佈了「EXPLAIN ANALYSE」(總共耗時約2.5秒);然後我向主表發出了相同的命令 - 並且也花了2秒鐘!我很尷尬。即使在幾個小時前,情況並非如此。小背景 - 直到今天,我在每張桌上都有'timestamp without time zone'的約束,我剛剛修復了它 - 但沒有看到任何更改(主表上的EXPLAIN ANALYSE幾乎殺死了我的應用程序)。這就是我決定尋求幫助的原因。現在 - 一切都很好。似乎需要所有子表的ANALYZE :-)謝謝! – skaurus