【问题标题】:Querying a datetime range while taking into account the time zone在考虑时区的同时查询日期时间范围
【发布时间】:2011-05-13 18:05:07
【问题描述】:

我在查询时遇到了很多麻烦。我真的不知道如何解释这一点,但我会尝试。

基本上,我们有几个带有“posted_at”字段的对象,它在日期时间字段中保存发布日期和时间以及时区。我需要查询并获取这些对象的日期范围。

以前,我将其转换为 Date 并将其与另一个 Date 对象进行比较。查询是这样的:

Date(posted_at) >= :start_date AND Date(posted_at) <= :end_date

但是,当 Postgre 将其转换为 Date 时,它​​会丢失导致查询结果不准确的时区信息。

所以,我改成这样:

if start_date then
    start_time = Time.zone.parse("#{start_date.year}-#{start_date.month}-#{start_date.day}")
    conditions << "posted_at >= :start"
    hash[:start] = start_time
end

if end_date then
    end_time = Time.zone.parse("#{end_date.year}-#{end_date.month}-#{end_date.day}").end_of_day
    conditions << "posted_at <= :end"
    hash[:end] = end_time
end

虽然这让我得到了准确的结果,但它的性能也很糟糕,并导致我的应用程序出现一些超时。

我找不到任何其他方法来执行此查询并仍然保持准确的结果。有人有什么建议或想法吗?

提前谢谢你。

【问题讨论】:

    标签: ruby-on-rails performance postgresql datetime timezone


    【解决方案1】:

    您永远不想在数据库中存储时区信息。

    这里有一篇文章讨论了一些陷阱:

    http://derickrethans.nl/storing-date-time-in-database.html

    按照 tadman 的建议,您将获得更好的结果:添加一个带有时间戳 at time zone 'utc' 的新字段,并将其编入索引。然后你就可以使用posted_at between ? and ? 抓取东西了。

    【讨论】:

    • 谢谢丹尼斯,这真的很值得了解。
    【解决方案2】:

    您可能会更幸运地将开始和结束时间转换为 UTC,这将使时区在进行查询本身时几乎无关紧要。这很容易做到:

    start_date.to_time.to_datetime.beginning_of_day.utc
    end_date.to_time.to_datetime.end_of_day.utc
    

    您还可以将查询调整为:

    posted_at BETWEEN :start AND :end
    

    请务必在您正在搜索的字段上也有一个索引,否则您将获得糟糕的性能。

    【讨论】:

    • 该字段已编入索引,我已尝试两种方法。不过,仍然会出现一些超时:(
    • 它在log/development.log 中生成什么查询?您是否尝试过在此查询中使用EXAMINE?它通常会突出显示可能存在问题的地方。
    • 我认为问题不是真正的查询,而是我们有数百万行的事实......因为当我比较日期时一切正常,我在这里与一些人交谈,我们'将创建一个仅保留日期的新索引列,同时考虑时区。感谢您的帮助和信息!
    • 我发现如果创建 date 字段而不是 datetime 字段通常效果更好,因为基数较低,所以这个建议当然值得追求。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-04-16
    • 2013-06-04
    • 2013-10-22
    • 2019-05-26
    • 1970-01-01
    • 2019-12-06
    相关资源
    最近更新 更多