定义表时,按目的对逻辑组中的列和组本身进行排序很有帮助。表中列的逻辑顺序将含义传达给开发人员,并且是一个良好样式的元素。
很清楚
但是,尚不清楚的是,表中列的逻辑顺序是否会对存储层的物理顺序有任何影响,或者是否有其他可能影响的影响。
除了对样式的影响之外,列顺序是否重要?
定义表时,按目的对逻辑组中的列和组本身进行排序很有帮助。表中列的逻辑顺序将含义传达给开发人员,并且是一个良好样式的元素。
很清楚
但是,尚不清楚的是,表中列的逻辑顺序是否会对存储层的物理顺序有任何影响,或者是否有其他可能影响的影响。
除了对样式的影响之外,列顺序是否重要?
Answers:
表中列的逻辑顺序是否会对存储层的物理顺序有影响?是。
不管是否重要,这是我无法回答的另一个问题。
以类似于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
上面的输出显示我们需要看一下第89页:
DBCC TRACEON (3604);
GO
DBCC PAGE ('RowStructure', 1, 89, 3);
GO
在DBCC PAGE的输出中,我们看到c1塞满了c2的“ B”之前的字符“ A”:
Memory Dump @0x000000000D25A060
0000000000000000: 10001c00 01000000 41414141 41414141 †........AAAAAAAA
0000000000000010: 41414242 42424242 42424242 030000††††AABBBBBBBBBB...
正因为如此,让我们RowStructure.mdf
用十六进制编辑器打开胸围并确认'A'字符串位于'B'字符串之前:
现在重复测试,但要颠倒字符串的顺序,将'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
这次,我们的DBCC PAGE输出是不同的,并且'B'字符串首先出现:
Memory Dump @0x000000000FC2A060
0000000000000000: 10001c00 01000000 42424242 42424242 †........BBBBBBBB
0000000000000010: 42424141 41414141 41414141 030000††††BBAAAAAAAAAA...
再次,只为咯咯地笑,让我们检查数据文件的十六进制转储:
正如“记录剖析”所述,记录的固定长度和可变长度列存储在不同的块中。逻辑上交错的固定列和可变列类型与物理记录无关。但是,在每个块中,列的顺序确实映射到数据文件中字节的顺序。
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
也可以看看:
C
不合适,并进入其自己的扩展页。因此,select A, B
从YourTable只需读取一半的页面select A, C from YourTable
。
"Whether it matters or not is a different issue that I can't answer (yet)."
:列的顺序会显着影响性能。此外,甚至会影响错误!检查一下 -演示2更好地显示了我的想法
如果不定义聚簇索引,则会得到一个堆表。对于堆表,您在读取数据时将始终进行扫描,因此将读取整行,从而使列顺序成为问题。
定义聚簇索引后,将按照您指定的方式对数据进行物理重新排列,使其与列的物理顺序保持一致-此时,物理顺序变得很重要。实际顺序是根据您使用的谓语确定寻求运营商资格的因素。
虽然我不记得在任何地方阅读它,但我假设SQL Server不保证堆的列的物理顺序,而可以保证索引的物理顺序。要回答您的问题,不,定义中的列顺序无关紧要,因为它们在读取数据时无关紧要(请注意,这仅适用于堆-索引是另一回事)。
更新
实际上,您在问两个问题-“表中列的逻辑顺序是否会影响它们在存储层的物理顺序”是“否”。由元数据定义的逻辑顺序不必与物理顺序相同。我正在寻找的答案是,尽管上面有警告,但CREATE TABLE中的逻辑顺序是否会导致创建时的物理顺序相同(对于堆,我不知道)。
CREATE TABLE
语句进行的(除了CI键列确实在该部分中排在第一位)。尽管如果ALTER COLUMN
更改数据类型/列长度,则列的顺序可以更改。我能想到的唯一较小的情况是,变量长度部分结尾处带有空字符串或NULL的列在列偏移数组中根本不占空间(由Kalen Delaney在2008年内部手册中演示)