sql - Top 1 如何在 sql server 2012 中工作

标签 sql sql-server sql-server-2012

我有一个包含以下数据的表格

  IF OBJECT_ID('TEMPDB.DBO.#t1', 'U') IS NOT NULL
            DROP TABLE #t1;
CREATE TABLE #t1
    ([c1] varchar(100), [c2] varchar(10), [c3] varchar(100), [c4] varchar(100))
;

INSERT INTO #t1
    ([c1], [c2], [c3], [c4])
VALUES
    (93, '60-1.1.1.', 60, 3),
    (104, '60-1.2.1.', 60, 3),
    (102, '60-1.1.2.', 60, 3),
    (101, '60-1.2.2.', 60, 3),
    (92, '60-1.1.3.', 60, 3),
    (96, '60-1.2.3.', 60, 3),
    (103, '60-1.1.4.', 60, 3),
    (94, '60-1.2.4.', 60, 3),
    (105, '60-1.2.5.', 60, 3),
    (97, '60-1.2.6.', 60, 3),
    (99, '60-1.2.7.', 60, 3),
    (100, '60-1.2.8.', 60, 3),
    (98, '60-1.2.9.', 60, 3),
    (95, '60-1.2.10.', 60, 3),
    (91, '60-1.2.11.', 60, 3)
;
select * from #t1

表格结果如下

enter image description here

select * from #t1 order by c3,c4

enter image description here

现在我运行了以下查询,得到了预期的结果

select  Cast(c4 AS VARCHAR(2)) + '~'+ Cast(c1 AS VARCHAR(100)) AS c5,* from #t1

上述查询结果如下

enter image description here

现在我已经使用 top 1 来获取一条记录,我编写的代码如下

select top 1 Cast(c4 AS VARCHAR(2)) + '~'+ Cast(c1 AS VARCHAR(100)) AS c5,* from #t1

上述查询结果如下

enter image description here

现在我使用了 top 和 order by 子句,然后我得到了以下结果

select top 1 Cast(c4 AS VARCHAR(2)) + '~'+ Cast(c1 AS VARCHAR(100)) AS c5,*
 from #t1 order by c3,c4

enter image description here

问题:为什么最后 2 个查询的结果发生了变化,因为我希望得到相同的结果?

让我这样问你:

当我执行没有 order by 的 top 1 查询时,我得到了 93 个记录值,因此当我执行带有 order by 列的 top 1 查询时,我期望得到相同的结果。根据我的假设,在查询中,按 Caluse 排序没有影响

提前致谢

编辑 1

即使我执行了 100 次结果都是一样的

编辑2

  • 服务器 1

实际上我已经创建了一个主表并插入了上述记录。在两个不同的 session 中运行最后两个查询,结果是相同的

  • 服务器 2

在第二台服务器中完成上述操作(与服务器 1 中的步骤相同)。运行最后两个 top 1 查询,两个 session 中的结果相同。

服务器和 session 中的结果似乎相同。

结果

enter image description here

执行计划 enter image description here

最佳答案

如果没有 ORDER BY 子句,则 Sql Server允许它想要的任何顺序显示结果。这意味着您可能会得到与预期不同的结果。即使您有 ORDER BY 子句,如果结果集中的某些记录处于同一位置,Sql Server 可能会使用它想要的任何顺序来排列这些记录。

通常,当未指定顺序时,Sql Server 将按照最快的顺序提供结果。这意味着随着时间的推移,结果将趋于一致,这取决于主键顺序或索引顺序等。在您的简单示例中,如果“基本”顺序发生变化,那将是令人惊讶的。

但重要的是要记住,这种排序根本无法保证。在实际生产环境中,如果您不指定顺序,则结果可能会在执行之间发生变化。发生这种情况的原因有很多,但一个基本的例子是优化,其中两个查询可能会搭载相同的索引或表查找,而第二个查询会在第一个查询的中间进行查找。另一个原因是表上的统计信息或行计数发生变化,使得 Sql Server 决定使用(或不使用)与以前不同的索引。

因此,如果您在使用像 TOP 这样的选择器时确实关心获取特定记录,那么您确实也应该使用 ORDER BY,并确保您足够具体明确。

<小时/>

对于此特定数据和查询示例,您有一个不带 ORDER BY 子句的示例和一个带 ORDER BY 子句的示例,但第二个示例的子句仅按列 c3c4 排序。 这些列对于每条记录都具有相同的值。这意味着 Sql Server 仍然可以自由地使用最方便的顺序,因为一切都是相关的。

但是,这并不意味着 Sql Server 将在第二个查询中使用与第一个查询相同的顺序。添加 ORDER BY 子句迫使 Sql Server 至少查看并评估结果集,然后才能知道哪条记录属于哪个位置,并且该过程可以改变结果在内存中的排列,制作一个全新的订单似乎是最方便的。

因此我们发现,如果您关心结果,您不仅需要一个 ORDER BY 子句,而且该子句必须具有足够的选择性以保证您想要的顺序。如果您希望显示特定的 c1 值,则应在 ORDER BY 子句中包含 c1

关于sql - Top 1 如何在 sql server 2012 中工作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44705632/

相关文章:

mysql - SQL游戏区查询

MySQL返回两个日期之间的所有记录

sql-server - 如何确定文本是否可以转换为日期?

stored-procedures - SQL Server 2012 存储过程被自动删除

sql-server - 每天只运行一次的触发器

sql - 验证 varbinary 列的数据完整性

sql - 可串行化隔离级别原子性

mysql - SQL 嵌套 if 在具有存在并检查时间戳的函数内部

用于查找第一个缺失序列字符串(前缀+无)的 SQL 查询

java - 从 Java 程序到 mssql 的 SSL 连接