我一直想當然的認為用GUID做主鍵沒什么大不了,不就是比int多了12位而已嗎?而且現在都是SQL Server 2008, 2012時代了,應該更不是問題了吧?而且微軟很多項目也是用GUID做主鍵啊?Sharepoint, ASP.NET SQL Server Membership Provider默認的表等等。而且還有許多而且......
果真這樣嗎?直到我讀了這兩篇文章后GUIDs as PRIMARY KEYs and/or the clustering key 和 THAT'S NOT THE POINT!!!,結論令我很吃驚,甚至是“震撼”。
確切的講,這種糟糕的結果不僅僅是使用GUID作為主鍵的原因,更主要的,我們通常在把它作為主鍵的同時還把它作為聚集索引。因為SQL Server默認就是這樣的,我們總是接受默認的。注:這里我們是針對隨機無序的GUID,如SQL Server的NEWID(), 客戶端生成的如.NET的 Guid.NewGuid()。如果是順序的GUID,如SQL Server NEWSEQUENTIALID()方法生成的,則不會有聚集索引的問題(但長度帶來的問題依然存在)。事實是誰會用順序的GUID呢?我今天才知道有這個方法。
總結兩篇文章作者的結論,無序GUID作為主鍵以及作為聚集索引所帶來的問題包括:
- 空間的浪費以及由此帶來的讀寫效率的下降。
- 更主要的,存儲的碎片化(fragmentation)以及由此帶來的讀寫效率嚴重下降。
所以,盡量避免用GUID(無序或有序)做主鍵,不要用無序GUID做聚集索引。
我很好奇難道微軟的開發人員也會犯這么低級的錯誤嗎?我打開了ASP.NET SQL Server Membership Provider默認的表查看了一下,發現這些表雖然主鍵是GUID,但聚集索引不是默認的主鍵,如aspnet_Applications聚集索引是LoweredApplicationName字段,aspnet_Users聚集索引是ApplicationId和LoweredUserName連個字段。