Sql-Server

表定義中的列順序是否重要?

  • January 27, 2016

定義表時,按目的對邏輯組中的列和組本身進行排序會很有幫助。表格中列的邏輯順序向開發人員傳達了意義,並且是良好風格的一個元素。

這很清楚。

然而,不清楚的是,表中列的邏輯順序是否對它們在儲存層的物理順序有任何影響,或者是否有任何其他人可能關心的影響。

除了對樣式的影響之外,列順序是否重要?

Stack Overflow上有一個關於這個的問題,但它缺乏權威的答案。

表中列的邏輯順序對它們在儲存層的物理順序有影響嗎?是的。

是否重要是一個不同的問題,我(還)無法回答。

以與 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

DBCC IND 輸出

上面的輸出表明我們需要查看第 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... 

再次,只是為了咯咯笑,讓我們檢查數據文件的十六進制轉儲:

BBBBBBBBBB

正如Anatomy of a Record解釋的那樣,記錄的固定和可變長度列儲存在不同的塊中。邏輯上交錯的固定和可變列類型與物理記錄無關。但是,在每個塊中,列的順序確實映射到數據文件中的字節順序。

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

也可以看看:

列順序無關緊要……一般來說,但是 - 它取決於!

如果你沒有定義聚集索引,你會得到一個堆表。對於堆表,您將始終在讀取數據時進行掃描,因​​此將讀取整行,從而使列的順序成為一個有爭議的問題。

一旦定義了聚集索引,數據就會在物理上重新排列以符合您指定的列的物理順序——此時,物理順序變得很重要。物理順序是根據您使用的謂詞確定搜尋操作員資格的原因。

雖然我不記得在任何地方讀過它,但我假設 SQL Server 不保證堆的列的物理順序,但它會保證索引。要回答您的問題,不,定義中列的順序應該無關緊要,因為它們在讀取數據時無關緊要(請注意,這適用於堆 - 索引是另一回事)。

更新

實際上,您要問兩個問題-“表中列的邏輯順序是否對它們在儲存層的物理順序有任何影響”是否定的。元數據定義的邏輯順序不必與物理順序相同。我收集到您正在尋找的答案是 CREATE TABLE 中的邏輯順序是否導致創建時的物理順序相同 - 我不知道,對於堆 - 儘管有上面的警告。

引用自:https://dba.stackexchange.com/questions/18719