PostgreSQL:在timestamp :: DATE上创建索引

Ada*_*tan 13 sql postgresql indexing casting date

我正在创建一个汇总表,汇总给定日期内的所有事件.

INSERT INTO graph_6(
  day,
  event_type,
  (SELECT COUNT(*) FROM event e 
                  WHERE event_type = e.event_type 
                  AND creation_time::DATE = sq.day)
FROM event_type
CROSS JOIN
    (SELECT generate_series(
                (SELECT '2014-01-01'::DATE),
                (SELECT '2014-01-02'::DATE),
                '1 day') as day) sq;
Run Code Online (Sandbox Code Playgroud)

creation_time列已编入索引:

CREATE INDEX event_creation_time_date_idx ON event USING BTREE(creation_time);
Run Code Online (Sandbox Code Playgroud)

但是,即使仅使用少量事件(2014年1月1日至2日)查询两天的数据,查询也会运行很长时间.

EXPLAIN上查询是相当严峻-它运行一个顺序扫描的event表,而不是利用指数都:

->  Seq Scan on event e_1  (cost=0.00..12557.39 rows=531 width=38)
Filter: ... AND ((creation_time)::date = (generate_series(($12)::timestamp with time zone, ($13)::timestamp with time zone, '1 day'::interval))))
Run Code Online (Sandbox Code Playgroud)

我认为这是因为我们比较了一个铸造值 - creation_time::DATE而不是creation_time.我试过索引转换:

CREATE INDEX event_creation_time_date_idx ON event USING BTREE(creation_time::DATE);
Run Code Online (Sandbox Code Playgroud)

但是得到了一个错误:

ERROR: syntax error at or near "::"
Run Code Online (Sandbox Code Playgroud)

有没有办法在投放到DATE的时区列上使用PostgreSQL索引?

kli*_*lin 27

索引声明中的表达式应该包含在其他括号中,请尝试:

CREATE INDEX event_creation_time_date_idx ON event ((creation_time::DATE));
Run Code Online (Sandbox Code Playgroud)

  • 这只适用于没有时区的时间戳.否则您将收到此错误:错误:索引表达式中的函数必须标记为IMMUTABLE (9认同)
  • 如果您选择一个时区并在索引和查询中都转换为时区,则可以解决时区问题(有点):`creation_time AT TIME ZONE 'UTC'` (3认同)
  • 如果您正在使用 @thaddeusmt 的解决方案,只需确保在查询中也使用该语法(转换为 utc) - 否则它不会使用索引。谢谢你的窍门。;) (2认同)