更新INCLUDE indexes中的非键列会引起索引碎片吗?
今天跟CareySon 讨论有些索引碎片的一个事情,他发现下面一篇文章中的有些问题,所以我做了个简单测试,如有不妥,欢迎大家批评指点。
http://www.daveturpin.com/2010/04/composite-index-vs-include-covering-index/
也就是更新INCLUDE indexes中的非键列会引起索引碎片吗?
测试代码如下:
CREATE TABLE sp_tablepages
(PageFID tinyint,
PagePID int,
IAMFID tinyint,
IAMPID int,
ObjectID int,
IndexID tinyint,
PartitionNumber tinyint,
PartitionID bigint,
iam_chain_type varchar(30),
PageType tinyint,
IndexLevel tinyint,
NextPageFID tinyint,
NextPagePID int,
PrevPageFID tinyint,
PrevPagePID int,
Primary Key (PageFID, PagePID));
go
CREATE TABLE bigrows
(
a int ,
b varchar(6400)
);
GO
/****** Object: Index [NonClusteredIndex] Script Date: 2012/5/18 15:05:12 ******/
CREATE NONCLUSTERED INDEX [NonClusteredIndex] ON [dbo].[bigrows]
(
[a] ASC
)
INCLUDE ( [b]) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
GO
/* Insert five rows into the table */
INSERT INTO bigrows
VALUES (5, REPLICATE('a', 1550));
INSERT INTO bigrows
VALUES (10, replicate('b', 1550));
INSERT INTO bigrows
VALUES (15, replicate('c', 1550));
INSERT INTO bigrows
VALUES (20, replicate('d', 1550));
INSERT INTO bigrows
VALUES (25, replicate('e', 1550));
--INSERT INTO bigrows
--VALUES (26, replicate('f', 1600));
GO
TRUNCATE TABLE sp_tablepages;
INSERT INTO sp_tablepages
EXEC ('DBCC IND ( DDDD, 1333579789, 2 )' );
GO
--上面的DDDD, 1333579789 分别为数据库的NAME跟INDEX的ID
TRUNCATE TABLE sp_tablepages;
INSERT INTO sp_tablepages
EXEC ('DBCC IND ( DDDD, 1349579846, 2 )' );
GO
SELECT *
FROM sp_tablepages where pagetype =2 and indexlevel=0
结果如下:
pagepid pagetype indexlevel
420 2 0
看一下那个页面里包含什么东西:
执行
DBCC TRACEON(3604);
GO
DBCC PAGE(DDDD, 1, 420, 1);
GO
DBCC execution completed. If DBCC printed error messages, contact your system administrator.
PAGE: (1:420)
BUFFER:
BUF @0x04686868
bpage = 0x10D5C000 bhash = 0x00000000 bpageno = (1:420)
bdbid = 10 breferences = 0 bcputicks = 0
bsampleCount = 0 bUse1 = 21914 bstat = 0x10b
blog = 0xcc7acccc bnext = 0x00000000
PAGE HEADER:
Page @0x10D5C000
m_pageId = (1:420) m_headerVersion = 1 m_type = 2
m_typeFlagBits = 0x0 m_level = 0 m_flagBits = 0x8000
m_objId (AllocUnitId.idObj) = 122 m_indexId (AllocUnitId.idInd) = 256
Metadata: AllocUnitId = 72057594045923328
Metadata: PartitionId = 72057594041532416 Metadata: IndexId = 2
Metadata: ObjectId = 1349579846 m_prevPage = (0:0) m_nextPage = (0:0)
pminlen = 13 m_slotCnt = 5 m_freeCnt = 236
m_freeData = 7946 m_reservedCnt = 0 m_lsn = (42:221:4)
m_xactReserved = 0 m_xdesId = (0:0) m_ghostRecCnt = 0
m_tornBits = 0 DB Frag ID = 1
Allocation Status
GAM (1:2) = ALLOCATED SGAM (1:3) = ALLOCATED
PFS (1:1) = 0x60 MIXED_EXT ALLOCATED 0_PCT_FULL DIFF (1:6) = CHANGED
ML (1:7) = NOT MIN_LOGGED
DATA:
Slot 0, Offset 0x60, Length 1570, DumpStyle BYTE
Record Type = INDEX_RECORD Record Attributes = NULL_BITMAP VARIABLE_COLUMNS
Record Size = 1570
Memory Dump @0x0F8FA060
00000000: 36050000 00a20100 00010000 00030000 01002206 6.................".
00000014: 61616161 61616161 61616161 61616161 61616161 aaaaaaaaaaaaaaaaaaaa
00000028: 61616161 61616161 61616161 61616161 61616161 aaaaaaaaaaaaaaaaaaaa
0000003C: 61616161 61616161 61616161 61616161 61616161 aaaaaaaaaaaaaaaaaaaa
---------------------- 此处省略
000005F0: 61616161 61616161 61616161 61616161 61616161 aaaaaaaaaaaaaaaaaaaa
00000604: 61616161 61616161 61616161 61616161 61616161 aaaaaaaaaaaaaaaaaaaa
00000618: 61616161 61616161 6161 aaaaaaaaaa
Slot 1, Offset 0x682, Length 1570, DumpStyle BYTE
Record Type = INDEX_RECORD Record Attributes = NULL_BITMAP VARIABLE_COLUMNS
Record Size = 1570
Memory Dump @0x0F8FA682
00000000: 360a0000 00a20100 00010001 00030000 01002206 6.................".
00000014: 62626262 62626262 62626262 62626262 62626262 bbbbbbbbbbbbbbbbbbbb
00000028: 62626262 62626262 62626262 62626262 62626262 bbbbbbbbbbbbbbbbbbbb
00000550: 62626262 62626262 62626262 62626262 62626262 bbbbbbbbbbbbbbbbbbbb
----------------------此处省略
000005F0: 62626262 62626262 62626262 62626262 62626262 bbbbbbbbbbbbbbbbbbbb
00000604: 62626262 62626262 62626262 62626262 62626262 bbbbbbbbbbbbbbbbbbbb
00000618: 62626262 62626262 6262 bbbbbbbbbb
Slot 2, Offset 0xca4, Length 1570, DumpStyle BYTE
Record Type = INDEX_RECORD Record Attributes = NULL_BITMAP VARIABLE_COLUMNS
Record Size = 1570
Memory Dump @0x0F8FACA4
00000000: 360f0000 00a20100 00010002 00030000 01002206 6.................".
00000014: 63636363 63636363 63636363 63636363 63636363 cccccccccccccccccccc
00000028: 63636363 63636363 63636363 63636363 63636363 cccccccccccccccccccc
---------------------- 此处省略
000005F0: 63636363 63636363 63636363 63636363 63636363 cccccccccccccccccccc
00000604: 63636363 63636363 63636363 63636363 63636363 cccccccccccccccccccc
00000618: 63636363 63636363 6363 cccccccccc
Slot 3, Offset 0x12c6, Length 1570, DumpStyle BYTE
Record Type = INDEX_RECORD Record Attributes = NULL_BITMAP VARIABLE_COLUMNS
Record Size = 1570
Memory Dump @0x0F8FB2C6
00000000: 36140000 00a20100 00010003 00030000 01002206 6.................".
00000014: 64646464 64646464 64646464 64646464 64646464 dddddddddddddddddddd
00000028: 64646464 64646464 64646464 64646464 64646464 dddddddddddddddddddd
---------------------- 此处省略
000005F0: 64646464 64646464 64646464 64646464 64646464 dddddddddddddddddddd
00000604: 64646464 64646464 64646464 64646464 64646464 dddddddddddddddddddd
00000618: 64646464 64646464 6464 dddddddddd
Slot 4, Offset 0x18e8, Length 1570, DumpStyle BYTE
Record Type = INDEX_RECORD Record Attributes = NULL_BITMAP VARIABLE_COLUMNS
Record Size = 1570
Memory Dump @0x0F8FB8E8
00000000: 36190000 00a20100 00010004 00030000 01002206 6.................".
00000014: 65656565 65656565 65656565 65656565 65656565 eeeeeeeeeeeeeeeeeeee
---------------------- 此处略微
000005F0: 65656565 65656565 65656565 65656565 65656565 eeeeeeeeeeeeeeeeeeee
00000604: 65656565 65656565 65656565 65656565 65656565 eeeeeeeeeeeeeeeeeeee
00000618: 65656565 65656565 6565 eeeeeeeeee
OFFSET TABLE:
Row - Offset
4 (0x4) - 6376 (0x18e8)
3 (0x3) - 4806 (0x12c6)
2 (0x2) - 3236 (0xca4)
1 (0x1) - 1666 (0x682)
0 (0x0) - 96 (0x60)
好了,很明显,所以的数据在同一个索引页面里。
再看一下碎片的情况。
SET NOCOUNT ON
--Use the pubs database
USE DDDD
DBCC SHOWCONTIG (bigrows,NonClusteredIndex)-- WITH ALL_INDEXES
GO
DBCC SHOWCONTIG scanning 'bigrows' table...
Table: 'bigrows' (1349579846); index ID: 2, database ID: 10
LEAF level scan performed.
- Pages Scanned................................: 1
- Extents Scanned..............................: 1
- Extent Switches..............................: 0
- Avg. Pages per Extent........................: 1.0
- Scan Density [Best Count:Actual Count].......: 100.00% [1:1]
- Logical Scan Fragmentation ..................: 0.00%
- Extent Scan Fragmentation ...................: 0.00%
- Avg. Bytes Free per Page.....................: 236.0
- Avg. Page Density (full).....................: 97.08%
DBCC execution completed. If DBCC printed error messages, contact your system administrator.
Avg. Bytes Free per Page : 236.0, Avg. Page Density (full) : 97.08%,Logical Scan Fragmentation ..................: 0.00%
从这个参数来看应该不错,碎片不严重。
Avg. Page Density (full) : 97.08%
Logical Scan Fragmentation ..................: 0.00%
然后我们更新INCLUDE indexes中的非键列,看看是不是会引起索引碎片。
UPDATE bigrows SET b= replicate('b', 2000) WHERE A=10
再次运行
DBCC PAGE(DDDD, 1, 420, 1);
PAGE: (1:420)
BUFFER:
BUF @0x04686868
bpage = 0x10D5C000 bhash = 0x00000000 bpageno = (1:420)
bdbid = 10 breferences = 0 bcputicks = 0
bsampleCount = 0 bUse1 = 22474 bstat = 0x9
blog = 0x7acccc7a bnext = 0x00000000
PAGE HEADER:
Page @0x10D5C000
m_pageId = (1:420) m_headerVersion = 1 m_type = 2
m_typeFlagBits = 0x0 m_level = 0 m_flagBits = 0x200
m_objId (AllocUnitId.idObj) = 122 m_indexId (AllocUnitId.idInd) = 256
Metadata: AllocUnitId = 72057594045923328
Metadata: PartitionId = 72057594041532416 Metadata: IndexId = 2
Metadata: ObjectId = 1349579846 m_prevPage = (0:0) m_nextPage = (1:412)
pminlen = 13 m_slotCnt = 2 m_freeCnt = 4502
m_freeData = 5256 m_reservedCnt = 0 m_lsn = (42:255:43)
m_xactReserved = 0 m_xdesId = (0:0) m_ghostRecCnt = 0
m_tornBits = -1654904262 DB Frag ID = 1
Allocation Status
GAM (1:2) = ALLOCATED SGAM (1:3) = NOT ALLOCATED
PFS (1:1) = 0x60 MIXED_EXT ALLOCATED 0_PCT_FULL DIFF (1:6) = CHANGED
ML (1:7) = NOT MIN_LOGGED
DATA:
Slot 0, Offset 0x60, Length 1570, DumpStyle BYTE
Record Type = INDEX_RECORD Record Attributes = NULL_BITMAP VARIABLE_COLUMNS
Record Size = 1570
Memory Dump @0x0724C060
00000000: 36050000 00a20100 00010000 00030000 01002206 6.................".
00000014: 61616161 61616161 61616161 61616161 61616161 aaaaaaaaaaaaaaaaaaaa
00000028: 61616161 61616161 61616161 61616161 61616161 aaaaaaaaaaaaaaaaaaaa
---------------------- 此处省略
00000604: 61616161 61616161 61616161 61616161 61616161 aaaaaaaaaaaaaaaaaaaa
00000618: 61616161 61616161 6161 aaaaaaaaaa
Slot 1, Offset 0xca4, Length 2020, DumpStyle BYTE
Record Type = INDEX_RECORD Record Attributes = NULL_BITMAP VARIABLE_COLUMNS
Record Size = 2020
Memory Dump @0x0724CCA4
00000000: 360a0000 00a20100 00010001 00030000 0100e407 6...................
00000014: 62626262 62626262 62626262 62626262 62626262 bbbbbbbbbbbbbbbbbbbb
---------------------- 此处省略
000007D0: 62626262 62626262 62626262 62626262 62626262 bbbbbbbbbbbbbbbbbbbb
OFFSET TABLE:
Row - Offset
1 (0x1) - 3236 (0xca4)
0 (0x0) - 96 (0x60)
DBCC execution completed. If DBCC printed error messages, contact your system administrator.
可以明显的看到420页面中的C,D,E数据已经移到了新的页面。
再看一下碎片的情况。
SET NOCOUNT ON
--Use the pubs database
USE DDDD
DBCC SHOWCONTIG (bigrows,NonClusteredIndex)-- WITH ALL_INDEXES
GO
DBCC SHOWCONTIG scanning 'bigrows' table...
Table: 'bigrows' (1349579846); index ID: 2, database ID: 10
LEAF level scan performed.
- Pages Scanned................................: 2
- Extents Scanned..............................: 2
- Extent Switches..............................: 1
- Avg. Pages per Extent........................: 1.0
- Scan Density [Best Count:Actual Count].......: 50.00% [1:2]
- Logical Scan Fragmentation ..................: 50.00%
- Extent Scan Fragmentation ...................: 0.00%
- Avg. Bytes Free per Page.....................: 3941.0
- Avg. Page Density (full).....................: 51.31%
DBCC execution completed. If DBCC printed error messages, contact your system administrator.
Avg. Bytes Free per Page : 3941.0, Avg. Page Density (full) :51.31%,Logical Scan Fragmentation ..................: 50.00%
从这个参数来看,更新INCLUDE indexes中的非键列明显产生了碎片(包括 Avg. Page Density (full),Logical Scan Fragmentation )。
第一次写技术博文,并且我对索引碎片的理解也是刚开始研究,写的不大好,希望各位多见谅。
顺便说一下,SQL SERVER 只有2个碎片类型: Avg. Page Density (full) 跟 Logical Scan Fragmentation(Extent Scan Fragmentation 其实也属于逻辑碎片),
神马内部碎片,外部碎片都是山寨的说法,不受官方文档的支持。