再說一下表分區
網上表分區的文章成千上萬,但是分區之后表數據的分布和流向都沒有說
首先要說明的是表分區的分區不是指頁面存儲概念的分區,我用下面的圖來表示
他們是沒有關系的
正式開始
SQL腳本如下:
1 USE master 2 GO 3 4 --創建數據庫 5 CREATE DATABASE [Test] 6 GO 7 8 USE [Test] 9 GO 10 11 12 --1.創建文件組 13 ALTER DATABASE [Test] 14 ADD FILEGROUP [FG_TestUnique_Id_01] 15 16 ALTER DATABASE [Test] 17 ADD FILEGROUP [FG_TestUnique_Id_02] 18 19 ALTER DATABASE [Test] 20 ADD FILEGROUP [FG_TestUnique_Id_03] 21 22 --2.創建文件 23 ALTER DATABASE [Test] 24 ADD FILE 25 (NAME = N'FG_TestUnique_Id_01_data',FILENAME = N'E:\FG_TestUnique_Id_01_data.ndf',SIZE = 1MB, FILEGROWTH = 1MB ) 26 TO FILEGROUP [FG_TestUnique_Id_01]; 27 28 ALTER DATABASE [Test] 29 ADD FILE 30 (NAME = N'FG_TestUnique_Id_02_data',FILENAME = N'E:\FG_TestUnique_Id_02_data.ndf',SIZE = 1MB, FILEGROWTH = 1MB ) 31 TO FILEGROUP [FG_TestUnique_Id_02]; 32 33 ALTER DATABASE [Test] 34 ADD FILE 35 (NAME = N'FG_TestUnique_Id_03_data',FILENAME = N'E:\FG_TestUnique_Id_03_data.ndf',SIZE = 1MB, FILEGROWTH = 1MB ) 36 TO FILEGROUP [FG_TestUnique_Id_03];
創建分區函數和分區方案
我們創建了一個用於數據類型為int的分區函數,按照數值來划分
文件組 分區 取值范圍
[FG_TestUnique_Id_01] 1 (小於2, 2] --包括2
[FG_TestUnique_Id_02] 2 [3, 4]
[FG_TestUnique_Id_03] 3 (4,大於4) --不包括4
1 --3.創建分區函數 2 --我們創建了一個用於數據類型為int的分區函數,按照數值來划分 3 --文件組 分區 取值范圍 4 --[FG_TestUnique_Id_01] 1 (小於2, 2]--包括2 5 --[FG_TestUnique_Id_02] 2 [3, 4] 6 --[FG_TestUnique_Id_03] 3 (4,大於4) --不包括4 7 8 CREATE PARTITION FUNCTION 9 Fun_TestUnique_Id(INT) AS 10 RANGE LEFT 11 FOR VALUES(2,4) 12 13 14 15 16 --4.創建分區方案 17 CREATE PARTITION SCHEME 18 Sch_TestUnique_Id AS 19 PARTITION Fun_TestUnique_Id 20 TO([FG_TestUnique_Id_01],[FG_TestUnique_Id_02],[FG_TestUnique_Id_03])
建立分區表
1 --5.創建分區表 2 CREATE TABLE testPartionTable 3 ( 4 id INT NOT NULL, 5 itemno CHAR(20), 6 itemname CHAR(40) 7 )ON Sch_TestUnique_Id([id]) 8 9 10 INSERT INTO [dbo].[testPartionTable] ( [id], [itemno], [itemname] ) 11 SELECT 1,'1','中國' UNION ALL 12 SELECT 2,'2','法國' UNION ALL 13 SELECT 3,'3','美國' UNION ALL 14 SELECT 4,'4','英國' UNION ALL 15 SELECT 5,'5','德國'
查看邊界值點
1 --查看邊界值點 2 select * from sys.partition_range_values 3 GO
查看表數據
1 SELECT * FROM [dbo].[testNonPartionTable] 2 GO
我們看一下當前數據庫的情況
1 EXEC [sys].[sp_helpdb] @dbname = test -- sysname 2 GO
FG_TestUnique_Id_0X這三個文件組建立在三個ndf文件上,三個ndf文件都位於E盤
而fileid分別是3、4、5
我們看一下表的頁面分配情況

1 CREATE TABLE DBCCResult ( 2 PageFID NVARCHAR(200), 3 PagePID NVARCHAR(200), 4 IAMFID NVARCHAR(200), 5 IAMPID NVARCHAR(200), 6 ObjectID NVARCHAR(200), 7 IndexID NVARCHAR(200), 8 PartitionNumber NVARCHAR(200), 9 PartitionID NVARCHAR(200), 10 iam_chain_type NVARCHAR(200), 11 PageType NVARCHAR(200), 12 IndexLevel NVARCHAR(200), 13 NextPageFID NVARCHAR(200), 14 NextPagePID NVARCHAR(200), 15 PrevPageFID NVARCHAR(200), 16 PrevPagePID NVARCHAR(200) 17 ) 18 19 --TRUNCATE TABLE [dbo].[DBCCResult] 20 INSERT INTO DBCCResult EXEC ('DBCC IND(test,testPartionTable,-1) ') 21 22 SELECT * FROM [dbo].[DBCCResult] ORDER BY [PageType] DESC
1 SELECT * 2 FROM sys.dm_db_index_physical_stats(DB_ID('test'), 3 OBJECT_ID('testPartionTable'), NULL, 4 NULL, 'detailed')
從上面兩個圖我們可以得知
-----------------------------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------------------------
分區號1~3對應的文件組名和ndf文件名分別是:
分區號1 (PartitionNumber1)-》文件組FG_TestUnique_Id_01-》E:\FG_TestUnique_Id_01_data.ndf
分區號2 (PartitionNumber2)-》文件組FG_TestUnique_Id_02-》E:\FG_TestUnique_Id_02_data.ndf
分區號3 (PartitionNumber3)-》文件組FG_TestUnique_Id_03-》E:\FG_TestUnique_Id_03_data.ndf
表中只有一個數據頁面8 和一個IAM頁面9
但是每個ndf文件里面卻都存儲了一份數據頁面8 和一份IAM頁面9
而且每個ndf文件里面 數據頁面存儲的內容都不一樣,雖然頁面編號一樣,都是8
數據頁面存儲的內容
我們來看一下每個ndf文件里面的數據頁面都存儲了些什么內容?
我們先來看一下testPartionTable表的objectID
1 SELECT OBJECT_ID('testPartionTable') AS 'OBJECTID'
先看FILEID為3的文件里面的數據頁面
1 DBCC TRACEON(3604,-1) 2 GO 3 DBCC PAGE(test,3,8,3) 4 GO

1 DBCC 執行完畢。如果 DBCC 輸出了錯誤信息,請與系統管理員聯系。 2 3 PAGE: (3:8) 4 5 6 BUFFER: 7 8 9 BUF @0x03DFDE90 10 11 bpage = 0x16EEE000 bhash = 0x00000000 bpageno = (3:8) 12 bdbid = 11 breferences = 0 bUse1 = 28337 13 bstat = 0x3c0000b blog = 0x212121bb bnext = 0x00000000 14 15 PAGE HEADER: 16 17 18 Page @0x16EEE000 19 20 m_pageId = (3:8) m_headerVersion = 1 m_type = 1 21 m_typeFlagBits = 0x4 m_level = 0 m_flagBits = 0x8000 22 m_objId (AllocUnitId.idObj) = 82 m_indexId (AllocUnitId.idInd) = 256 23 Metadata: AllocUnitId = 72057594043301888 24 Metadata: PartitionId = 72057594038321152 Metadata: IndexId = 0 25 Metadata: ObjectId = 2073058421 m_prevPage = (0:0) m_nextPage = (0:0) 26 pminlen = 68 m_slotCnt = 2 m_freeCnt = 7950 27 m_freeData = 238 m_reservedCnt = 0 m_lsn = (41:289:25) 28 m_xactReserved = 0 m_xdesId = (0:0) m_ghostRecCnt = 0 29 m_tornBits = 0 30 31 Allocation Status 32 33 GAM (3:2) = ALLOCATED SGAM (3:3) = ALLOCATED 34 PFS (3:1) = 0x61 MIXED_EXT ALLOCATED 50_PCT_FULL DIFF (3:6) = CHANGED 35 ML (3:7) = NOT MIN_LOGGED 36 37 Slot 0 Offset 0x60 Length 71 38 39 Record Type = PRIMARY_RECORD Record Attributes = NULL_BITMAP 40 Memory Dump @0x0A70C060 41 42 00000000: 10004400 01000000 31202020 20202020 †..D.....1 43 00000010: 20202020 20202020 20202020 d6d0b9fa † .... 44 00000020: 20202020 20202020 20202020 20202020 † 45 00000030: 20202020 20202020 20202020 20202020 † 46 00000040: 20202020 0300f8†††††††††††††††††††††† ... 47 48 Slot 0 Column 0 Offset 0x4 Length 4 49 50 id = 1 51 52 Slot 0 Column 1 Offset 0x8 Length 20 53 54 itemno = 1 55 56 Slot 0 Column 2 Offset 0x1c Length 40 57 58 itemname = 中國 59 60 Slot 1 Offset 0xa7 Length 71 61 62 Record Type = PRIMARY_RECORD Record Attributes = NULL_BITMAP 63 Memory Dump @0x0A70C0A7 64 65 00000000: 10004400 02000000 32202020 20202020 †..D.....2 66 00000010: 20202020 20202020 20202020 b7a8b9fa † .... 67 00000020: 20202020 20202020 20202020 20202020 † 68 00000030: 20202020 20202020 20202020 20202020 † 69 00000040: 20202020 0300f8†††††††††††††††††††††† ... 70 71 Slot 1 Column 0 Offset 0x4 Length 4 72 73 id = 2 74 75 Slot 1 Column 1 Offset 0x8 Length 20 76 77 itemno = 2 78 79 Slot 1 Column 2 Offset 0x1c Length 40 80 81 itemname = 法國 82 83 84 DBCC 執行完畢。如果 DBCC 輸出了錯誤信息,請與系統管理員聯系。
這個頁面是屬於testPartionTable表
1 Slot 0 Column 0 Offset 0x4 Length 4 2 3 id = 1 4 5 Slot 0 Column 1 Offset 0x8 Length 20 6 7 itemno = 1 8 9 Slot 0 Column 2 Offset 0x1c Length 40 10 11 itemname = 中國 12 13 Slot 1 Offset 0xa7 Length 71 14 15 16 17 Slot 1 Column 0 Offset 0x4 Length 4 18 19 id = 2 20 21 Slot 1 Column 1 Offset 0x8 Length 20 22 23 itemno = 2 24 25 Slot 1 Column 2 Offset 0x1c Length 40 26 27 itemname = 法國
FILEID為3的文件里面的數據頁面里存放了id為1和id為2的這兩條記錄
看FILEID為4的文件里面的數據頁面
1 DBCC TRACEON(3604,-1) 2 GO 3 DBCC PAGE(test,4,8,3) 4 GO

1 DBCC 執行完畢。如果 DBCC 輸出了錯誤信息,請與系統管理員聯系。 2 3 PAGE: (4:8) 4 5 6 BUFFER: 7 8 9 BUF @0x03E6777C 10 11 bpage = 0x19A78000 bhash = 0x00000000 bpageno = (4:8) 12 bdbid = 11 breferences = 0 bUse1 = 28520 13 bstat = 0x3c0000b blog = 0x212121bb bnext = 0x00000000 14 15 PAGE HEADER: 16 17 18 Page @0x19A78000 19 20 m_pageId = (4:8) m_headerVersion = 1 m_type = 1 21 m_typeFlagBits = 0x4 m_level = 0 m_flagBits = 0x8000 22 m_objId (AllocUnitId.idObj) = 83 m_indexId (AllocUnitId.idInd) = 256 23 Metadata: AllocUnitId = 72057594043367424 24 Metadata: PartitionId = 72057594038386688 Metadata: IndexId = 0 25 Metadata: ObjectId = 2073058421 m_prevPage = (0:0) m_nextPage = (0:0) 26 pminlen = 68 m_slotCnt = 2 m_freeCnt = 7950 27 m_freeData = 238 m_reservedCnt = 0 m_lsn = (41:289:49) 28 m_xactReserved = 0 m_xdesId = (0:0) m_ghostRecCnt = 0 29 m_tornBits = 0 30 31 Allocation Status 32 33 GAM (4:2) = ALLOCATED SGAM (4:3) = ALLOCATED 34 PFS (4:1) = 0x61 MIXED_EXT ALLOCATED 50_PCT_FULL DIFF (4:6) = CHANGED 35 ML (4:7) = NOT MIN_LOGGED 36 37 Slot 0 Offset 0x60 Length 71 38 39 Record Type = PRIMARY_RECORD Record Attributes = NULL_BITMAP 40 Memory Dump @0x0A37C060 41 42 00000000: 10004400 03000000 33202020 20202020 †..D.....3 43 00000010: 20202020 20202020 20202020 c3c0b9fa † .... 44 00000020: 20202020 20202020 20202020 20202020 † 45 00000030: 20202020 20202020 20202020 20202020 † 46 00000040: 20202020 0300f8†††††††††††††††††††††† ... 47 48 Slot 0 Column 0 Offset 0x4 Length 4 49 50 id = 3 51 52 Slot 0 Column 1 Offset 0x8 Length 20 53 54 itemno = 3 55 56 Slot 0 Column 2 Offset 0x1c Length 40 57 58 itemname = 美國 59 60 Slot 1 Offset 0xa7 Length 71 61 62 Record Type = PRIMARY_RECORD Record Attributes = NULL_BITMAP 63 Memory Dump @0x0A37C0A7 64 65 00000000: 10004400 04000000 34202020 20202020 †..D.....4 66 00000010: 20202020 20202020 20202020 d3a2b9fa † .... 67 00000020: 20202020 20202020 20202020 20202020 † 68 00000030: 20202020 20202020 20202020 20202020 † 69 00000040: 20202020 0300f8†††††††††††††††††††††† ... 70 71 Slot 1 Column 0 Offset 0x4 Length 4 72 73 id = 4 74 75 Slot 1 Column 1 Offset 0x8 Length 20 76 77 itemno = 4 78 79 Slot 1 Column 2 Offset 0x1c Length 40 80 81 itemname = 英國 82 83 84 DBCC 執行完畢。如果 DBCC 輸出了錯誤信息,請與系統管理員聯系。
這個頁面是屬於testPartionTable表
1 Slot 0 Offset 0x60 Length 71 2 3 4 Slot 0 Column 0 Offset 0x4 Length 4 5 6 id = 3 7 8 Slot 0 Column 1 Offset 0x8 Length 20 9 10 itemno = 3 11 12 Slot 0 Column 2 Offset 0x1c Length 40 13 14 itemname = 美國 15 16 Slot 1 Offset 0xa7 Length 71 17 18 19 Slot 1 Column 0 Offset 0x4 Length 4 20 21 id = 4 22 23 Slot 1 Column 1 Offset 0x8 Length 20 24 25 itemno = 4 26 27 Slot 1 Column 2 Offset 0x1c Length 40 28 29 itemname = 英國
FILEID為4的文件里面的數據頁面里存放了id為3和id為4的這兩條記錄
看FILEID為5的文件里面的數據頁面
1 DBCC TRACEON(3604,-1) 2 GO 3 DBCC PAGE(test,5,8,3) 4 GO
這個頁面是屬於testPartionTable表

1 DBCC 執行完畢。如果 DBCC 輸出了錯誤信息,請與系統管理員聯系。 2 3 PAGE: (5:8) 4 5 6 BUFFER: 7 8 9 BUF @0x03E7B0FC 10 11 bpage = 0x1A2A8000 bhash = 0x00000000 bpageno = (5:8) 12 bdbid = 11 breferences = 0 bUse1 = 28674 13 bstat = 0x3c0000b blog = 0x212121bb bnext = 0x00000000 14 15 PAGE HEADER: 16 17 18 Page @0x1A2A8000 19 20 m_pageId = (5:8) m_headerVersion = 1 m_type = 1 21 m_typeFlagBits = 0x4 m_level = 0 m_flagBits = 0x8000 22 m_objId (AllocUnitId.idObj) = 84 m_indexId (AllocUnitId.idInd) = 256 23 Metadata: AllocUnitId = 72057594043432960 24 Metadata: PartitionId = 72057594038452224 Metadata: IndexId = 0 25 Metadata: ObjectId = 2073058421 m_prevPage = (0:0) m_nextPage = (0:0) 26 pminlen = 68 m_slotCnt = 1 m_freeCnt = 8023 27 m_freeData = 167 m_reservedCnt = 0 m_lsn = (41:326:23) 28 m_xactReserved = 0 m_xdesId = (0:0) m_ghostRecCnt = 0 29 m_tornBits = 0 30 31 Allocation Status 32 33 GAM (5:2) = ALLOCATED SGAM (5:3) = ALLOCATED 34 PFS (5:1) = 0x61 MIXED_EXT ALLOCATED 50_PCT_FULL DIFF (5:6) = CHANGED 35 ML (5:7) = NOT MIN_LOGGED 36 37 Slot 0 Offset 0x60 Length 71 38 39 Record Type = PRIMARY_RECORD Record Attributes = NULL_BITMAP 40 Memory Dump @0x0A37C060 41 42 00000000: 10004400 05000000 35202020 20202020 †..D.....5 43 00000010: 20202020 20202020 20202020 b5c2b9fa † .... 44 00000020: 20202020 20202020 20202020 20202020 † 45 00000030: 20202020 20202020 20202020 20202020 † 46 00000040: 20202020 0300f8†††††††††††††††††††††† ... 47 48 Slot 0 Column 0 Offset 0x4 Length 4 49 50 id = 5 51 52 Slot 0 Column 1 Offset 0x8 Length 20 53 54 itemno = 5 55 56 Slot 0 Column 2 Offset 0x1c Length 40 57 58 itemname = 德國 59 60 61 DBCC 執行完畢。如果 DBCC 輸出了錯誤信息,請與系統管理員聯系。
1 Slot 0 Offset 0x60 Length 71 2 3 4 Slot 0 Column 0 Offset 0x4 Length 4 5 6 id = 5 7 8 Slot 0 Column 1 Offset 0x8 Length 20 9 10 itemno = 5 11 12 Slot 0 Column 2 Offset 0x1c Length 40 13 14 itemname = 德國
FILEID為5的文件里面的數據頁面里存放了id為5這條記錄
再看我們剛才建立的分區函數,和各個ndf里的數據頁面存儲的記錄條數
1 創建分區函數 2 我們創建了一個用於數據類型為int的分區函數,按照數值來划分 3 文件組 分區 取值范圍 4 [FG_TestUnique_Id_01] 1 (小於2, 2]--包括2 5 [FG_TestUnique_Id_02] 2 [3, 4] 6 [FG_TestUnique_Id_03] 3 (4,大於4) --不包括4 7 8 CREATE PARTITION FUNCTION 9 Fun_TestUnique_Id(INT) AS 10 RANGE LEFT 11 FOR VALUES(2,4)
當執行select * from testPartionTable的時候,就需要跨這三個ndf文件來讀取記錄
IO一定會有所影響,所以一般應用都是按照月份、性別等來進行分區,確保查詢數據的時候不要跨多個文件組
如果表沒有分區是怎樣的?
SQL腳本如下,建立testNonPartionTable表:

1 USE [Test] 2 GO 3 CREATE TABLE testNonPartionTable 4 ( 5 id INT NOT NULL, 6 itemno CHAR(20), 7 itemname CHAR(40) 8 ) 9 10 11 INSERT INTO [dbo].[testNonPartionTable] ( [id], [itemno], [itemname] ) 12 SELECT 1,'1','中國' UNION ALL 13 SELECT 2,'2','法國' UNION ALL 14 SELECT 3,'3','美國' UNION ALL 15 SELECT 4,'4','英國' UNION ALL 16 SELECT 5,'5','德國' 17 18 --TRUNCATE TABLE [dbo].[DBCCResult] 19 INSERT INTO DBCCResult EXEC ('DBCC IND(test,testNonPartionTable,-1) ') 20 21 SELECT * FROM [dbo].[DBCCResult] ORDER BY [PageType] DESC
1 DBCC TRACEON(3604,-1) 2 GO 3 DBCC PAGE(test,1,47,3) 4 GO

1 DBCC 執行完畢。如果 DBCC 輸出了錯誤信息,請與系統管理員聯系。 2 3 PAGE: (1:47) 4 5 6 BUFFER: 7 8 9 BUF @0x03E83C38 10 11 bpage = 0x1763C000 bhash = 0x00000000 bpageno = (1:47) 12 bdbid = 11 breferences = 0 bUse1 = 29165 13 bstat = 0x3c0000b blog = 0xca2159bb bnext = 0x00000000 14 15 PAGE HEADER: 16 17 18 Page @0x1763C000 19 20 m_pageId = (1:47) m_headerVersion = 1 m_type = 1 21 m_typeFlagBits = 0x4 m_level = 0 m_flagBits = 0x8000 22 m_objId (AllocUnitId.idObj) = 86 m_indexId (AllocUnitId.idInd) = 256 23 Metadata: AllocUnitId = 72057594043564032 24 Metadata: PartitionId = 72057594038583296 Metadata: IndexId = 0 25 Metadata: ObjectId = 2105058535 m_prevPage = (0:0) m_nextPage = (0:0) 26 pminlen = 68 m_slotCnt = 5 m_freeCnt = 7731 27 m_freeData = 451 m_reservedCnt = 0 m_lsn = (41:355:23) 28 m_xactReserved = 0 m_xdesId = (0:0) m_ghostRecCnt = 0 29 m_tornBits = 0 30 31 Allocation Status 32 33 GAM (1:2) = ALLOCATED SGAM (1:3) = NOT ALLOCATED 34 PFS (1:1) = 0x61 MIXED_EXT ALLOCATED 50_PCT_FULL DIFF (1:6) = CHANGED 35 ML (1:7) = NOT MIN_LOGGED 36 37 Slot 0 Offset 0x60 Length 71 38 39 Record Type = PRIMARY_RECORD Record Attributes = NULL_BITMAP 40 Memory Dump @0x0A37C060 41 42 00000000: 10004400 01000000 31202020 20202020 †..D.....1 43 00000010: 20202020 20202020 20202020 d6d0b9fa † .... 44 00000020: 20202020 20202020 20202020 20202020 † 45 00000030: 20202020 20202020 20202020 20202020 † 46 00000040: 20202020 0300f8†††††††††††††††††††††† ... 47 48 Slot 0 Column 0 Offset 0x4 Length 4 49 50 id = 1 51 52 Slot 0 Column 1 Offset 0x8 Length 20 53 54 itemno = 1 55 56 Slot 0 Column 2 Offset 0x1c Length 40 57 58 itemname = 中國 59 60 Slot 1 Offset 0xa7 Length 71 61 62 Record Type = PRIMARY_RECORD Record Attributes = NULL_BITMAP 63 Memory Dump @0x0A37C0A7 64 65 00000000: 10004400 02000000 32202020 20202020 †..D.....2 66 00000010: 20202020 20202020 20202020 b7a8b9fa † .... 67 00000020: 20202020 20202020 20202020 20202020 † 68 00000030: 20202020 20202020 20202020 20202020 † 69 00000040: 20202020 0300f8†††††††††††††††††††††† ... 70 71 Slot 1 Column 0 Offset 0x4 Length 4 72 73 id = 2 74 75 Slot 1 Column 1 Offset 0x8 Length 20 76 77 itemno = 2 78 79 Slot 1 Column 2 Offset 0x1c Length 40 80 81 itemname = 法國 82 83 Slot 2 Offset 0xee Length 71 84 85 Record Type = PRIMARY_RECORD Record Attributes = NULL_BITMAP 86 Memory Dump @0x0A37C0EE 87 88 00000000: 10004400 03000000 33202020 20202020 †..D.....3 89 00000010: 20202020 20202020 20202020 c3c0b9fa † .... 90 00000020: 20202020 20202020 20202020 20202020 † 91 00000030: 20202020 20202020 20202020 20202020 † 92 00000040: 20202020 0300f8†††††††††††††††††††††† ... 93 94 Slot 2 Column 0 Offset 0x4 Length 4 95 96 id = 3 97 98 Slot 2 Column 1 Offset 0x8 Length 20 99 100 itemno = 3 101 102 Slot 2 Column 2 Offset 0x1c Length 40 103 104 itemname = 美國 105 106 Slot 3 Offset 0x135 Length 71 107 108 Record Type = PRIMARY_RECORD Record Attributes = NULL_BITMAP 109 Memory Dump @0x0A37C135 110 111 00000000: 10004400 04000000 34202020 20202020 †..D.....4 112 00000010: 20202020 20202020 20202020 d3a2b9fa † .... 113 00000020: 20202020 20202020 20202020 20202020 † 114 00000030: 20202020 20202020 20202020 20202020 † 115 00000040: 20202020 0300f8†††††††††††††††††††††† ... 116 117 Slot 3 Column 0 Offset 0x4 Length 4 118 119 id = 4 120 121 Slot 3 Column 1 Offset 0x8 Length 20 122 123 itemno = 4 124 125 Slot 3 Column 2 Offset 0x1c Length 40 126 127 itemname = 英國 128 129 Slot 4 Offset 0x17c Length 71 130 131 Record Type = PRIMARY_RECORD Record Attributes = NULL_BITMAP 132 Memory Dump @0x0A37C17C 133 134 00000000: 10004400 05000000 35202020 20202020 †..D.....5 135 00000010: 20202020 20202020 20202020 b5c2b9fa † .... 136 00000020: 20202020 20202020 20202020 20202020 † 137 00000030: 20202020 20202020 20202020 20202020 † 138 00000040: 20202020 0300f8†††††††††††††††††††††† ... 139 140 Slot 4 Column 0 Offset 0x4 Length 4 141 142 id = 5 143 144 Slot 4 Column 1 Offset 0x8 Length 20 145 146 itemno = 5 147 148 Slot 4 Column 2 Offset 0x1c Length 40 149 150 itemname = 德國 151 152 153 DBCC 執行完畢。如果 DBCC 輸出了錯誤信息,請與系統管理員聯系。
1 itemname = 中國 2 3 Slot 1 Offset 0xa7 Length 71 4 5 6 Slot 1 Column 0 Offset 0x4 Length 4 7 8 id = 2 9 10 Slot 1 Column 1 Offset 0x8 Length 20 11 12 itemno = 2 13 14 Slot 1 Column 2 Offset 0x1c Length 40 15 16 itemname = 法國 17 18 Slot 2 Offset 0xee Length 71 19 20 21 Slot 2 Column 0 Offset 0x4 Length 4 22 23 id = 3 24 25 Slot 2 Column 1 Offset 0x8 Length 20 26 27 itemno = 3 28 29 Slot 2 Column 2 Offset 0x1c Length 40 30 31 itemname = 美國 32 33 Slot 3 Offset 0x135 Length 71 34 35 36 Slot 3 Column 0 Offset 0x4 Length 4 37 38 id = 4 39 40 Slot 3 Column 1 Offset 0x8 Length 20 41 42 itemno = 4 43 44 Slot 3 Column 2 Offset 0x1c Length 40 45 46 itemname = 英國 47 48 Slot 4 Offset 0x17c Length 71 49 50 51 52 Slot 4 Column 0 Offset 0x4 Length 4 53 54 id = 5 55 56 Slot 4 Column 1 Offset 0x8 Length 20 57 58 itemno = 5 59 60 Slot 4 Column 2 Offset 0x1c Length 40 61 62 itemname = 德國
五條記錄都在同一個數據頁面
參考文章:
http://www.cnblogs.com/zhijianliutang/archive/2012/10/28/2743722.html
如有不對的地方,歡迎大家拍磚o(∩_∩)o
----------------------------------------------------------------
2013-10-19 晚上補充
我們用Internal Viewer來查看TEST數據庫
在Internal Viewer查看到TEST數據庫是分區的,十分形象
也能夠看到那3個pageid為8的數據頁面
我們進入第4個文件的數據頁面,即是:E:\FG_TestUnique_Id_02_data.ndf里的數據頁面
可以看到每個數據文件都會有GAM、SGAM、DCM、BCM、PFS頁面
另外的兩個數據頁面我就不打開來看了
關於GAM、SGAM、DCM、BCM、PFS這些頁面的作用可以參考下面文章:
SQL Server 2008 連載之存儲結構之DCM、BCM
SQL Server 2008連載之存儲結構之GAM、SGAM
關於索引對齊/分區對齊
大家可以先看一下我之前寫的文章,看一下數據頁面之間是怎麽關聯的,先了解一下
SQLSERVER聚集索引與非聚集索引的再次研究(上)
SQLSERVER聚集索引與非聚集索引的再次研究(下)
MSDN中的解釋
索引分區
除了對表的數據集進行分區之外,還可以對索引進行分區。使用相同的函數對表及其索引進行分區通常可以優化性能。
當索引和表按照相同的順序使用相同的分區函數和列時,表和索引將對齊。如果在已經分區的表中建立索引,
SQL Server 會自動將新索引與該表的分區架構對齊,除非該索引的分區明顯不同。當表及其索引對齊后,
SQL Server 則可以更有效地將分區移入和移出分區表,因為所有相關的數據和索引都使用相同的算法進行划分。
如果定義表和索引時不僅使用了相同的分區函數,還使用了相同的分區架構,則這些表和索引將被認為是按存儲位置對齊。
按存儲位置對齊的一個優點是,相同邊界內的所有數據都位於相同的物理磁盤上。在這種情況下,
可以單獨在某個時間段內執行備份操作,還可以根據數據的變化在備份頻率和備份類型方面改變您的策略。
如果連接或收集了相同文件或文件組中的表和索引,則可以發現更多的好處。SQL Server 可以通過在多個分區中並行操作來獲益。
在按存儲位置對齊和多 CPU 的情況下,每個處理器都可以直接處理特定的文件或文件組,而不會與數據訪問產生任何沖突,
因為所有需要的數據都位於同一個磁盤上。這樣,可以並行運行多個進程,而不會相互干擾。
建立索引:是否分區?
默認情況下,分區表中創建的索引也使用相同的分區架構和分區列。
如果屬於這種情況,索引將與表對齊。盡管未作要求,但將表與其索引對齊可以使管理工作更容易進行,
對於滑動窗口方案尤其如此。
例如,要創建唯一的索引,分區列必須是一個關鍵列;這將確保對相應的分區進行驗證,以保證索引的唯一性。
因此,如果需要在一列上對表進行分區,而必須在另一個列上創建唯一的索引,這些表和索引將無法對齊。
在這種情況下,可以在唯一的列(如果是多列的唯一鍵,則可以是任一關鍵列)中對索引進行分區,或者根本就不進行分區。
請注意,在分區表中移入和移出數據時,必須刪除和創建此索引。
注意:如果您打算使用現有數據加載表並立即在其中添加索引,則通常可以通過以下方式獲得更好的性能:
先加載到未分區、未建立索引的表中,然后在加載數據后創建分區索引。
通過為分區架構定義群集索引,可以在加載數據后更有效地為表分區。
這也是為現有表分區的不錯方法。要創建與未分區表相同的表並創建與已分區群集索引相同的群集索引,
請用一個文件組目標位置替換創建表中的 ON 子句。然后,在加載數據之后為分區架構創建群集索引。
索引對齊,簡單來講,因為索引也可以創建在不同的文件組中,那里創建索引的時候也可以根據
分區架構和用來分區的列來創建索引,這樣索引數據和表數據都放在同一個文件組中,叫索引對齊
------------------------------------------------------------------------------
聚集索引表
聚集索引建立在分區列
我們drop掉testPartionTable表,重新建立testPartionTable表

1 --5.創建分區表 2 CREATE TABLE testPartionTable 3 ( 4 id INT NOT NULL, 5 itemname NVARCHAR(4000) 6 )ON Sch_TestUnique_Id([id]) 7 8 9 INSERT INTO [dbo].[testPartionTable] ( [id], [itemname] ) 10 SELECT 1,'中國'+REPLICATE('a',3500) UNION ALL 11 SELECT 2,'法國'+REPLICATE('a',3500) UNION ALL 12 SELECT 3,'美國'+REPLICATE('a',3500) UNION ALL 13 SELECT 4,'英國'+REPLICATE('a',3500) UNION ALL 14 SELECT 5,'德國'+REPLICATE('a',3500) 15 16 SELECT * FROM [dbo].[testPartionTable] 17 GO 18 19 --查看邊界值點 20 select * from sys.partition_range_values 21 GO
這個表有一個特點:就是一條記錄占用一個數據頁面
創建聚集索引,聚集索引字段創建在分區字段id上
1 --創建聚集索引 2 CREATE CLUSTERED INDEX cix_id ON testPartionTable(id ASC)
我們看一下,創建聚集索引之后,表的頁面的分配情況

1 --TRUNCATE TABLE [dbo].[DBCCResult] 2 INSERT INTO DBCCResult EXEC ('DBCC IND(test,testPartionTable,-1) ') 3 4 SELECT * FROM [dbo].[DBCCResult] ORDER BY [PageType] DESC
上圖中,紅色框的列都需要注意的
分區號1/fileid3 (PartitionNumber1)-》文件組FG_TestUnique_Id_01-》E:\FG_TestUnique_Id_01_data.ndf
分區號2/fileid4 (PartitionNumber2)-》文件組FG_TestUnique_Id_02-》E:\FG_TestUnique_Id_02_data.ndf
分區號3/fileid5 (PartitionNumber3)-》文件組FG_TestUnique_Id_03-》E:\FG_TestUnique_Id_03_data.ndf
從上圖可以得出:
fileid3/分區號1:聚集索引頁15,IAM頁13,數據頁12,數據頁14
fileid4/分區號2:聚集索引頁15,IAM頁13,數據頁12,數據頁14
fileid5/分區號3:IAM頁12,數據頁11
fileid PartitionID
fileid3:72057594038583296
fileid4:72057594038648832
fileid5:72057594038714368
PartitionID指的是:表的分區ID,如果一張表沒有使用表分區技術,每張表本來默認會有一個分區
如果使用了表分區技術,那么,每個分區都會有一個分區ID(PartitionID)
頁面12既是IAM頁面也是數據頁面
不同的是:一個頁面12在fileid5文件里作為IAM頁面,另一個頁面12在fileid4文件里作為數據頁面
可以看到fileid3文件和fileid4文件里的數據頁面是首尾相連的,都標記了與那個文件的哪個頁面進行相連
唯獨fileid5文件里面沒有聚集索引頁面,可能因為只有一個數據頁11,所以沒有聚集索引頁面
而且也看不到fileid5文件里數據頁有首尾相連標記
-------------------------------------------------------------------
----------------------------------------------------------------------
頁面指向
文件4里數據頁面12-》文件4里數據頁面14
文件3里數據頁面12-》文件3里數據頁面14
可以看到三個文件組之間或者三個ndf文件之間,數據頁面與數據頁面之間已經沒有聯系了,
只有大家都在同一個ndf文件里才能首尾相連,才有聯系
我們看一下聚集索引頁面
fileid為3的聚集索引頁面
1 DBCC TRACEON(3604,-1) 2 GO 3 DBCC PAGE(test,3,15,3) 4 GO
fileid為4的聚集索引頁面
1 DBCC TRACEON(3604,-1) 2 GO 3 DBCC PAGE(test,4,15,3) 4 GO
每個文件中的聚集索引頁面都各自為政,都只管他自己的文件里的數據頁面,而別的文件里的數據頁面他是不管的
我們看一下數據頁面,這里我只顯示有用的信息,數據頁面的其他沒用信息我都刪掉了
1 DBCC TRACEON(3604,-1) 2 GO 3 DBCC PAGE(test,3,12,3) 4 GO
1 PAGE: (3:12) 2 3 4 5 UNIQUIFIER = [NULL] 6 7 Slot 0 Column 1 Offset 0x4 Length 4 8 9 id = 1 10 11 Slot 0 Column 2 Offset 0x11 Length 7004 12 13 itemname = 中國aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 14 15 DBCC 執行完畢。如果 DBCC 輸出了錯誤信息,請與系統管理員聯系。
1 DBCC TRACEON(3604,-1) 2 GO 3 DBCC PAGE(test,3,14,3) 4 GO
1 PAGE: (3:14) 2 3 4 5 6 UNIQUIFIER = [NULL] 7 8 Slot 0 Column 1 Offset 0x4 Length 4 9 10 id = 2 11 12 Slot 0 Column 2 Offset 0x11 Length 7004 13 14 itemname = 法國aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 15 16 DBCC 執行完畢。如果 DBCC 輸出了錯誤信息,請與系統管理員聯系。
1 DBCC TRACEON(3604,-1) 2 GO 3 DBCC PAGE(test,4,12,3) 4 GO
1 PAGE: (4:12) 2 3 4 5 UNIQUIFIER = [NULL] 6 7 Slot 0 Column 1 Offset 0x4 Length 4 8 9 id = 3 10 11 Slot 0 Column 2 Offset 0x11 Length 7004 12 13 itemname = 美國aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 14 15 DBCC 執行完畢。如果 DBCC 輸出了錯誤信息,請與系統管理員聯系。
1 DBCC TRACEON(3604,-1) 2 GO 3 DBCC PAGE(test,4,14,3) 4 GO
1 PAGE: (4:14) 2 3 4 UNIQUIFIER = [NULL] 5 6 Slot 0 Column 1 Offset 0x4 Length 4 7 8 id = 4 9 10 Slot 0 Column 2 Offset 0x11 Length 7004 11 12 itemname = 英國aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 13 14 DBCC 執行完畢。如果 DBCC 輸出了錯誤信息,請與系統管理員聯系。
1 DBCC TRACEON(3604,-1) 2 GO 3 DBCC PAGE(test,5,11,3) 4 GO
1 PAGE: (5:11) 2 3 UNIQUIFIER = [NULL] 4 5 Slot 0 Column 1 Offset 0x4 Length 4 6 7 id = 5 8 9 Slot 0 Column 2 Offset 0x11 Length 7004 10 11 itemname = 德國aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 12 13 DBCC 執行完畢。如果 DBCC 輸出了錯誤信息,請與系統管理員聯系。
從上面的結果得出:
fileid3:數據頁12存放的 id值為1
fileid3:數據頁14存放的 id值為2
fileid4:數據頁12存放的 id值為3
fileid4:數據頁14存放的 id值為4
fileid5:數據頁11存放的 id值為5
fileid3/分區號1:id值為1和2
fileid4/分區號2:id值為3和4
fileid5/分區號3:id值為5
按照了分區函數來分
1 --我們創建了一個用於數據類型為int的分區函數,按照數值來划分 2 --文件組 分區 取值范圍 3 --[FG_TestUnique_Id_01] 1 (小於2, 2]--包括2 4 --[FG_TestUnique_Id_02] 2 [3, 4] 5 --[FG_TestUnique_Id_03] 3 (4,大於4) --不包括4 6 7 CREATE PARTITION FUNCTION 8 Fun_TestUnique_Id(INT) AS 9 RANGE LEFT 10 FOR VALUES(2,4)
而且聚集索引頁面保存的id值也是按照分區函數來分的
fileid3/分區號1:id值為1和2
fileid4/分區號2:id值為3和4
那么這時候可以說聚集索引和數據都按照分區函數來划分,是索引對齊的
-----------------------------------------------------------------------------------------------------
聚集索引建立在非分區列
我們drop掉testPartionTable表,重新建立testPartionTable表

1 CREATE TABLE testPartionTable 2 ( 3 id INT NOT NULL, 4 itemno CHAR(20), 5 itemname NVARCHAR(4000) 6 )ON Sch_TestUnique_Id([id]) 7 8 9 10 11 12 INSERT INTO [dbo].[testPartionTable] ( [id],[itemno], [itemname] ) 13 SELECT 1,'5','中國'+REPLICATE('a',3500) UNION ALL 14 SELECT 2,'6','法國'+REPLICATE('a',3500) UNION ALL 15 SELECT 3,'3','美國'+REPLICATE('a',3500) UNION ALL 16 SELECT 4,'1','英國'+REPLICATE('a',3500) UNION ALL 17 SELECT 5,'4','德國'+REPLICATE('a',3500) UNION ALL 18 SELECT 6,'2','日本'+REPLICATE('a',3500) 19 20 SELECT * FROM [dbo].[testPartionTable] 21 GO 22 23 --查看邊界值點 24 select * from sys.partition_range_values 25 GO
創建聚集索引之前testPartionTable表頁面分配情況
這次我們將聚集索引創建在非分區字段itemno上
1 --創建聚集索引 2 CREATE CLUSTERED INDEX cix_id ON testPartionTable([itemno] ASC) 3 GO

1 --TRUNCATE TABLE [dbo].[DBCCResult] 2 INSERT INTO DBCCResult EXEC ('DBCC IND(test,testPartionTable,-1) ') 3 4 SELECT * FROM [dbo].[DBCCResult] ORDER BY [PageType] DESC
建立聚集索引之后,頁面會重新分配
這個在SQLSERVER聚集索引與非聚集索引的再次研究(下)里已經講過了
從上圖可以得出:
fileid3/分區號1:聚集索引頁23,IAM頁21,數據頁20,數據頁22
fileid4/分區號2:聚集索引頁23,IAM頁21,數據頁20,數據頁22
fileid5/分區號3:聚集索引頁23,IAM頁21,數據頁20,數據頁22
這里跟剛才不一樣的是:多了聚集索引頁23
fileid5/分區號3:聚集索引頁23,IAM頁21,數據頁20,數據頁22
fileid5/分區號3(剛才):IAM頁12,數據頁11
而且可以看到fileid5文件里數據頁有首尾相連標記
剛才:
現在:
這里可以反映出:一個文件/文件組里的數據頁多於一個才會出現聚集索引頁面
我們看一下 聚集索引頁面
1 DBCC TRACEON(3604,-1) 2 GO 3 DBCC PAGE(test,3,23,3) 4 GO
1 DBCC TRACEON(3604,-1) 2 GO 3 DBCC PAGE(test,4,23,3) 4 GO
1 DBCC TRACEON(3604,-1) 2 GO 3 DBCC PAGE(test,5,23,3) 4 GO
聚集索引頁面告訴我們:雖然我們在itemno字段上建立聚集索引,但是SQLSERVER在聚集索引頁面里
還是以id為聚集索引鍵來建立聚集索引,直白一點來說就是SQLSERVER會在id列上建立聚集索引,按照id字段來進行排序
無論你在非分區列的那個列上建立聚集索引,SQLSERVER都只會在分區列上建立聚集索引(可能有點繞口o(∩_∩)o )
1 INSERT INTO [dbo].[testPartionTable] ( [id],[itemno], [itemname] ) 2 SELECT 1,'5','中國'+REPLICATE('a',3500) UNION ALL 3 SELECT 2,'6','法國'+REPLICATE('a',3500) UNION ALL 4 SELECT 3,'3','美國'+REPLICATE('a',3500) UNION ALL 5 SELECT 4,'1','英國'+REPLICATE('a',3500) UNION ALL 6 SELECT 5,'4','德國'+REPLICATE('a',3500) UNION ALL 7 SELECT 6,'2','日本'+REPLICATE('a',3500) 8 9 --創建聚集索引 10 CREATE CLUSTERED INDEX cix_id ON testPartionTable([itemno] ASC) 11 GO
我們看一下數據頁面
1 PAGE: (3:20) 2 3 UNIQUIFIER = [NULL] 4 5 Slot 0 Column 1 Offset 0x4 Length 20 6 7 itemno = 5 8 9 Slot 0 Column 2 Offset 0x18 Length 4 10 11 id = 1 12 13 Slot 0 Column 3 Offset 0x25 Length 7004 14 15 itemname = 中國aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
1 PAGE: (3:22) 2 3 UNIQUIFIER = [NULL] 4 5 Slot 0 Column 1 Offset 0x4 Length 20 6 7 itemno = 6 8 9 Slot 0 Column 2 Offset 0x18 Length 4 10 11 id = 2 12 13 Slot 0 Column 3 Offset 0x25 Length 7004 14 15 itemname = 法國aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
1 PAGE: (4:20) 2 3 UNIQUIFIER = [NULL] 4 5 Slot 0 Column 1 Offset 0x4 Length 20 6 7 itemno = 1 8 9 Slot 0 Column 2 Offset 0x18 Length 4 10 11 id = 4 12 13 Slot 0 Column 3 Offset 0x25 Length 7004 14 15 itemname = 英國aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
1 PAGE: (4:22) 2 3 UNIQUIFIER = [NULL] 4 5 Slot 0 Column 1 Offset 0x4 Length 20 6 7 itemno = 3 8 9 Slot 0 Column 2 Offset 0x18 Length 4 10 11 id = 3 12 13 Slot 0 Column 3 Offset 0x25 Length 7004 14 15 itemname = 美國aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
1 PAGE: (5:20) 2 3 UNIQUIFIER = [NULL] 4 5 Slot 0 Column 1 Offset 0x4 Length 20 6 7 itemno = 2 8 9 Slot 0 Column 2 Offset 0x18 Length 4 10 11 id = 6 12 13 Slot 0 Column 3 Offset 0x25 Length 7004 14 15 itemname = 日本aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
1 PAGE: (5:22) 2 3 UNIQUIFIER = [NULL] 4 5 Slot 0 Column 1 Offset 0x4 Length 20 6 7 itemno = 4 8 9 Slot 0 Column 2 Offset 0x18 Length 4 10 11 id = 5 12 13 Slot 0 Column 3 Offset 0x25 Length 7004 14 15 itemname = 德國aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
注意:我這里為了節省篇幅,將數據頁面的內容進行了刪減
fileid3/分區號1:id值為1和2
fileid4/分區號2:id值為3和4
fileid5/分區號3:id值為5和6
那么就是說,對於聚集索引表來說,無論聚集索引建立在分區列還是非分區列,都會索引對齊
非聚集索引表
非聚集索引建立在分區列
我們drop掉數據庫test,重新建立數據庫test

1 USE master 2 GO 3 DROP DATABASE [Test] 4 GO
SQL腳本都跟剛才一樣的

1 USE master 2 GO 3 4 --創建數據庫 5 CREATE DATABASE [Test] 6 GO 7 8 USE [Test] 9 GO 10 11 12 --1.創建文件組 13 ALTER DATABASE [Test] 14 ADD FILEGROUP [FG_TestUnique_Id_01] 15 16 ALTER DATABASE [Test] 17 ADD FILEGROUP [FG_TestUnique_Id_02] 18 19 ALTER DATABASE [Test] 20 ADD FILEGROUP [FG_TestUnique_Id_03] 21 22 --2.創建文件 23 ALTER DATABASE [Test] 24 ADD FILE 25 (NAME = N'FG_TestUnique_Id_01_data',FILENAME = N'E:\FG_TestUnique_Id_01_data.ndf',SIZE = 1MB, FILEGROWTH = 1MB ) 26 TO FILEGROUP [FG_TestUnique_Id_01]; 27 28 ALTER DATABASE [Test] 29 ADD FILE 30 (NAME = N'FG_TestUnique_Id_02_data',FILENAME = N'E:\FG_TestUnique_Id_02_data.ndf',SIZE = 1MB, FILEGROWTH = 1MB ) 31 TO FILEGROUP [FG_TestUnique_Id_02]; 32 33 ALTER DATABASE [Test] 34 ADD FILE 35 (NAME = N'FG_TestUnique_Id_03_data',FILENAME = N'E:\FG_TestUnique_Id_03_data.ndf',SIZE = 1MB, FILEGROWTH = 1MB ) 36 TO FILEGROUP [FG_TestUnique_Id_03]; 37 38 39 --3.創建分區函數 40 --我們創建了一個用於數據類型為int的分區函數,按照數值來划分 41 --文件組 分區 取值范圍 42 --[FG_TestUnique_Id_01] 1 (小於2, 2]--包括2 43 --[FG_TestUnique_Id_02] 2 [3, 4] 44 --[FG_TestUnique_Id_03] 3 (4,大於4) --不包括4 45 46 CREATE PARTITION FUNCTION 47 Fun_TestUnique_Id(INT) AS 48 RANGE LEFT 49 FOR VALUES(2,4) 50 51 52 53 54 --4.創建分區方案 55 CREATE PARTITION SCHEME 56 Sch_TestUnique_Id AS 57 PARTITION Fun_TestUnique_Id 58 TO([FG_TestUnique_Id_01],[FG_TestUnique_Id_02],[FG_TestUnique_Id_03]) 59 60 --5.創建分區表 61 --DROP TABLE testPartionTable 62 CREATE TABLE testPartionTable 63 ( 64 id INT NOT NULL, 65 itemno CHAR(20), 66 itemname NVARCHAR(4000) 67 )ON Sch_TestUnique_Id([id]) 68 69 70 71 72 73 INSERT INTO [dbo].[testPartionTable] ( [id],[itemno], [itemname] ) 74 SELECT 1,'5','中國'+REPLICATE('a',3500) UNION ALL 75 SELECT 2,'6','法國'+REPLICATE('a',3500) UNION ALL 76 SELECT 3,'3','美國'+REPLICATE('a',3500) UNION ALL 77 SELECT 4,'1','英國'+REPLICATE('a',3500) UNION ALL 78 SELECT 5,'4','德國'+REPLICATE('a',3500) UNION ALL 79 SELECT 6,'2','日本'+REPLICATE('a',3500) 80 81 SELECT * FROM [dbo].[testPartionTable] 82 GO 83 84 --查看邊界值點 85 select * from sys.partition_range_values 86 GO

1 CREATE TABLE DBCCResult ( 2 PageFID NVARCHAR(200), 3 PagePID NVARCHAR(200), 4 IAMFID NVARCHAR(200), 5 IAMPID NVARCHAR(200), 6 ObjectID NVARCHAR(200), 7 IndexID NVARCHAR(200), 8 PartitionNumber NVARCHAR(200), 9 PartitionID NVARCHAR(200), 10 iam_chain_type NVARCHAR(200), 11 PageType NVARCHAR(200), 12 IndexLevel NVARCHAR(200), 13 NextPageFID NVARCHAR(200), 14 NextPagePID NVARCHAR(200), 15 PrevPageFID NVARCHAR(200), 16 PrevPagePID NVARCHAR(200) 17 ) 18 19 --TRUNCATE TABLE [dbo].[DBCCResult] 20 INSERT INTO DBCCResult EXEC ('DBCC IND(test,testPartionTable,-1) ') 21 22 SELECT * FROM [dbo].[DBCCResult] ORDER BY [PageType] DESC
在id字段上建立非聚集索引
1 --創建非聚集索引 2 CREATE INDEX cix_id ON testPartionTable([id] ASC) 3 GO

1 --TRUNCATE TABLE [dbo].[DBCCResult] 2 INSERT INTO DBCCResult EXEC ('DBCC IND(test,testPartionTable,-1) ') 3 4 SELECT * FROM [dbo].[DBCCResult] ORDER BY [PageType] DESC
我們比較一下創建非聚集索引之前和之后的圖片
-----------------------------------------------------------------------------------------------------------------------
放大左下角的圖片
可以看到只是在每個文件fileid3、fileid4、fileid5里新建了非聚集索引頁面12和IAM頁面13,其他什么都沒有改變
fileid3/分區號1:非聚集索引頁12,IAM頁13,IAM頁9,數據頁8,數據頁10
fileid4/分區號2:非聚集索引頁12,IAM頁13,IAM頁9,數據頁8,數據頁10
fileid5/分區號3:非聚集索引頁12,IAM頁13,IAM頁9,數據頁8,數據頁10
----------------------------------------------------------------------------
我們看一下非聚集索引頁面

1 DBCC TRACEON(3604,-1) 2 GO 3 DBCC PAGE(test,3,12,3) 4 GO

1 DBCC TRACEON(3604,-1) 2 GO 3 DBCC PAGE(test,4,12,3) 4 GO

1 DBCC TRACEON(3604,-1) 2 GO 3 DBCC PAGE(test,5,12,3) 4 GO
每個文件中的非聚集索引頁面都各自為政,都只管他自己的文件里的數據頁面,而別的文件里的數據頁面他是不管的
這里HEAP RID(key)只會指向本文件里的數據頁面,不會指向其他文件的數據頁面,因為如果指向其他文件的數據頁面的話
那么就不用每個文件都有一個非聚集索引頁面12了
我們看一下數據頁面,這里我只顯示有用的信息,數據頁面的其他沒用信息我都刪掉了

1 DBCC TRACEON(3604,-1) 2 GO 3 DBCC PAGE(test,3,8,3) 4 GO
1 PAGE: (3:8) 2 3 Slot 0 Column 0 Offset 0x4 Length 4 4 5 id = 1 6 7 Slot 0 Column 1 Offset 0x8 Length 20 8 9 itemno = 5 10 11 Slot 0 Column 2 Offset 0x23 Length 7004 12 13 itemname = 中國aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

1 DBCC TRACEON(3604,-1) 2 GO 3 DBCC PAGE(test,3,10,3) 4 GO
1 PAGE: (3:10) 2 3 Slot 0 Column 0 Offset 0x4 Length 4 4 5 id = 2 6 7 Slot 0 Column 1 Offset 0x8 Length 20 8 9 itemno = 6 10 11 Slot 0 Column 2 Offset 0x23 Length 7004 12 13 itemname = 法國aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

1 DBCC TRACEON(3604,-1) 2 GO 3 DBCC PAGE(test,4,8,3) 4 GO
1 PAGE: (4:8) 2 3 Slot 0 Column 0 Offset 0x4 Length 4 4 5 id = 3 6 7 Slot 0 Column 1 Offset 0x8 Length 20 8 9 itemno = 3 10 11 Slot 0 Column 2 Offset 0x23 Length 7004 12 13 itemname = 美國aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

1 DBCC TRACEON(3604,-1) 2 GO 3 DBCC PAGE(test,4,10,3) 4 GO
1 PAGE: (4:10) 2 3 Slot 0 Column 0 Offset 0x4 Length 4 4 5 id = 4 6 7 Slot 0 Column 1 Offset 0x8 Length 20 8 9 itemno = 1 10 11 Slot 0 Column 2 Offset 0x23 Length 7004 12 13 itemname = 英國aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

1 DBCC TRACEON(3604,-1) 2 GO 3 DBCC PAGE(test,5,8,3) 4 GO
1 PAGE: (5:8) 2 3 Slot 0 Column 0 Offset 0x4 Length 4 4 5 id = 5 6 7 Slot 0 Column 1 Offset 0x8 Length 20 8 9 itemno = 4 10 11 Slot 0 Column 2 Offset 0x23 Length 7004 12 13 itemname = 德國aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

1 DBCC TRACEON(3604,-1) 2 GO 3 DBCC PAGE(test,5,10,3) 4 GO
1 PAGE: (5:10) 2 3 Slot 0 Column 0 Offset 0x4 Length 4 4 5 id = 6 6 7 Slot 0 Column 1 Offset 0x8 Length 20 8 9 itemno = 2 10 11 Slot 0 Column 2 Offset 0x23 Length 7004 12 13 itemname = 日本aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
fileid3/分區號1:id值為1和2
fileid4/分區號2:id值為3和4
fileid5/分區號3:id值為5和6
非聚集索引和數據都按照分區函數來划分,是索引對齊的
非聚集索引建立在非分區列
我們drop掉testPartionTable表,重新建立testPartionTable表

1 CREATE TABLE testPartionTable 2 ( 3 id INT NOT NULL, 4 itemno CHAR(20), 5 itemname NVARCHAR(4000) 6 )ON Sch_TestUnique_Id([id]) 7 8 9 10 11 12 INSERT INTO [dbo].[testPartionTable] ( [id],[itemno], [itemname] ) 13 SELECT 1,'5','中國'+REPLICATE('a',3500) UNION ALL 14 SELECT 2,'6','法國'+REPLICATE('a',3500) UNION ALL 15 SELECT 3,'3','美國'+REPLICATE('a',3500) UNION ALL 16 SELECT 4,'1','英國'+REPLICATE('a',3500) UNION ALL 17 SELECT 5,'4','德國'+REPLICATE('a',3500) UNION ALL 18 SELECT 6,'2','日本'+REPLICATE('a',3500) 19 20 SELECT * FROM [dbo].[testPartionTable] 21 GO 22 23 --查看邊界值點 24 select * from sys.partition_range_values 25 GO
創建非聚集索引之前testPartionTable表頁面分配情況
這次我們將非聚集索引創建在非分區字段itemno上
1 --創建非聚集索引 2 CREATE INDEX ix_id ON testPartionTable([itemno] ASC) 3 GO

1 --TRUNCATE TABLE [dbo].[DBCCResult] 2 INSERT INTO DBCCResult EXEC ('DBCC IND(test,testPartionTable,-1) ') 3 4 SELECT * FROM [dbo].[DBCCResult] ORDER BY [PageType] DESC
這里跟聚集索引不同,原來的數據頁面不會重新分配
從上圖可以得出:
fileid3/分區號1:非聚集索引頁12,IAM頁13,IAM頁9,數據頁8,數據頁10
fileid4/分區號2:非聚集索引頁12,IAM頁13,IAM頁9,數據頁8,數據頁10
fileid5/分區號3:非聚集索引頁12,IAM頁13,IAM頁9,數據頁8,數據頁10
我們看一下非聚集索引頁面

1 DBCC TRACEON(3604,-1) 2 GO 3 DBCC PAGE(test,3,12,3) 4 GO

1 DBCC TRACEON(3604,-1) 2 GO 3 DBCC PAGE(test,4,12,3) 4 GO

1 DBCC TRACEON(3604,-1) 2 GO 3 DBCC PAGE(test,5,12,3) 4 GO
非聚集索引頁面告訴我們:非聚集索引里面會包含分區依據列,但是索引鍵還是不變還是itemno
我們看一下數據頁面
1 PAGE: (3:8) 2 3 Slot 0 Column 0 Offset 0x4 Length 4 4 5 id = 1 6 7 Slot 0 Column 1 Offset 0x8 Length 20 8 9 itemno = 5 10 11 Slot 0 Column 2 Offset 0x23 Length 7004 12 13 itemname = 中國aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
1 PAGE: (3:10) 2 3 Slot 0 Column 0 Offset 0x4 Length 4 4 5 id = 2 6 7 Slot 0 Column 1 Offset 0x8 Length 20 8 9 itemno = 6 10 11 Slot 0 Column 2 Offset 0x23 Length 7004 12 13 itemname = 法國aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
1 PAGE: (4:8) 2 3 Slot 0 Column 0 Offset 0x4 Length 4 4 5 id = 3 6 7 Slot 0 Column 1 Offset 0x8 Length 20 8 9 itemno = 3 10 11 Slot 0 Column 2 Offset 0x23 Length 7004 12 13 itemname = 美國aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
1 PAGE: (4:10) 2 3 Slot 0 Column 0 Offset 0x4 Length 4 4 5 id = 4 6 7 Slot 0 Column 1 Offset 0x8 Length 20 8 9 itemno = 1 10 11 Slot 0 Column 2 Offset 0x23 Length 7004 12 13 itemname = 英國aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
1 PAGE: (5:8) 2 3 Slot 0 Column 0 Offset 0x4 Length 4 4 5 id = 5 6 7 Slot 0 Column 1 Offset 0x8 Length 20 8 9 itemno = 4 10 11 Slot 0 Column 2 Offset 0x23 Length 7004 12 13 itemname = 德國aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
1 PAGE: (5:10) 2 3 Slot 0 Column 0 Offset 0x4 Length 4 4 5 id = 6 6 7 Slot 0 Column 1 Offset 0x8 Length 20 8 9 itemno = 2 10 11 Slot 0 Column 2 Offset 0x23 Length 7004 12 13 itemname = 日本aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
fileid3/分區號1:id值為1和2
fileid4/分區號2:id值為3和4
fileid5/分區號3:id值為5和6
對於非聚集索引表來說,無論非聚集索引建立在分區列還是非分區列,都會索引對齊
補兩張圖
表分區下的聚集索引
可以看到每個分區都有兩個數據頁和一個聚集索引頁,而主文件組/fileid1里是沒有任何表數據的
表分區下的非聚集索引
可以看到每個分區都有兩個數據頁和一個非聚集索引頁,而主文件組/fileid1里是沒有任何表數據的
這里不知道是不是Intelnals Viewer的BUG,就算是非聚集索引都會顯示為聚集索引
1 USE [GPOSDB] 2 GO 3 CREATE TABLE NONCLUSTEREDtalbe(id int,NAME CHAR(20)) 4 INSERT INTO NONCLUSTEREDtalbe 5 SELECT 1,'nin' UNION ALL 6 SELECT 2,'nin' UNION ALL 7 SELECT 3,'nin' UNION ALL 8 SELECT 4,'nin' 9 10 CREATE NONCLUSTERED INDEX ix_NONCLUSTEREDtalbe ON NONCLUSTEREDtalbe(id ASC)
總結
缺點:這里不但數據分布在多個文件里,連聚集索引頁面和非聚集索引頁面都分布在多個文件里
如果是聚集索引/非聚集索引查找也需要到多個文件里去查找
因為在表分區了之后多個文件組之間/多個ndf文件之間,數據頁面與數據頁面之間已經沒有聯系了
必須到每個ndf文件里的聚集索引頁面/非聚集索引頁面去查找,直到找到所需的數據為止
所以,在使用表分區的時候一定要做好分區字段的選擇,避免select * from 表 不加where 分區字段=
造成的掃描所有分區
無論是索引頁還是數據頁,將一個頁面在每個分區里都保存一份這就是分區,表分區沒有什么神秘的o(∩_∩)o
看一下插入和查詢的執行計划