在这个有争议的问题上,我无法得到明确的答案. MSDN文档提到
集群
聚簇索引根据键值对表或视图中的数据行进行排序和存储.这些是索引定义中包含的列.每个表只能有一个聚簇索引,因为数据行本身只能按一个顺序排序.
表中的数据行以排序顺序存储的唯一时间是表包含聚簇索引.当表具有聚簇索引时,该表称为聚簇表.如果表没有聚簇索引,则其数据行存储在称为堆的无序结构中.
虽然我看到了大部分答案
回答否定.
它是什么 ?
只是为了清楚.据推测,您正在谈论一个简单的查询,例如:
select *
from table t;
Run Code Online (Sandbox Code Playgroud)
首先,如果表中的所有数据都适合单个页面并且表上没有其他索引,那么我很难想象一个结果集未按主键排序的情况.但是,这是因为我认为最合理的查询计划需要全表扫描,而不是因为SQL或SQL Server中的任何要求(记录或其他).如果没有显式order by,则结果集中的排序是查询计划的结果.
这是问题的核心.当您谈论结果集的排序时,您实际上是在谈论查询计划.而且,主键排序的假设实际上意味着您假设查询使用全表扫描.具有讽刺意味的是,人们在没有真正理解"为什么"的情况下做出了假设.此外,人们倾向于从小例子中概括(好吧,这是人类智能基础的一部分).不幸的是,他们始终认为,对小型表的简单查询的结果集总是按主键顺序排列,并推广到较大的表.在此示例中,归纳步骤不正确.
有什么可以改变这个?另外,我认为如果满足以下条件,全表扫描将以主键顺序返回数据:
我不是说这总是如此.在这些情况下,这样的查询将使用从表开始处开始的全表扫描,这似乎是合理的.
即使在小桌子上,你也会感到意外.考虑:
select NonPrimaryKeyColumn
from table
Run Code Online (Sandbox Code Playgroud)
查询计划可能会决定使用索引table(NonPrimaryKeyColumn)而不是进行全表扫描.主键不会对结果进行排序(除非偶然).我表明,因为索引可以用于多种目的,不只是这个例子order by或where过滤.
如果您使用数据库的多线程实例并且具有合理大小的表,order by则无需明确排序即可快速了解结果.
最后,SQL Server有一个非常聪明的优化器.我认为order by在查询中有一些不情愿,因为用户认为它会自动进行排序.SQL Server很难找到查询的最佳执行计划.如果它order by因为计划的其余部分而认识到这是多余的,那么这order by将不会导致排序.
当然,您希望保证结果的排序,您需要order by在最外层的查询中.甚至像这样的查询:
select *
from (select top 100 t.* from t order by col1) t
Run Code Online (Sandbox Code Playgroud)
不保证结果在最终结果集中排序.你真的需要这样做:
select *
from (select top 100 t.* from t order by col1) t
order by col1;
Run Code Online (Sandbox Code Playgroud)
以特定顺序保证结果.这种行为被记录在这里.
如果没有ORDER BY,即使您有聚簇索引,也没有默认的排序顺序
在这个链接中有一个很好的例子:
CREATE SCHEMA Data AUTHORIZATION dbo
GO
CREATE TABLE Data.Numbers(Number INT NOT NULL PRIMARY KEY)
GO
DECLARE @ID INT;
SET NOCOUNT ON;
SET @ID = 1;
WHILE @ID < 100000 BEGIN
INSERT INTO Data.Numbers(Number)
SELECT @ID;
SET @ID = @ID+1;
END
CREATE TABLE Data.WideTable(ID INT NOT NULL
CONSTRAINT PK_WideTable PRIMARY KEY,
RandomInt INT NOT NULL,
CHARFiller CHAR(1000))
GO
CREATE VIEW dbo.WrappedRand
AS
SELECT RAND() AS random_value
GO
CREATE ALTER FUNCTION dbo.RandomInt()
RETURNS INT
AS
BEGIN
DECLARE @ret INT;
SET @ret = (SELECT random_value*1000000 FROM dbo.WrappedRand);
RETURN @ret;
END
GO
INSERT INTO Data.WideTable(ID,RandomInt,CHARFiller)
SELECT Number, dbo.RandomInt(), 'asdf'
FROM Data.Numbers
GO
CREATE INDEX WideTable_RandomInt ON Data.WideTable(RandomInt)
GO
SELECT TOP 100 ID FROM Data.WideTable
Run Code Online (Sandbox Code Playgroud)
OUTPUT:
1407
253
9175
6568
4506
1623
581
Run Code Online (Sandbox Code Playgroud)
如您所见,优化器已选择使用非聚集索引来满足此SELECT TOP查询.
显然,除非明确使用ORDER BY子句,否则不能假定您的结果是有序的.
| 归档时间: |
|
| 查看次数: |
2645 次 |
| 最近记录: |