为具有时区的时间戳添加索引

时间:2015-08-17 02:56:03

标签: 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) (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"

1 个答案:

答案 0 :(得分:3)

首先,修复您的查询以生成谓词sargable

SELECT count(*) AS ct
FROM   events
WHERE  dtt >= date_trunc('day', now() AT TIME ZONE 'America/Santiago')
                                      AT TIME ZONE 'America/Santiago'

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

这是正确的,在推导当天的本地开始后,再次应用AT TIME ZONEtimestamp再次转换回timestamptz。详细说明:

逐步说明

  1. <强> now()
    ..是SQL标准CURRENT_TIMESTAMP的Postgres实现。两者都是100%等效,你可以使用其中之一。它会将当前时间点返回为 timestamptz - 值的显示会考虑当前会话的时区,但是这样做了与值无关

  2. now() AT TIME ZONE 'America/Santiago'
    ..计算给定时区的当地时间。生成的数据类型为 timestamp 。我们这样做是为了允许:

  3. date_trunc( now() AT TIME ZONE 'America/Santiago' )
    ..截断时间组件以获取“美国/圣地亚哥”当天的当地开始时间,与当前时区设置无关。

  4. date_trunc('day', now() AT TIME ZONE 'America/Santiago') AT TIME ZONE 'America/Santiago'
    ..将timestamp提供给AT TIME ZONE构造,我们得到相应的 timestamptz 值(内部UTC),以比较timestamptz值{{1转到。

  5. 我删除了dtt,怀疑您刚刚滥用该内容将+ interval '1s'转换为date。请改用timestamp来生成date_trunc()值。

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

    dtt

    如果您的重要查询仅考虑最近的行,则部分索引可能会有所帮助。详细说明: