【问题标题】:How to optimize this "Time apart" SQL query?如何优化这个“时间间隔”的 SQL 查询?
【发布时间】:2011-03-17 20:13:46
【问题描述】:

我想要一种简单的方法来对我的时间序列数据运行如下查询:

“相隔 7 天内最典型的事件是什么”?

我可以通过使用 SQL 和 Java 程序来做到这一点,通过查看每一行并运行一个查询,该查询会在 7 天之前或之后查找所有事件,但这不是很优雅,而且性能会很糟糕。

我还得到了 JNK 和 Milen A. Radev 的帮助来编写以下 SQL。我的问题是,当我在 2300 万行上测试它时,它运行了两个小时并停止了,因为我的 RamDisk(我运行 PostgreSQL 数据库的地方)已满。您知道如何优化这样的查询吗?

SELECT a.eventID, b.eventID, COUNT(*)
FROM table a
INNER JOIN table b
    ON a.eventID <> b.eventID
WHERE aBS(EXTRACT(EPOCH FROM (a.thetimeanddate - b.thetimeanddate))) < 5 
GROUP BY a.eventID, b.eventID 
ORDER BY COUNT(*) DESC
LIMIT 1000;

【问题讨论】:

  • 您的查询“查找早于或晚 7 天的事件”。它只是返回表 a 中在表 be 中具有匹配行的 所有 行,并计算两列之间的差异。
  • @a_horse_with_no_name 你完全正确。我选择了错误的 SQL 查询。我已经更新了我的问题。
  • @David:你确定ON a.eventID &lt;&gt; b.eventID 条件吗?这不会连接相应的行,并且可能会生成巨大的结果集。
  • @a_horse_with_no_name 我同意这是一个非常广泛的连接,但我不知道如何使其更具限制性。使用 where 子句减少了最终输出,但也许我应该移动 where 子句使其成为连接条件的一部分?
  • @David:你确定不想要ON a.eventID = b.eventID 吗?

标签: sql postgresql


【解决方案1】:

部分问题在于某些功能会阻止 RDBMS 推断查询的某些属性,然后搜索任何索引。 (查找 SARGABLE 了解更多信息。)

这意味着 RDBMS 必须处理每个事件组合并检查 WHERE 原因以查看它们是否在 5 天内。每个组合等于 529,000,000,000,000 个组合。 (5.29亿是相当多的。)

如果您将查询改写为“WHERE b.thetimeanddate 具有这些属性”,那么您可能会发现性能提升。如果您有一个涵盖 [thetimeanddate] 字段的索引,就会发生这种情况。比如……

SELECT
  a.eventID,
  b.eventID,
  COUNT(*)
FROM
  table a
INNER JOIN
  table b
    ON a.eventID <> b.eventID
WHERE
      b.thetimeanddate >= date_trunc('day', a.thetimeanddate) - INTERVAL '5 days'
  AND b.thetimeanddate <  date_trunc('day', a.thetimeanddate) + INTERVAL '6 days'
GROUP BY
  a.eventID,
  b.eventID
ORDER BY
  COUNT(*) DESC
LIMIT
  1000
;

RDBMS 现在应该能够更轻松地使用表中包含 [thetimeanddate] 字段的任何索引。它现在只计算您拥有的 2900 万个事件中的每一个的截断日期,并检查索引以查看“此日期”和“那个日期”之间出现了多少。可能比替代方案快几百万倍......

(我也很想将 WHERE 子句移到 ON 子句中,但仅出于样式目的。性能将相同。记住,RBDMS 编译这些查询,并选择算法和优化。如果两个查询可以通过代数操作使其相同,它们通常会产生相同的最终执行计划。[假设操作所需的所有信息都存在于查询中,并且不是“只是在你的脑海中知道”。])

编辑

我还注意到您按 a.eventID 和 b.eventID 进行分组,然后进行计数。假设 eventID 在表中是唯一的,这将始终产生 1...

编辑

将 +5 更改为 + INTERVAL '5 天'

【讨论】:

  • 这种重构可能仍然会在没有索引的情况下产生性能提升。但是,强烈建议您创建一个。正如所指出的,基本的自连接产生 5.29 亿个组合,您需要为 RDBMS 提供一种机制来选择性地减少被检查的记录。第一部分是索引。
  • @Dems 实际上时间列中从来没有索引,因为我认为它不能被这样的查询使用。相同的事件可能会发生很多次,因此需要对两者进行分组。但是,您的查询出现错误:运算符不存在:没有时区的时间戳 - 整数
  • @David - 强烈建议您在时间字段上放置索引。
  • @david:您的 [thetimeanddate] 字段是什么数据类型?您只需要让示例的 date_trunc() 部分执行您希望它们执行的操作...
  • 间隔的标准 SQL 语法是 + INTERVAL '5' DAY,如果您在多个平台上工作,这很重要。 PostgreSQL 对间隔有点奇怪。例如,+ INTERVAL '5' DAY+ INTERVAL '5' DAYS 的评估方式大不相同。
猜你喜欢
  • 2020-02-08
  • 1970-01-01
  • 2017-08-09
  • 2023-02-21
  • 1970-01-01
  • 1970-01-01
  • 2013-05-27
  • 2020-02-14
  • 1970-01-01
相关资源
最近更新 更多