如何在PostgreSQL中使用不同的时区索引日历查询?

时间:2017-02-15 13:32:16

标签: postgresql date timezone

在我们的PostgreSQL 9.6应用程序中,我们目前正在重写一个性能最关键的部分:显示一些帖子的日历。

SELECT
  assigned_user_id,
  channel_id,
  id,
  row_number()
  OVER (
    PARTITION BY DATE(publication_at AT TIME ZONE 'Europe/Vienna')
    ORDER BY publication_at ASC, id ASC )                            AS "row_number",
  TO_CHAR(publication_at AT TIME ZONE 'Europe/Vienna', 'YYYY-MM-DD') AS "day",
  COUNT(*)
  OVER (
    PARTITION BY DATE(publication_at AT TIME ZONE 'Europe/Vienna') ) AS "count_per_day"
FROM posts
WHERE client_id = 159 AND publication_at BETWEEN '2016-12-25 23:00:00' AND '2017-02-05 22:59:59'
ORDER BY publication_at AT TIME ZONE 'Europe/Vienna', id ASC

根据特定月份(在本例中为2017年1月),我们选择具有特定publication_at的所有帖子(注意:WHERE子句中传递的值已经转换为本地时间) 。由于其他原因(这里与此案例无关),我们选择行号以及数据库中每个当地日的帖子数量。

目前,我们的索引(posts_client_id_publication_at_assigned_user_id_id)仅被部分使用,因为AT TIME ZONE …不能对索引起作用(它根本不是sargable)。

这里是我的开发机器的EXPLAIN ANALYSE输出 - 生产表有近10百万行:

Sort  (cost=268.52..268.74 rows=87 width=92) (actual time=2.464..2.517 rows=524 loops=1)
  Sort Key: (timezone('Europe/Vienna'::text, publication_at)), id
  Sort Method: quicksort  Memory: 98kB
  Buffers: shared hit=246 read=6
  ->  WindowAgg  (cost=260.93..265.72 rows=87 width=92) (actual time=0.920..2.306 rows=524 loops=1)
        Buffers: shared hit=246 read=6
        ->  WindowAgg  (cost=260.93..263.32 rows=87 width=44) (actual time=0.899..1.173 rows=524 loops=1)
              Buffers: shared hit=246 read=6
              ->  Sort  (cost=260.93..261.15 rows=87 width=36) (actual time=0.895..0.952 rows=524 loops=1)
                    Sort Key: (date(timezone('Europe/Vienna'::text, publication_at))), publication_at, id
                    Sort Method: quicksort  Memory: 65kB
                    Buffers: shared hit=246 read=6
                    ->  Index Scan using posts_client_id_publication_at_assigned_user_id_id on posts  (cost=0.41..258.13 rows=87 width=36) (actual time=0.050..0.774 rows=524 loops=1)
                          Index Cond: ((client_id = 159) AND (publication_at >= '2016-12-25 23:00:00+01'::timestamp with time zone) AND (publication_at <= '2017-02-05 22:59:59+01'::timestamp with time zone))
                          Buffers: shared hit=246 read=6
Planning time: 0.343 ms
Execution time: 2.641 ms

我知道我们应该将时区部分从列移动到右侧部分,这样我们仍然可以在索引中使用publication_at。但我不知道如何使用给定的查询来执行此操作。

提示:我们的用户可以选择不同的时区,因此我们不能简单地在索引中放入一个特定的时区值。

0 个答案:

没有答案