1. 程式人生 > >SQL SERVER下有序GUID和無序GUID作為主鍵&聚集索引的效能表現

SQL SERVER下有序GUID和無序GUID作為主鍵&聚集索引的效能表現

 背景

  前段時間學習《Microsoft SQL Server 2008技術內幕:T-SQL查詢》時,看到裡面關於無序GUID作為主鍵與聚集索引的建議,無序GUID作為主鍵以及作為聚集索引所帶來的問題包括:

  1. 空間的浪費以及由此帶來的讀寫效率的下降。
  2. 更主要的,儲存的碎片化(fragmentation)以及由此帶來的讀寫效率嚴重下降。

所以,儘量避免用GUID(無序或有序)做主鍵,不要用無序GUID做聚集索引。<摘自博友部落格>

  想到在工作中存在一個檢視轉成物理表的時候使用到了此種場景,分析了一下資料情況,已經有較多客戶此表的資料將近百萬級,後續會繼續線性增長,而且在程式碼規範也強制要求不允許使用無序GUID,需要調整為有序的GUID,對於修改前後的表現,還是想做一個對比分析...

一、插入無序GUID資料

複製程式碼
 1 --建立表並插入無序GUID資料
 2 --DROP TABLE T_PROORDERTYPEGUIDTEST;
 3 create table T_PROORDERTYPEGUIDTEST (
 4    FENTRYID             varchar(36)          not null default ' ',
 5    FPROORDERENTRYID     int                  not null default 0,
 6    FPROORDERTYPE        varchar
(20) not null default ' ', 7 FFORMID varchar(36) not null default ' ', 8 FNUMBER nvarchar(160) not null default ' ', 9 FCREATEORGID int not null default 0, 10 FUSEORGID int not null
default 0, 11 FDOCUMENTSTATUS char(1) not null default 'C', 12 FFORBIDSTATUS char(1) not null default 'A', 13 FDATE datetime not null default getdate(), 14 FMATERIALID int not null default 0, 15 FBOMID int not null default 0, 16 FAUXPROPID int not null default 0, 17 FLOT int not null default 0, 18 FMtoNo nvarchar(200) not null default '', 19 FSEQ int not null default 0, 20 FUNITID int not null default 0, 21 FPRODUCTID int not null default 0, 22 FWORKSHOPID int not null default 0, 23 FCOSTCENTERID int not null default 0, 24 constraint PK_PROORDERTYPE primary key (FENTRYID) 25 ) 26 --插入500000條資料 27 declare @i int 28 set @i = 1 29 while @i < 500000 30 begin 31 INSERT INTO T_PROORDERTYPEGUIDTEST(FENTRYID,FPROORDERENTRYID,FPROORDERTYPE,FFORMID,FNUMBER,FCREATEORGID, 32 FUSEORGID,FDOCUMENTSTATUS,FFORBIDSTATUS,FDATE,FMATERIALID,FBOMID,FAUXPROPID,FLOT, 33 FSEQ,FUNITID,FPRODUCTID,FWORKSHOPID,FCOSTCENTERID) values 34 (NEWID(),@i,'PO','FORM_OUTSRCPROORDER','TEST00001',@i,@i,'C','A',GETDATE(),@i,@i,@i,@i,@i,@i,@i,@i,@i) 35 SET @i=@i+1 36 end ; 37 38 select COUNT(1) from T_PROORDERTYPEGUIDTEST
複製程式碼

 

二、插入有序GUID資料

複製程式碼
 1 --建立表並插入有序GUID資料
 2 DROP TABLE T_PROORDERTYPESEQGUIDTEST;
 3 create table T_PROORDERTYPESEQGUIDTEST (
 4    FENTRYID             uniqueidentifier     not null default (NEWSEQUENTIALID()),
 5    FPROORDERENTRYID     int                  not null default 0,
 6    FPROORDERTYPE        varchar(20)          not null default ' ',
 7    FFORMID              varchar(36)          not null default ' ',
 8    FNUMBER              nvarchar(160)        not null default ' ',
 9    FCREATEORGID         int                  not null default 0,
10    FUSEORGID            int                  not null default 0,
11    FDOCUMENTSTATUS      char(1)              not null default 'C',
12    FFORBIDSTATUS        char(1)              not null default 'A',
13    FDATE                datetime             not null default getdate(),
14    FMATERIALID          int                  not null default 0,
15    FBOMID               int                  not null default 0,
16    FAUXPROPID           int                  not null default 0,
17    FLOT                 int                  not null default 0,
18    FMtoNo               nvarchar(200)        not null default '',
19    FSEQ                 int                  not null default 0,
20    FUNITID              int                  not null default 0,
21    FPRODUCTID           int                  not null default 0,
22    FWORKSHOPID          int                  not null default 0,
23    FCOSTCENTERID        int                  not null default 0,
24    constraint PK_SEQPROORDERTYPE primary key (FENTRYID)
25 )
26 --插入500000條資料
27 declare @i int
28 set @i = 1 
29 while @i < 500000
30 begin 
31 INSERT INTO T_PROORDERTYPESEQGUIDTEST(FPROORDERENTRYID,FPROORDERTYPE,FFORMID,FNUMBER,FCREATEORGID,
32 FUSEORGID,FDOCUMENTSTATUS,FFORBIDSTATUS,FDATE,FMATERIALID,FBOMID,FAUXPROPID,FLOT,
33 FSEQ,FUNITID,FPRODUCTID,FWORKSHOPID,FCOSTCENTERID) values
34 (@i,'PO','FORM_OUTSRCPROORDER','TEST00001',@i,@i,'C','A',GETDATE(),@i,@i,@i,@i,@i,@i,@i,@i,@i)
35 SET @i=@i+1
36 end ;
37 
38 select COUNT(1) from T_PROORDERTYPESEQGUIDTEST
複製程式碼

 

三、分析索引碎片

1 --分析索引碎片
2 declare @table_id int
3 set @table_id=object_id('T_PROORDERTYPEGUIDTEST') 
4 dbcc showcontig(@table_id);

DBCC SHOWCONTIG 正在掃描 'T_PROORDERTYPEGUIDTEST' 表...
表: 'T_PROORDERTYPEGUIDTEST' (410536596);索引 ID: 1,資料庫 ID: 8
已執行 TABLE 級別的掃描。
- 掃描頁數................................: 13933
- 掃描區數..............................: 1759
- 區切換次數..............................: 13932
- 每個區的平均頁數........................: 7.9
- 掃描密度 [最佳計數:實際計數].......: 12.50% [1742:13933]
- 邏輯掃描碎片 ..................: 99.22%
- 區掃描碎片 ..................: 0.11%
- 每頁的平均可用位元組數.....................: 2569.6
- 平均頁密度(滿).....................: 68.25%
DBCC 執行完畢。如果 DBCC 輸出了錯誤資訊,請與系統管理員聯絡。

1 declare @table_id int
2 set @table_id=object_id('T_PROORDERTYPESEQGUIDTEST') 
3 dbcc showcontig(@table_id) 

DBCC SHOWCONTIG 正在掃描 'T_PROORDERTYPESEQGUIDTEST' 表...
表: 'T_PROORDERTYPESEQGUIDTEST' (1114539104);索引 ID: 1,資料庫 ID: 8
已執行 TABLE 級別的掃描。
- 掃描頁數................................: 8197
- 掃描區數..............................: 1033
- 區切換次數..............................: 1032
- 每個區的平均頁數........................: 7.9
- 掃描密度 [最佳計數:實際計數].......: 99.23% [1025:1033]
- 邏輯掃描碎片 ..................: 0.67%
- 區掃描碎片 ..................: 0.10%
- 每頁的平均可用位元組數.....................: 44.3
- 平均頁密度(滿).....................: 99.45%
DBCC 執行完畢。如果 DBCC 輸出了錯誤資訊,請與系統管理員聯絡。

 

四、佔用空間情況

1 sp_spaceused 'T_PROORDERTYPEGUIDTEST';

1 sp_spaceused 'T_PROORDERTYPESEQGUIDTEST';

 

五、查詢執行情況

1 select * from T_PROORDERTYPEGUIDTEST ;
2 select * from T_PROORDERTYPESEQGUIDTEST ;

 再分別插入50W資料

複製程式碼
 1 declare @i int
 2 set @i = 1 
 3 while @i < 500000
 4 begin 
 5 INSERT INTO T_PROORDERTYPEGUIDTEST(FENTRYID,FPROORDERENTRYID,FPROORDERTYPE,FFORMID,FNUMBER,FCREATEORGID,
 6 FUSEORGID,FDOCUMENTSTATUS,FFORBIDSTATUS,FDATE,FMATERIALID,FBOMID,FAUXPROPID,FLOT,
 7 FSEQ,FUNITID,FPRODUCTID,FWORKSHOPID,FCOSTCENTERID) values
 8 (NEWID(),@i,'PO','FORM_OUTSRCPROORDER','TEST00001',@i,@i,'C','A',GETDATE(),@i,@i,@i,@i,@i,@i,@i,@i,@i)
 9 SET @i=@i+1
10 end ;
11 
12 declare @i int
13 set @i = 1 
14 while @i < 500000
15 begin 
16 INSERT INTO T_PROORDERTYPESEQGUIDTEST(FPROORDERENTRYID,FPROORDERTYPE,FFORMID,FNUMBER,FCREATEORGID,
17 FUSEORGID,FDOCUMENTSTATUS,FFORBIDSTATUS,FDATE,FMATERIALID,FBOMID,FAUXPROPID,FLOT,
18 FSEQ,FUNITID,FPRODUCTID,FWORKSHOPID,FCOSTCENTERID) values
19 (@i,'PO','FORM_OUTSRCPROORDER','TEST00001',@i,@i,'C','A',GETDATE(),@i,@i,@i,@i,@i,@i,@i,@i,@i)
20 SET @i=@i+1
21 end ;
複製程式碼

 

參考文章

http://msdn.microsoft.com/zh-cn/library/ms175008(v=sql.90).aspx

http://msdn.microsoft.com/zh-cn/library/ms188776.aspx

http://www.sqlskills.com/blogs/kimberly/disk-space-is-cheap/

http://www.cnblogs.com/zhouruifu/archive/2012/04/18/2454088.html

Microsoft SQL Server 2008技術內幕:T-SQL查詢

 

**********轉載:https://www.cnblogs.com/springwind268/p/3984175.html

 背景

  前段時間學習《Microsoft SQL Server 2008技術內幕:T-SQL查詢》時,看到裡面關於無序GUID作為主鍵與聚集索引的建議,無序GUID作為主鍵以及作為聚集索引所帶來的問題包括:

  1. 空間的浪費以及由此帶來的讀寫效率的下降。
  2. 更主要的,儲存的碎片化(fragmentation)以及由此帶來的讀寫效率嚴重下降。

所以,儘量避免用GUID(無序或有序)做主鍵,不要用無序GUID做聚集索引。<摘自博友部落格>

  想到在工作中存在一個檢視轉成物理表的時候使用到了此種場景,分析了一下資料情況,已經有較多客戶此表的資料將近百萬級,後續會繼續線性增長,而且在程式碼規範也強制要求不允許使用無序GUID,需要調整為有序的GUID,對於修改前後的表現,還是想做一個對比分析...

一、插入無序GUID資料

複製程式碼
 1 --建立表並插入無序GUID資料
 2 --DROP TABLE T_PROORDERTYPEGUIDTEST;
 3 create table T_PROORDERTYPEGUIDTEST (
 4    FENTRYID             varchar(36)          not null default ' ',
 5    FPROORDERENTRYID     int                  not null default 0,
 6    FPROORDERTYPE        varchar(20)          not null default ' ',
 7    FFORMID              varchar(36)          not null default ' ',
 8    FNUMBER              nvarchar(160)        not null default ' ',
 9    FCREATEORGID         int                  not null default 0,
10    FUSEORGID            int                  not null default 0,
11    FDOCUMENTSTATUS      char(1)              not null default 'C',
12    FFORBIDSTATUS        char(1)              not null default 'A',
13    FDATE                datetime             not null default getdate(),
14    FMATERIALID          int                  not null default 0,
15    FBOMID               int                  not null default 0,
16    FAUXPROPID           int                  not null default 0,
17    FLOT                 int                  not null default 0,
18    FMtoNo               nvarchar(200)        not null default '',
19    FSEQ                 int                  not null default 0,
20    FUNITID              int                  not null default 0,
21    FPRODUCTID           int                  not null default 0,
22    FWORKSHOPID          int                  not null default 0,
23    FCOSTCENTERID        int                  not null default 0,
24    constraint PK_PROORDERTYPE primary key (FENTRYID)
25 )
26 --插入500000條資料
27 declare @i int
28 set @i = 1 
29 while @i < 500000
30 begin 
31 INSERT INTO T_PROORDERTYPEGUIDTEST(FENTRYID,FPROORDERENTRYID,FPROORDERTYPE,FFORMID,FNUMBER,FCREATEORGID,
32 FUSEORGID,FDOCUMENTSTATUS,FFORBIDSTATUS,FDATE,FMATERIALID,FBOMID,FAUXPROPID,FLOT,
33 FSEQ,FUNITID,FPRODUCTID,FWORKSHOPID,FCOSTCENTERID) values
34 (NEWID(),@i,'PO','FORM_OUTSRCPROORDER','TEST00001',@i,@i,'C','A',GETDATE(),@i,@i,@i,@i,@i,@i,@i,@i,@i)
35 SET @i=@i+1
36 end ;
37 
38 select COUNT(1) from T_PROORDERTYPEGUIDTEST
複製程式碼

 

二、插入有序GUID資料

複製程式碼
 1 --建立表並插入有序GUID資料
 2 DROP TABLE T_PROORDERTYPESEQGUIDTEST;
 3 create table T_PROORDERTYPESEQGUIDTEST (
 4    FENTRYID             uniqueidentifier     not null default (NEWSEQUENTIALID()),
 5    FPROORDERENTRYID     int                  not null default 0,
 6    FPROORDERTYPE        varchar(20)          not null default ' ',
 7    FFORMID              varchar(36)          not null default ' ',
 8    FNUMBER              nvarchar(160)        not null default ' ',
 9    FCREATEORGID         int                  not null default 0,
10    FUSEORGID            int                  not null default 0,
11    FDOCUMENTSTATUS      char(1)              not null default 'C',
12    FFORBIDSTATUS        char(1)              not null default 'A',
13    FDATE                datetime             not null default getdate(),
14    FMATERIALID          int                  not null default 0,
15    FBOMID               int                  not null default 0,
16    FAUXPROPID           int                  not null default 0,
17    FLOT                 int                  not null default 0,
18    FMtoNo               nvarchar(200)        not null default '',
19    FSEQ                 int                  not null default 0,
20    FUNITID              int                  not null default 0,
21    FPRODUCTID           int                  not null default 0,
22    FWORKSHOPID          int                  not null default 0,
23    FCOSTCENTERID        int                  not null default 0,
24    constraint PK_SEQPROORDERTYPE primary key (FENTRYID)
25 )
26 --插入500000條資料
27 declare @i int
28 set @i = 1 
29 while @i < 500000
30 begin 
31 INSERT INTO T_PROORDERTYPESEQGUIDTEST(FPROORDERENTRYID,FPROORDERTYPE,FFORMID,FNUMBER,FCREATEORGID,
32 FUSEORGID,FDOCUMENTSTATUS,FFORBIDSTATUS,FDATE,FMATERIALID,FBOMID,FAUXPROPID,FLOT,
33 FSEQ,FUNITID,FPRODUCTID,FWORKSHOPID,FCOSTCENTERID) values
34 (@i,'PO','FORM_OUTSRCPROORDER','TEST00001',@i,@i,'C','A',GETDATE(),@i,@i,@i,@i,@i,@i,@i,@i,@i)
35 SET @i=@i+1
36 end ;
37 
38 select COUNT(1) from T_PROORDERTYPESEQGUIDTEST
複製程式碼

 

三、分析索引碎片

1 --分析索引碎片
2 declare @table_id int
3 set @table_id=object_id('T_PROORDERTYPEGUIDTEST') 
4 dbcc showcontig(@table_id);

DBCC SHOWCONTIG 正在掃描 'T_PROORDERTYPEGUIDTEST' 表...
表: 'T_PROORDERTYPEGUIDTEST' (410536596);索引 ID: 1,資料庫 ID: 8
已執行 TABLE 級別的掃描。
- 掃描頁數................................: 13933
- 掃描區數..............................: 1759
- 區切換次數..............................: 13932
- 每個區的平均頁數........................: 7.9
- 掃描密度 [最佳計數:實際計數].......: 12.50% [1742:13933]
- 邏輯掃描碎片 ..................: 99.22%
- 區掃描碎片 ..................: 0.11%
- 每頁的平均可用位元組數.....................: 2569.6
- 平均頁密度(滿).....................: 68.25%
DBCC 執行完畢。如果 DBCC 輸出了錯誤資訊,請與系統管理員聯絡。

1 declare @table_id int
2 set @table_id=object_id('T_PROORDERTYPESEQGUIDTEST') 
3 dbcc showcontig(@table_id) 

DBCC SHOWCONTIG 正在掃描 'T_PROORDERTYPESEQGUIDTEST' 表...
表: 'T_PROORDERTYPESEQGUIDTEST' (1114539104);索引 ID: 1,資料庫 ID: 8
已執行 TABLE 級別的掃描。
- 掃描頁數................................: 8197
- 掃描區數..............................: 1033
- 區切換次數..............................: 1032
- 每個區的平均頁數........................: 7.9
- 掃描密度 [最佳計數:實際計數].......: 99.23% [1025:1033]
- 邏輯掃描碎片 ..................: 0.67%
- 區掃描碎片 ..................: 0.10%
- 每頁的平均可用位元組數.....................: 44.3
- 平均頁密度(滿).....................: 99.45%
DBCC 執行完畢。如果 DBCC 輸出了錯誤資訊,請與系統管理員聯絡。

 

四、佔用空間情況

1 sp_spaceused 'T_PROORDERTYPEGUIDTEST';

1 sp_spaceused 'T_PROORDERTYPESEQGUIDTEST';

 

五、查詢執行情況

1 select * from T_PROORDERTYPEGUIDTEST ;
2 select * from T_PROORDERTYPESEQGUIDTEST ;

 再分別插入50W資料

複製程式碼
 1 declare @i int
 2 set @i = 1 
 3 while @i < 500000
 4 begin 
 5 INSERT INTO T_PROORDERTYPEGUIDTEST(FENTRYID,FPROORDERENTRYID,FPROORDERTYPE,FFORMID,FNUMBER,FCREATEORGID,
 6 FUSEORGID,FDOCUMENTSTATUS,FFORBIDSTATUS,FDATE,FMATERIALID,FBOMID,FAUXPROPID,FLOT,
 7 FSEQ,FUNITID,FPRODUCTID,FWORKSHOPID,FCOSTCENTERID) values
 8 (NEWID(),@i,'PO','FORM_OUTSRCPROORDER','TEST00001',@i,@i,'C','A',GETDATE(),@i,@i,@i,@i,@i,@i,@i,@i,@i)
 9 SET @i=@i+1
10 end ;
11 
12 declare @i int
13 set @i = 1 
14 while @i < 500000
15 begin 
16 INSERT INTO T_PROORDERTYPESEQGUIDTEST(FPROORDERENTRYID,FPROORDERTYPE,FFORMID,FNUMBER,FCREATEORGID,
17 FUSEORGID,FDOCUMENTSTATUS,FFORBIDSTATUS,FDATE,FMATERIALID,FBOMID,FAUXPROPID,FLOT,
18 FSEQ,FUNITID,FPRODUCTID,FWORKSHOPID,FCOSTCENTERID) values
19 (@i,'PO','FORM_OUTSRCPROORDER','TEST00001',@i,@i,'C','A',GETDATE(),@i,@i,@i,@i,@i,@i,@i,@i,@i)
20 SET @i=@i+1
21 end ;
複製程式碼

 

參考文章

http://msdn.microsoft.com/zh-cn/library/ms175008(v=sql.90).aspx

http://msdn.microsoft.com/zh-cn/library/ms188776.aspx

http://www.sqlskills.com/blogs/kimberly/disk-space-is-cheap/

http://www.cnblogs.com/zhouruifu/archive/2012/04/18/2454088.html

Microsoft SQL Server 2008技術內幕:T-SQL查詢