表定义中的列顺序重要吗?

Nic*_*mas 38 sql-server-2008 database-design sql-server database-internals

定义表时,按目的对逻辑组中的列和组本身进行排序会很有帮助。表中列的逻辑顺序向开发人员传达了意义,是良好风格的元素。

这是清楚的。

然而,不清楚的是,表中列的逻辑顺序是否对其在存储层的物理顺序有任何影响,或者是否有任何其他人可能关心的影响。

除了对样式的影响之外,列顺序是否重要?

Stack Overflow 上有一个关于这个的问题,但它缺乏权威的答案。

Mar*_*ith 24

表中列的逻辑顺序对它们在存储层的物理顺序有任何影响吗?是的。

它是否重要是一个不同的问题,我无法回答(还)。

与 Paul Randal 的关于记录剖析的频繁链接文章中描述的方式类似,让我们看一下带有 DBCC IND 的简单的两列表:

SET STATISTICS IO OFF;
SET STATISTICS TIME OFF;

USE master;
GO

IF DATABASEPROPERTY (N'RowStructure', 'Version') > 0 DROP DATABASE RowStructure;
GO

CREATE DATABASE RowStructure;
GO

USE RowStructure;
GO

CREATE TABLE FixedLengthOrder
(
    c1 INT IDENTITY(1,1) PRIMARY KEY CLUSTERED
    , c2 CHAR(10) DEFAULT REPLICATE('A', 10) NOT NULL
    , c3 CHAR(10) DEFAULT REPLICATE('B', 10) NOT NULL  
);
GO

INSERT FixedLengthOrder DEFAULT VALUES;
GO

DBCC IND ('RowStructure', 'FixedLengthOrder', 1);
GO
Run Code Online (Sandbox Code Playgroud)

DBCC IND 输出

上面的输出表明我们需要查看第 89 页:

DBCC TRACEON (3604);
GO
DBCC PAGE ('RowStructure', 1, 89, 3);
GO
Run Code Online (Sandbox Code Playgroud)

在 DBCC PAGE 的输出中,我们看到 c1 在 c2 的 'B' 之前塞满了字符 'A':

Memory Dump @0x000000000D25A060

0000000000000000:   10001c00 01000000 41414141 41414141 †........AAAAAAAA
0000000000000010:   41414242 42424242 42424242 030000††††AABBBBBBBBBB...
Run Code Online (Sandbox Code Playgroud)

仅仅因为,让我们RowStructure.mdf用十六进制编辑器打开并确认 'A' 字符串在 'B' 字符串之前:

AAAAAAAA

现在重复测试但颠倒字符串的顺序,将 'B' 字符放在 c1 中,将 'A' 字符放在 c2 中:

CREATE TABLE FixedLengthOrder
(
    c1 INT IDENTITY(1,1) PRIMARY KEY CLUSTERED
    , c2 CHAR(10) DEFAULT REPLICATE('B', 10) NOT NULL
    , c3 CHAR(10) DEFAULT REPLICATE('A', 10) NOT NULL  
);
GO
Run Code Online (Sandbox Code Playgroud)

这次我们的 DBCC PAGE 输出不同,'B' 字符串首先出现:

Memory Dump @0x000000000FC2A060

0000000000000000:   10001c00 01000000 42424242 42424242 †........BBBBBBBB 
0000000000000010:   42424141 41414141 41414141 030000††††BBAAAAAAAAAA... 
Run Code Online (Sandbox Code Playgroud)

再次,为了咯咯的笑声,让我们检查数据文件的十六进制转储:

BBBBBBBBBB

正如记录剖析所解释的那样,记录的固定长度和可变长度列存储在不同的块中。逻辑上交错的固定和可变列类型与物理记录无关。但是,在每个块中,列的顺序确实映射到数据文件中的字节顺序。

CREATE TABLE FixedAndVariableColumns
(
    c1 INT IDENTITY(1,1) PRIMARY KEY CLUSTERED
    , c2 CHAR(10) DEFAULT REPLICATE('A', 10) NOT NULL
    , c3 VARCHAR(10) DEFAULT REPLICATE('B', 10) NOT NULL  
    , c4 CHAR(10) DEFAULT REPLICATE('C', 10) NOT NULL
    , c5 VARCHAR(10) DEFAULT REPLICATE('D', 10) NOT NULL
    , c6 CHAR(10) DEFAULT REPLICATE('E', 10) NOT NULL  
);
GO

Memory Dump @0x000000000E07C060

0000000000000000:   30002600 01000000 41414141 41414141 †0.&.....AAAAAAAA 
0000000000000010:   41414343 43434343 43434343 45454545 †AACCCCCCCCCCEEEE 
0000000000000020:   45454545 45450600 00020039 00430042 †EEEEEE.....9.C.B 
0000000000000030:   42424242 42424242 42444444 44444444 †BBBBBBBBBDDDDDDD 
0000000000000040:   444444†††††††††††††††††††††††††††††††DDD
Run Code Online (Sandbox Code Playgroud)

也可以看看:

列顺序无关紧要……一般来说,但是 – 视情况而定!


Mar*_*sen 7

如果你没有定义聚集索引,你会得到一个堆表。对于堆表,您在读取数据时将始终进行扫描,因此将读取整行,从而使列的顺序成为一个有争议的问题。

一旦您定义了聚集索引,数据就会在物理上重新排列以符合您指定的列的物理顺序——此时,物理顺序变得很重要。物理顺序是根据您使用的谓词确定寻找运算符资格的因素。

虽然我不记得在任何地方读过它,但我认为 SQL Server 不保证堆的列的物理顺序,而它会保证索引。要回答您的问题,不,定义中列的顺序应该无关紧要,因为它们在读取数据时无关紧要(请注意,这适用于堆 - 索引是另一回事)。

更新
实际上你在问两个问题——“表中列的逻辑顺序是否对它们在存储层的物理顺序有任何影响”是否定的。元数据定义的逻辑顺序不必与物理顺序相同。我认为您正在寻找的答案是 CREATE TABLE 中的逻辑顺序是否在创建时产生相同的物理顺序 - 我不知道,对于堆 - 尽管有上面的警告。


Tod*_*ett 2

根据我所看到和阅读的内容,SQL Server 中的列顺序没有区别。存储引擎将列放置在行上,无论它们在 CREATE TABLE 语句中如何指定。话虽如此,我确信存在一些非常孤立的边缘情况,这确实很重要,但我认为您将很难就这些问题获得单一的明确答案。Paul Randal 的“存储引擎内部”博客类别的帖子是我所知道的有关存储引擎如何工作的所有详细信息的最佳来源。我认为您必须研究存储工作的所有不同方式以及针对所有用例的矩阵,以找到顺序重要的边缘情况。除非指出适用于我的情况的特定边缘情况,否则我只是在 CREATE TABLE 上对列进行逻辑排序。我希望这有帮助。