【问题标题】:SQL is there a way to sort multiple time columns into one while preserving metadata without UNION?SQL 有没有一种方法可以将多个时间列排序为一个,同时在没有 UNION 的情况下保留元数据?
【发布时间】:2019-04-13 14:08:39
【问题描述】:

这是我上一个问题的扩展:SQL is there a way to sort multiple time columns into one while preserving metadata?

我现在正在尝试优化此解决方案,但现在我遇到了第一个时间戳列已排序的情况。使用 UNION 作为解决方案的问题在于,它大大增加了查询大量数据的时间,因为它实际上再次将数据置于无序状态,并且需要在时间戳上再进行一次 ORDER BY。

所以,总结上一个问题: 我有一个 SQL 数据库表,它有四个不同时间的列按第一个时间戳 (a_time) 排序。我希望能够以一种可以将 a、b、c 和 d 时间戳中的每一个合并到一列中的方式对它们进行排序,同时保留 id 和元数据。

id | a_time | b_time | c_time | d_time | metadata1 | metadata2
1  | 5      | 7      | 2      | 4      | a         | b
2  | 6      | 1      | 12     | 10     | c         | d
3  | 8      | 9      | 3      | 11     | e         | f

在上面的例子中,我想要一些结果:

id | time | metadata1 | metadata2
2  |  1   |     c     |    d
1  |  2   |     a     |    b
3  |  3   |     e     |    f
1  |  4   |     a     |    b
1  |  5   |     a     |    b
2  |  6   |     c     |    d
1  |  7   |     a     |    b
3  |  8   |     e     |    f
3  |  9   |     e     |    f
2  |  10  |     c     |    d
3  |  11  |     e     |    f
2  |  12  |     c     |    d

我认为没有其他方法可以做到这一点,并且我可能需要以不同的方式解析查询数据,但我很感激任何对此问题的可能优化解决方案的见解。 em>

【问题讨论】:

  • 有一种方法可以在没有工会的情况下做到这一点。如果您可以将表的架构(IOW,create table 语句)添加到您的问题中,我将创建一个 SQLFiddle 来展示另一种方法。
  • 另见CASE ...GROU PBY id

标签: mysql sql database sorting optimization


【解决方案1】:

如果你有一个数字表,你可以通过JOINing 到元数据表来得到你想要的结果:

SELECT m.id, n.n, m.metadata1, m.metadata2
FROM numbers n
JOIN metadata m ON m.a_time = n.n OR m.b_time = n.n OR m.c_time = n.n OR m.d_time = n.n
ORDER BY n.n

输出

id  n   metadata1   metadata2   
2   1   c           d
1   2   a           b
3   3   e           f
1   4   a           b
1   5   a           b
2   6   c           d
1   7   a           b
3   8   e           f
3   9   e           f
2   10  c           d
3   11  e           f
2   12  c           d

如果您没有数字表,您可以使用以下查询即时创建一个:

SELECT m.id, n.n, m.metadata1, m.metadata2
FROM (SELECT n1.n + n10.n * 10 AS n 
      FROM (SELECT 0 AS n UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) n1
           CROSS JOIN
           (SELECT 0 AS n UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) n10
           ) n
JOIN metadata m ON m.a_time = n.n OR m.b_time = n.n OR m.c_time = n.n OR m.d_time = n.n
ORDER BY n.n

SQLFiddle

更新

似乎出于性能原因,最好添加一个WHERE 子句,将numbers 表中的数字范围限制为metadata 中的时间范围,即

WHERE n.n <= (SELECT GREATEST(MAX(a_time), MAX(b_time), MAX(c_time), MAX(d_time)) FROM metadata)

a_timeb_timec_timed_time 添加索引也可以提高此查询的性能。

【讨论】:

  • 有用。我想指出,我使用的许多 DBA 都故意将具有 OR 条件的查询拆分为单独的查询,这些查询随后合并在一起,因为 sqlserver 不一定会使用多个索引(例如,每个 _time 列都有自己的索引)使用 OR 在多个列中查找单个值的单个查询,而如果有两个查询被联合,它会。因此,此解决方案可能会忽略时间列上的索引,这可能会使其在某些情况下运行得更快。如果需要,绝对可以进行测试
  • @CaiusJard 这很有趣。我尝试为metadata 中的每个*_time 列添加索引,EXPLAIN 肯定表明它正在使用它们。我确实看到执行时间也从 0.01 秒缩短到了 0.001 秒。
  • 这些查询中最令人难忘的是一个表格,它描述了一个 fromuser guid 和一个 touser guid 的对话,几亿行和两个独立的索引;每个用户标识列一个。发现WHERE fromuser = @userid OR touser = @useridWHERE fromuser = @userid UNION WHERE touser = @userid 慢得多,因为在OR 表单中只使用了一个索引。也许还有其他因素阻碍了处理的某些并行方面
  • @CaiusJard 这是个好问题。在此期间,也许查询优化刚刚好很多。
【解决方案2】:

你似乎想要apply

select t.id, v.time, t.metadata1, t.metadata2
from t cross apply
     (values (a_time), (b_time), (c_time), (d_time)
     ) v(time)
order by v.time;

【讨论】:

    猜你喜欢
    • 2019-03-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-10-18
    • 2011-09-30
    • 2022-11-21
    • 2021-05-16
    相关资源
    最近更新 更多