【问题标题】:How to find a gap in a time ordered table where a given column does not have a certain value for a specified interval如何在时间排序表中查找给定列在指定间隔内没有特定值的间隙
【发布时间】:2010-12-23 19:08:59
【问题描述】:

我有一个大表(数百万行),我需要根据某个列值的存在和未发生指定的“超时”来查找记录组。我认为一种方法是在整个表中找到这些“超时”间隙发生的位置。

示例表:

+----------------+--------+ |时间 |基地 | +----------------+--------+ | 1245184797.064 |一个 | | 1245184802.020 |一个 | | 1245184807.103 |乙 | | 1245184812.089 |乙 | | 1245184816.831 |乙 | | 1245184821.856 |一个 | | 1245184821.856 |一个 | | 1245184855.903 |一个 | | 1245184855.903 |乙 | | 1245184858.362 |乙 | | 1245184858.362 |乙 | | 1245184860.360 |一个 | | 1245184860.360 |一个 | | 1245184862.174 |一个 | | 1245184862.174 |乙 | | 1245185001.480 |乙 | | 1245185417.556 |一个 | | 1245185417.844 |一个 | | 1245185419.960 |乙 | | 1245185420.181 |乙 | +----------------+--------+

鉴于此集合,我如何快速找到表中在给定秒数(例如 5 秒)内未发生 base=a 的点。

归结起来,我的目标是找到base=a HAS 持续发生而没有超时的记录范围。

【问题讨论】:

    标签: sql sql-server postgresql mysql


    【解决方案1】:

    我认为这会对你有所帮助:

    SELECT * FROM (
        SELECT t1.[time],
               t1.time - (SELECT MAX(time) FROM my_table t2 WHERE t2.time < t1.time and t2.base = 'a') AS timeout
        FROM my_table t1
        WHERE t1.base = 'a') d
    WHERE timeout > 5
    

    并且不要忘记为这个查询创建索引以更有效:

    CREATE INDEX idx_my_table_time_base ON my_table (time, base)
    

    【讨论】:

    • +1 有效,删除 WHERE t1.base = 'a' 并将 t2.base = 'a' 替换为 t2.base = t1.base 以使其搜索所有基本间隙
    • 是的。在任何情况下都使用 t2.base = t1.base。
    • 也很有意思,时间和上面差不多,3000行的base需要6秒。优化器也没有选择您建议的索引。还是太慢了。
    • 尝试通过对该索引的全面扫描来更新统计信息。可能是服务器不认为这个索引是有选择性的。如果它没有帮助尝试在内部选择中使用提示:“from my_tabe t2 with(index=my_index)”。有帮助吗?
    【解决方案2】:

    如果您使用的是支持窗口/分析功能的数据库,一种可能性是这样的:

    select * from (
        select time,
               base,
               time - lag(time) over(partition by base order by time) as interval
        from example) w
    where w.interval > 5
    

    这应该能够通过(base,time)索引的单次扫描来工作。它适用于 PostgreSQL 8.4,我认为也应该适用于 SQL Server 2008 和 Oracle 10。

    【讨论】:

      【解决方案3】:

      解决此问题的一种方法是检查“伸展头”,即距离上次出现超过 5 秒的碱基的出现。此示例查询将表连接到自身以过滤掉非头部:

      select    head.* 
      from      @t head
      left join @t nohead 
      on        head.base = nohead.base 
      and       head.time - 5 < nohead.time and nohead.time < head.time
      where     nohead.base is null
      order by  head.[time]
      

      对于每一行,left join 在最后 5 秒内搜索相同的碱基。 where nohead.base is null 子句表示这样的行可能不存在。效果是一个 5 秒以上没有基础的跨度发生时间的列表。

      它不会列出最后一个间隔:您可以为每个碱基显式添加“结束时间”行:

      <end time>     a
      <end time>     b
      ...
      

      使查询检查结束。

      【讨论】:

      • 有趣的解决方案,但它仍然需要太多时间 - 对 3000 行的基础进行查询需要 6 秒。
      • @naturalethic:我会说在 (base,time) 上添加一个索引...但是 3000 行 6 秒太慢了,即使你没有定义任何索引。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-09-18
      • 1970-01-01
      • 1970-01-01
      • 2017-12-23
      • 1970-01-01
      • 2021-08-22
      相关资源
      最近更新 更多