不要用把无序GUID既作为主键又作为聚集索引
我一直想当然的认为用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连个字段。