Sql 向带有时区的时间戳添加索引

Sql 向带有时区的时间戳添加索引,sql,postgresql,indexing,count,timezone,Sql,Postgresql,Indexing,Count,Timezone,我想改进这个缓慢的查询,我想添加一个索引,但我不知道哪种索引类型更适合我的情况 SELECT COUNT(*) ct FROM events WHERE dtt AT TIME ZONE 'America/Santiago' >= date(now() AT TIME ZONE 'America/Santiago') + interval '1s' 查询计划: "Aggregate (cost=128032.03..128032.04 rows=1 width=0) (act

我想改进这个缓慢的查询,我想添加一个索引,但我不知道哪种索引类型更适合我的情况

SELECT COUNT(*) ct FROM events
WHERE dtt AT TIME ZONE 'America/Santiago'
   >= date(now() AT TIME ZONE 'America/Santiago') + interval '1s'  
查询计划:

"Aggregate  (cost=128032.03..128032.04 rows=1 width=0) (actual time=3929.083..3929.083 rows=1 loops=1)"
"  ->  Seq Scan on events  (cost=0.00..125937.68 rows=837742 width=0) (actual time=113.080..3926.972 rows=25849 loops=1)"
"        Filter: (timezone('America/Santiago'::text, dtt) >= (date(timezone('America/Santiago'::text, now())) + '00:00:01'::interval))"
"        Rows Removed by Filter: 2487386"
"Planning time: 0.179 ms"
"Execution time: 3929.136 ms"
  • 该查询获取当天事件的计数
  • dtt是带有时区列的时间戳
  • 我正在使用Postgresql 9.4
注: 使用Erwin建议,查询运行得更快一些,但我认为仍然不够快

"Aggregate  (cost=119667.76..119667.77 rows=1 width=0) (actual time=3687.151..3687.152 rows=1 loops=1)"
"  ->  Seq Scan on vehicle_events  (cost=0.00..119667.14 rows=250 width=0) (actual time=104.635..3687.068 rows=469 loops=1)"
"        Filter: (dtt >= timezone('America/Santiago'::text, date_trunc('day'::text, timezone('America/Santiago'::text, now()))))"
"        Rows Removed by Filter: 2513337"
"Planning time: 0.164 ms"
"Execution time: 3687.204 ms"

首先,修复查询以生成谓词:

按原样使用列值并将所有计算移动到参数

没错,在导出一天的本地开始时间后,再次在时区应用
,将
时间戳
转换回
时间戳
。详情:

逐步解释
  • now()

    .. 是SQL标准的Postgres实现
    当前时间戳
    。两者都是100%等效的,您可以使用其中一种。它将当前时间点返回为
    timestamtz
    ——该值的显示考虑了当前会话的时区,但这与该值无关

  • now()
    在时区“美国/圣地亚哥”

    .. 计算给定时区的本地时间。结果数据类型为时间戳。我们这样做是为了:

  • date\u trunc(
    now()在时区“美国/圣地亚哥”

    .. 截断时间分量以获取“America/Santiago”中的本地一天开始时间,与当前时区设置无关

  • date\u trunc('day',now()在时区“America/Santiago”)
    在时区“America/Santiago”

    .. 将
    时间戳
    输入时区的
    构造,我们得到相应的
    时间戳
    值(UTC内部),以比较
    时间戳
    dtt

  • 我删除了
    +间隔'1s'
    ,怀疑您刚刚滥用它将
    日期
    转换为
    时间戳
    。使用
    date\u trunc()
    生成
    时间戳

    现在,
    dtt
    上的普通(默认)btree索引就可以了。当然,只有当谓词具有足够的选择性时,才会使用索引

    CREATE INDEX events_dtt_idx ON events (dtt);
    

    如果您的重要查询只考虑最近的行,则<强>部分索引< /强>可能会有帮助。详情:


    谢谢Erwin的回答,我现在有了一个更好的结果,但是查询速度仍然很慢,需要对我的表重新编制索引吗?@Goku:
    reindex
    只有在索引严重膨胀或损坏时才需要<代码>真空分析事件
    可能有助于为您提供一个解决方案。如果由于太多的写入活动而无法获得仅索引扫描,则对表进行集群可能会加快扫描速度。您忘记转换回UTC了吗?或者这是在比较中隐含的吗?@Matt:都不是。“转换为UTC”是转换为
    timestamptz
    的一个隐含细节,它是UTC内部时间戳,独立于时区工作。请不要被有点误导性的数据类型名称弄糊涂:。按照链接查看详细信息。@MattJohnson:No.
    date\u trunc()
    返回
    timestamp
    输入的
    timestamp
    timestamp
    输入的
    timestamp
    。为了澄清,我一步一步地添加了一个解释。吹毛求疵,你的查询不会“得到当天事件的数量”。它获取从一天开始的所有事件的计数-包括将来的时间戳(如果有),这可能很容易在多个时区发生。
    CREATE INDEX events_dtt_idx ON events (dtt);