对所有空值的列进行排序有奇怪的行为

Mau*_*odi -2 index sql-server sorting

我的表中有一个列,其中特定列中的所有值都为空。现在,当我按此列 ASC 和 DESC 排序时,我应该得到与我的假设相同的结果。但我得到了不同的结果。我无法理解这种奇怪行为背后的原因。如果我删除我在这个表上创建的聚集索引,它会给出预期的结果,但通过保留该索引它不会。索引与此列无关。

该列将来会有值,同时这种行为在排序时会令人困惑。

谁能告诉为什么会发生?以及如何摆脱这个?

Aar*_*and 8

如果您只按该列排序,那么 SQL Server 没有什么可排序的,因此就好像您根本没有添加 ORDER BY 子句一样。如果您没有明确要求一个表格(或者如果您要求一个无效的表格),则表格没有固有的顺序,因此当您说“摆脱这个”时,您期望什么行为并不清楚。如果 SQL Server 无法对数据进行排序,因为没有要排序的内容,它将以最有效的方式将数据返回给您。由于一系列因素,这可能会随着时间的推移而改变。

想想您要 SQL Server 做什么。你是说按这些值排序,但这些值都是一样的。如果所有值都是1, or 'Bob', or ,您期望什么顺序2018-05-24?同样的事情,SQL Server 将所有值排列起来,尝试重新排列它们,当它发现它们都相同时,它无关紧要。因此,它可能会返回行而根本不需要排序,或者它可以任意地按照索引的顺序(如果存在的话)或聚集索引。就像将来对数据的更改可能会使 ORDER BY 函数不同一样,对索引的更改可能会使当前的任意和未定义的顺序表现不同。

如果我的衣橱里放满了朴素的海军蓝 T 恤,我让你根据颜色重新整理衣橱,你愿意做多少工作?你认为你需要做任何工作吗?你只是耸耸肩说“完成”。也许我用夏普在标签上写了一些数字,根据谁知道什么来决定排名,但如果我不告诉你这些数字在那里,我不应该指望你知道它们,别介意排序被他们。

如果您希望在 ORDER BY 中的第一列始终为相同值时对任何其他列进行特定顺序,请将其他列添加到 ORDER BY。然后它们可以用来打破关系。

如果您期望某个特定顺序会影响基于其他列对行进行排序的方式,您需要通过在 ORDER BY 中包含这些其他列来要求它。


Eri*_*ing 5

SQL Server 在较高级别上具有以下访问索引的方法:

  • 分配顺序
  • 索引顺序(聚集,覆盖非聚集)
  • 索引无序(聚集,覆盖非聚集)

我将留下可能需要查找的非覆盖非聚集索引。

有堆

这是一个没有聚集索引的表,最常见的是分配顺序扫描。即,按页和值插入表的顺序读取页和值的扫描。

CREATE TABLE #el_heapo (id INT, yourmom INT)

INSERT #el_heapo ( id )
VALUES ( 1 )
INSERT #el_heapo ( id )
VALUES ( 2 )
INSERT #el_heapo ( id )
VALUES ( 3 )
INSERT #el_heapo ( id )
VALUES ( 4 )
INSERT #el_heapo ( id )
VALUES ( 5 )
Run Code Online (Sandbox Code Playgroud)

如果我查询这个表,我会“按顺序”得到五行,但这仅仅是因为扫描数据的方式。

SELECT *
FROM #el_heapo AS eh

+----+---------+
| id | yourmom |
+----+---------+
|  1 | NULL    |
|  2 | NULL    |
|  3 | NULL    |
|  4 | NULL    |
|  5 | NULL    |
+----+---------+
Run Code Online (Sandbox Code Playgroud)

我完全不能依赖这个顺序。如果我再插入五行,结果就会改变。

INSERT #el_heapo ( id )
VALUES ( 1 )
INSERT #el_heapo ( id )
VALUES ( 2 )
INSERT #el_heapo ( id )
VALUES ( 3 )
INSERT #el_heapo ( id )
VALUES ( 4 )
INSERT #el_heapo ( id )
VALUES ( 5 )
Run Code Online (Sandbox Code Playgroud)

如果我运行相同的查询,我会得到这个:

+----+---------+
| id | yourmom |
+----+---------+
|  1 | NULL    |
|  2 | NULL    |
|  3 | NULL    |
|  4 | NULL    |
|  5 | NULL    |
|  1 | NULL    |
|  2 | NULL    |
|  3 | NULL    |
|  4 | NULL    |
|  5 | NULL    |
+----+---------+
Run Code Online (Sandbox Code Playgroud)

请注意,添加排序依据yourmom将为我们提供相同的结果。我可以按id我想要的任何方式订购并获得结果。

我为什么要谈论堆?

因为你说聚集索引与NULL列无关。你错了。聚集索引(在 SQL Server 中)是您的所有表数据,按您选择的键列排序。

您的NULL列将位于聚集索引的叶级。如果我在表上创建聚集索引,我的结果将再次改变。

CREATE CLUSTERED INDEX cx_id ON #el_heapo (id);

+----+---------+
| id | yourmom |
+----+---------+
|  1 | NULL    |
|  1 | NULL    |
|  2 | NULL    |
|  2 | NULL    |
|  3 | NULL    |
|  3 | NULL    |
|  4 | NULL    |
|  4 | NULL    |
|  5 | NULL    |
|  5 | NULL    |
+----+---------+
Run Code Online (Sandbox Code Playgroud)

扫描不是有序的,但它是从索引的一端开始并读取每一页的单个线程。跳来跳去是没有意义的。

事情变得草率有更多的行和并行计划。如果我们在这里添加一百万个重复行,然后尝试按以下顺序排序yourmom

INSERT #el_heapo ( id )
SELECT TOP 1000000
       x.n % 5 + 1
FROM   (   
        SELECT     ROW_NUMBER() OVER ( ORDER BY @@SPID )
        FROM       sys.messages AS m
        CROSS JOIN sys.messages AS m2 
       ) AS x(n);

SELECT eh.id
FROM #el_heapo AS eh
ORDER BY eh.yourmom
Run Code Online (Sandbox Code Playgroud)

行不会全部按yourmom和 then 的顺序返回idid如果您向下滚动一点,在我们转储到第二组 1-5 行之后,该列的排序方式与分配顺序扫描非常相似。1将重复,2将重复,3将重复,4将重复,5将重复,然后整个序列将重复。

亚伦的回答很好,除了他声称拥有海军蓝马球衫。他唯一拥有的马球衫是黑色和红色的,上面有公司的标志,但我认为可以使用一些插图。

希望这可以帮助!