SQL order by 分两步
Posted
技术标签:
【中文标题】SQL order by 分两步【英文标题】:SQL order by in two steps 【发布时间】: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]?据我所知,这不是最优的,因为索引将是不合理的,特别是由于时间戳中的毫秒和秒
我用这个问题的答案作为参考:***.com/questions/17381875/…
【参考方案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 会非常乏味。这就是为什么我首先使用圆角列 查看这个问题的答案:***.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;比数百万排序更快
【讨论】:
以上是关于SQL order by 分两步的主要内容,如果未能解决你的问题,请参考以下文章
sql [mysql:ORDER BY中的CASE]在mysql的ORDER BY中使用CASE。 #mysql #sql