使用GUID作為數據庫主鍵的測試
今天聽了MSDN的WebCast,是關于Entlib的數據訪問的講座,末尾我問了兩個自己所關心的問題:
- 在一個較大型的應用中,如果需要用到兩套以上的數據庫(如:SQL Server和Oracle),是否可以把需要的sql查詢全部封裝在存儲過程里,這樣就只需要一套訪問代碼了,有沒有更好的方法解決這個問題?
- 在數據庫的主鍵的設立中(同時支持多種數據庫)直接用GUID作為主鍵來得簡單,但是在查詢的時候影響性能的因素大不大,還有沒有更好的解決方法?
以上兩個問題,由于時間的關系吧,微軟的工程師解答的比較簡略,第一個應該需要針對具體的應用來考慮,但是第二個問題,性能影響肯定是有的,但是影響大不大呢,帶著這個問題,我做了這個小試驗。
注:如果您有更好的建議不防貢獻出來大家探討探討^_^!
測試環境:
- Dell筆記本電腦 迅馳1.5G
- Win XP professional
- 512MB DDR RAM
- SQL Server 2000 個人版
測試方法:
- 建立有10個字段的數據庫[test_GUID],使用GUID作為主鍵,以及其他常用的字段類型,模擬現實中的使用情況,建表的SQL代碼如下:
CREATE TABLE [dbo].[Test_GUID] (
[GUID] [varchar] (50) COLLATE Chinese_PRC_CI_AS NOT NULL ,
[test1] [varchar] (50) COLLATE Chinese_PRC_CI_AS NULL ,
[test2] [datetime] NULL ,
[test3] [varchar] (50) COLLATE Chinese_PRC_CI_AS NULL ,
[test4] [varchar] (100) COLLATE Chinese_PRC_CI_AS NULL ,
[test5] [varchar] (100) COLLATE Chinese_PRC_CI_AS NULL ,
[test6] [varchar] (50) COLLATE Chinese_PRC_CI_AS NULL ,
[test7] [text] COLLATE Chinese_PRC_CI_AS NULL ,
[test8] [int] NULL ,
[test9] [int] NULL
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GOALTER TABLE [dbo].[Test_GUID] WITH NOCHECK ADD
CONSTRAINT [PK_Test_GUID] PRIMARY KEY CLUSTERED
(
[GUID]
) ON [PRIMARY]
GO - 建立有10個字段的數據庫[test_IIDD],使用IIDD作為主鍵,以及其他常用的字段類型,模擬現實中的使用情況,建表的SQL代碼如下:
CREATE TABLE [dbo].[Test_IIDD] (
[IIDD] [numeric] (9) IDENTITY(1,1) NOT NULL ,
[test1] [varchar] (50) COLLATE Chinese_PRC_CI_AS NULL ,
[test2] [datetime] NULL ,
[test3] [varchar] (50) COLLATE Chinese_PRC_CI_AS NULL ,
[test4] [varchar] (100) COLLATE Chinese_PRC_CI_AS NULL ,
[test5] [varchar] (100) COLLATE Chinese_PRC_CI_AS NULL ,
[test6] [varchar] (50) COLLATE Chinese_PRC_CI_AS NULL ,
[test7] [text] COLLATE Chinese_PRC_CI_AS NULL ,
[test8] [int] NULL ,
[test9] [int] NULL
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GOALTER TABLE [dbo].[Test_IIDD] WITH NOCHECK ADD
CONSTRAINT [PK_Test_IIDD] PRIMARY KEY CLUSTERED
(
[IIDD]
) ON [PRIMARY]
GO - 可以看到,第一個表使用全局唯一標識(GUID)來作為主鍵,而第二個表使用普通numeric(類似Int型)的數據類型來作為主鍵,關于GUID這里做一個小小介紹:
GUID,全局唯一標識,常用在COM組件的標識里,因為此幾乎不可能生成重復的兩個值,所以在各個領域經常用到,具體的值如:“A89C9547-032B-4860-ABB5-6EAEAVE934D5”所示,你一定看到過類似的字符串吧,^_^,在SQL Server2000 中使用newid()函數來獲取一個唯一的GUID - 分別運行如下兩個SQL語句對兩個表分別插入10萬條語句,我所關心大數據量的情況下的效果,所以不要怪我開始點選擇10萬條數據的情況^_^。
declare @num int
set @num = 0
while(@num < 100000)
begininsert into test_Guid
values(
newid(),
'X222222222222222222',
getdate(),
'AAAAAAAAAAAAAAAAAA',
'BBBBBBBBBBBBBBBB',
'CCCCCCCCCCCCCCCCCCCCCC',
'DDDDDDDDDDDDDDDDD',
'479C8AAD-3040-4FC5-B53A-D6AF085AD38A
479C8AAD-3040-4FC5-B53A-D6AF085AD38A
479C8AAD-3040-4FC5-B53A-D6AF085AD38A
479C8AAD-3040-4FC5-B53A-D6AF085AD38A
479C8AAD-3040-4FC5-B53A-D6AF085AD38A
479C8AAD-3040-4FC5-B53A-D6AF085AD38A
479C8AAD-3040-4FC5-B53A-D6AF085AD38A
479C8AAD-3040-4FC5-B53A-D6AF085AD38A
',
'1',
'0'
)set @num = @num+1
enddeclare @num int
set @num = 0
while(@num < 100000)
begininsert into test_IIDD
values(
'X222222222222222222',
getdate(),
'AAAAAAAAAAAAAAAAAA',
'BBBBBBBBBBBBBBBB',
'CCCCCCCCCCCCCCCCCCCCCC',
'DDDDDDDDDDDDDDDDD',
'479C8AAD-3040-4FC5-B53A-D6AF085AD38A
479C8AAD-3040-4FC5-B53A-D6AF085AD38A
479C8AAD-3040-4FC5-B53A-D6AF085AD38A
479C8AAD-3040-4FC5-B53A-D6AF085AD38A
479C8AAD-3040-4FC5-B53A-D6AF085AD38A
479C8AAD-3040-4FC5-B53A-D6AF085AD38A
479C8AAD-3040-4FC5-B53A-D6AF085AD38A
479C8AAD-3040-4FC5-B53A-D6AF085AD38A
',
'1',
'0'
)set @num = @num+1
end - 開始測試,測試代碼及顯示結果如下:
#測試一 (GUID) --------------------
declare @times datetime
set @times = getdate()
--------------------
select * from test_guid
where
guid='A89C9547-032B-4860-ABB5-6EAEA0E934D5' or
guid='FFFA8619-BC9F-4B76-ACE8-B3324105BBDE' or
guid='FFFC26D5-6ECF-479D-838D-0D3E23AC7D2D' or
guid='FFF9FA53-E115-450A-A52D-B0AET36FF539' or
guid='A89C9547-032B-4860-ABB5-6EAEAVE934D5' or
guid='FFF90A0B-CB5B-446F-81FC-CFA661D03CF8' or
guid='FFF85F4A-4554-491F-9D1A-05C8BA3C1266' or
guid='FFFF354A-ED3E-4C3A-A033-3406F229EB34'
order by guid desc---------------------
select datediff(second,@times,getdate()) as 秒,datediff(ms,@times,getdate()) as 毫秒
---------------------0秒,0毫秒,有時會有10毫秒的情況 #測試二 (IIDD) --------------------
declare @times datetime
set @times = getdate()
--------------------
select * from test_IIDD
where
IIDD='1' or
IIDD='2' or
IIDD='200' or
IIDD='8000' or
IIDD='8900' or
IIDD='3' or
IIDD='8' or
IIDD='10000'
order by IIDD desc---------------------
select datediff(second,@times,getdate()) as 秒,datediff(ms,@times,getdate()) as 毫秒
---------------------0秒,0毫秒,有時會有10毫秒的情況 - 可以看到在10萬條數據的情況下,普通Select查詢的時候效率影響還不大
#測試三 (GUID) --------------------
declare @times datetime
set @times = getdate()
--------------------
select count(*) from test_guid
---------------------
select datediff(second,@times,getdate()) as 秒,datediff(ms,@times,getdate()) as 毫秒
---------------------29秒,28793毫秒,效果不好啊! #測試四(IIDD) --------------------
declare @times datetime
set @times = getdate()
--------------------
select count(*) from test_IIDD
---------------------
select datediff(second,@times,getdate()) as 秒,datediff(ms,@times,getdate()) as 毫秒
---------------------第一次運行3秒,第二次運行1秒,第三次運行0秒,50毫秒,my god! - 這可如何是好,GUID在沒有where子句的聚合運算時吃大虧了
#測試五 (GUID) --------------------
declare @times datetime
set @times = getdate()
--------------------
select count(*) from test_guid
where
test2 > '2005-06-03 21:05:33.330'
---------------------
select datediff(second,@times,getdate()) as 秒,datediff(ms,@times,getdate()) as 毫秒
---------------------29秒,29093毫秒,盡管查詢出來只有200多條數據但速度沒有變化! #測試六(IIDD) --------------------
declare @times datetime
set @times = getdate()
--------------------
select count(*) from test_IIDD
where
test2 > '2005-06-03 21:05:33.330'
---------------------
select datediff(second,@times,getdate()) as 秒,datediff(ms,@times,getdate()) as 毫秒
---------------------第一次運行2秒,第二次運行0秒,160毫秒,比沒有Where的情況稍慢 - 如結果所示,效果很不理想
#測試七 (GUID) 把test_GUID這個表的test2這一列(datetime)添加為索引列 運行【測試三】0秒,50毫秒,原來如此。。。
運行【測試五】0秒,0毫秒,非常明顯了吧。
#測試八(IIDD) 把test_IIDD這個表的test2這一列(datetime)添加為索引列 運行【測試四】0秒,40毫秒
運行【測試六】0秒,40毫秒
- 上面的測試七和測試八在返回值方面不盡相同造成一些微小的差別這個可以忽略(因為我測試了在相同返回值的情況下差別是很小的)
- 可以看出在以GUID作為主鍵的表中加一個時間類型或是Int類型的索引可以彌補以GUID作為主鍵帶來的性能損失。
總結:
此次測試由于時間的關系,測試的比較片面也很膚淺,還望能有高手把不足和疏漏的地方進行補充和改進,在這次測試后我想我還會做更多的關于性能方面的測試,有精力再做吧。
此次測試就只得出這么一點膚淺的東西,希望沒有浪費您寶貴的時間^_^!
精彩評論:
留言列表