0

我说的是这个功能

我有主表:

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 条件受 tstamp 约束的查询时 - 它工作得非常快。

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)

但是当我尝试在主表上做同样的事情时 - 它进入 Seq Scan:

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. 我修复了这个问题,修复了我的查询以进行类型转换 - 但对主表的查询仍然需要几分钟而不是几秒钟。那是我最后的选择,所以我去了 SO。在谈话过程中,我去了数据库EXPLAIN ANALYZE并向所有子表发出了一些实际数字 - 之后对主表的查询变得很快!

4

1 回答 1

1

查询应该一样快。seq 扫描仅在主表上执行,在给定正确配置的分区表的情况下,该表根本不应该包含任何行

考虑使用EXPLAIN ANALYZE,这样您就可以确切地看到查询需要多长时间。两者之间的差异应该可以忽略不计。


实际问题似乎是在不会返回任何结果的子表上执行查询。想必您的问题归结为:为什么CHECK无法满足约束的子表仍在搜索中?

pgsql-bugs 邮件列表上有一个关于这个问题的线程。您的tstamp专栏是timestamp with time zone. 检查不能用作您的WHERE子句中的表达式是一个date值,而不是时间戳。考虑使用CURRENT_TIMESTAMP而不是CURRENT_DATE. tstamp如果您需要从午夜开始查询,请保留您当前的查询,但将强制转换添加到该列所具有的完全相同的类型( ::timestamp with time zone)。

于 2013-04-01T15:21:55.627 回答