【问题标题】:SQL order by in two stepsSQL order by 分两步
【发布时间】:2020-12-31 11:04:02
【问题描述】:

我有一个有两个日期时间列的大表。

[Timestamp][TimestampRounded]

[Timestamp] 列具有完整的时间戳(包括毫秒),并且该表没有该列的索引。

[TimestampRounded] 列具有时间戳,但毫秒、秒和分钟被截断(设置为 0)。该表具有该列的聚集索引。即,表格有效地按此列的顺序存储。通常,最新的行位于表格的顶部。索引是这样创建的:

CREATE CLUSTERED INDEX cidx_time ON [dbo].[MyTable] ([TimestampRounded] DESC)

现在,我想利用我的聚集索引检索一些数据,所以我执行以下选择,我的表有大约 500 万行。

查询 1:

SELECT TOP(100) * FROM [dbo].[MyTable] ORDER BY [TimestampRounded] DESC

此查询立即返回(不到 1 秒)。但是返回的 100 行没有按毫秒排序,只是按小时排序。

然后我知道我是否也想按第二列排序:

查询 2:

SELECT TOP(100) * FROM [dbo].[MyTable] ORDER BY [TimestampRounded] DESC, [Timestamp] DESC

这个查询非常慢,大约需要 23 秒才能返回 100 行。

我的直接解决方案是使用第一个查询,然后在我的客户端前端代码中对返回的 100 行进行排序。但是我遇到了一些问题,我错过了应该返回的行,所以我想了解如何修复/重写查询 2 以按预期返回这 100 个排序的行,并且通过合理的逻辑也应该花费不到 1 秒。由于该表已经按小时存储(聚集索引),我不明白为什么需要更长的时间。

【问题讨论】:

  • TimestampRounded 有多少行在相同的最高值上?
  • 可以将数千行绑定到 TimestampRounded 值。那就是在那一小时内发生的每一行
  • 完全正确 - 所以您的第一个查询是“给我 any 100 行共享相同小时值的行” - 而您的第二个查询是“给我准确的 100 行最新的” - 第二个需要更多时间。
  • 那么获得正确数据的合理性是什么?对聚集索引使用 [Timestamp]?据我所知,这不是最优的,因为索引将是不合理的,特别是由于时间戳中的毫秒和秒
  • 我用这个问题的答案作为参考:stackoverflow.com/questions/17381875/…

标签: sql sql-server performance sql-order-by query-optimization


【解决方案1】:

我可能过于简单化了,但为什么不简单地在存储整个时间戳的列上创建一个索引呢?

CREATE INDEX cidx_time2 ON [dbo].[MyTable] ([Timestamp] DESC)

然后,你可以这样做:

SELECT TOP(100) * FROM [dbo].[MyTable] ORDER BY [[Timestamp] DESC

或者,如果您出于某种原因需要在 order by 子句中设置两个时间戳,那么您需要在两列上都有一个索引:

CREATE INDEX cidx_time3 ON [dbo].[MyTable] ([TimestampRounded] DESC, [Timestamp] DESC);

然后您可以运行原始查询:

SELECT TOP(100) * FROM [dbo].[MyTable] ORDER BY [TimestampRounded] DESC, [Timestamp] DESC

【讨论】:

  • 我了解到,如果我的聚集索引包含毫秒、秒和分钟,那么 INSERT 会非常乏味。这就是为什么我首先使用圆角列
  • 查看这个问题的答案:stackoverflow.com/questions/17381875/…
  • 不,那是错误的。无论哪种方式,它都是一个 64 位的值进行排序,它将具有相同的性能。当然,添加 another 列会让它变得更好
  • 怎么了?你是说我应该删除 Rounded 列并在 [Timestamp] 上使用聚集索引?
  • @Smith5727 最好忽略您链接的已接受答案 - 短语 the index has to account for every place within the datetime. This becomes very large spatially and bulky. 向我表明作者可能不知道索引是如何工作的
【解决方案2】:

指定WITH TIES,这样 sqlserver 将返回[最多]“几千”行,这些行具有所有相同的舍入时间戳值,然后按精确时间戳对这几千行排序,以获得真正最新的 100;比数百万排序更快

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-09
    • 1970-01-01
    • 1970-01-01
    • 2021-12-28
    相关资源
    最近更新 更多