在的设计中我们常常用Guid或int来做主键,根据所学的知识一直感觉int做主键效率要高,但没有做仔细的无法
说明道理。碰巧今天在数据库的优化过程中,遇到此问题,于是做了一下测试。
测试环境:
台式电脑 Pentiun(R) 4 Cpu 3.06GHz
Win XP professional 1.5G DDR RAM SQL Server 2005 个人版
测试过程:
首先创建测试数据库Test1.创建Test_Guid表,创建Test_Int表
-------------------------------------------
--创建Test_Guid表---------------------------------------------USE TestIF OBJECT_ID('Test_Guid', 'U') IS NOT NULL DROP TABLE Test_GuidGOCREATE TABLE Test_Guid( Guid varchar(50) not null, TestId int not null, TestText ntext not null, TestDateTime datetime default getdate(), CONSTRAINT PK_Guid PRIMARY KEY (Guid))GO-----------------------------------------------创建Test_Int表---------------------------------------------USE TestGOIF OBJECT_ID('Test_Int', 'U') IS NOT NULL DROP TABLE Test_IntGOCREATE TABLE Test_Int( Id int not null identity(1,1), TestId int not null, TestText ntext not null, TestDateTime datetime default getdate(), CONSTRAINT PK_Id PRIMARY KEY (Id))GO
2.创建Test_Guid子表:Test_Guid_Detail和创建Test_Int子表:Test_Int_Detail,用来做连接查询
--创建Test_Guid子表:Test_Guid_Detail
USE TestGOIF OBJECT_ID('Test_Guid_Detail', 'U') IS NOT NULL DROP TABLE Test_Guid_DetailGOCREATE TABLE Test_Guid_Detail( Guid varchar(50) not null,--Guid是Test_Guid的外键 TestId int not null, TestText ntext not null, TestDateTime datetime default getdate()--, --CONSTRAINT PK_Guid PRIMARY KEY (Guid))GO--创建Test_Int子表:Test_Int_DetailUSE TestGOIF OBJECT_ID('Test_Int_Detail', 'U') IS NOT NULL DROP TABLE Test_Int_DetailGOCREATE TABLE Test_Int_Detail( Id int not null,--Id是Test_Int的外键 TestId int not null, TestText ntext not null, TestDateTime datetime default getdate()--, --CONSTRAINT PK_Guid PRIMARY KEY (Guid))GO
3.开始测试
测试1:测试Insert:向Test_Guid表中插入10万条记录
---------------------------------------------
--测试Insert:向Test_Guid表中插入10万条记录---------------------------------------------declare @num intdeclare @startTime datetimeset @num=0;set @startTime=getdate()while(@num<100000)begin insert into Test_Guid values(newid(),@num,'测试guid',getdate()) set @num=@num+1endselect datediff(second,@startTime,getdate()) as 秒,datediff(ms,@startTime,getdate()) as 毫秒
测试2:测试Insert:向Test_Int表中插入10万条记录
---------------------------------------------
--测试Insert:向Test_Int表中插入10万条记录---------------------------------------------declare @num intdeclare @startTime datetimeset @num=0;set @startTime=getdate()while(@num<100000)begin insert into Test_Int values(@num,'测试int',getdate()) set @num=@num+1endselect datediff(second,@startTime,getdate()) as 秒,datediff(ms,@startTime,getdate()) as 毫秒
测试3:测试Select:查找Test_Guid表中所有记录
---------------------------------------------
--测试Select:查找Test_Guid表中所有记录---------------------------------------------declare @startTime datetimeset @startTime=getdate()select * from Test_Guidselect datediff(second,@startTime,getdate()) as 秒,datediff(ms,@startTime,getdate()) as 毫秒
测试4:测试Select:查找Test_Int表中所有记录
---------------------------------------------
--测试Select:查找Test_Int表中所有记录---------------------------------------------declare @startTime datetimeset @startTime=getdate()select * from Test_Intselect datediff(second,@startTime,getdate()) as 秒,datediff(ms,@startTime,getdate()) as 毫秒
测试5:聚合查询:查找Test_Guid表中所有记录数
---------------------------------------------
--聚合查询:查找Test_Guid表中所有记录---------------------------------------------declare @startTime datetimeset @startTime=getdate()select count(*) from Test_Guidselect datediff(second,@startTime,getdate()) as 秒,datediff(ms,@startTime,getdate()) as 毫秒
测试6:聚合查询:查找Test_Int表中所有记录数
---------------------------------------------
--聚合查询:查找Test_Int表中所有记录---------------------------------------------declare @startTime datetimeset @startTime=getdate()select count(*) from Test_Intselect datediff(second,@startTime,getdate()) as 秒,datediff(ms,@startTime,getdate()) as 毫秒
测试7:测试带where条件的Select查询:查找Test_Int表中所有记录,都查找10000到50000之间的4万条记录
----------------------------------------------------------------------------------------
--测试带where条件的Select查询:查找Test_Int表中所有记录,都查找10000到50000之间的4万条记录----------------------------------------------------------------------------------------declare @startTime datetimeset @startTime=getdate()select * from Test_Guid where TestId between 10000 and 50000 select datediff(second,@startTime,getdate()) as 秒,datediff(ms,@startTime,getdate()) as 毫秒
测试8:测试带where条件的Select查询:查找Test_Int表中所有记录,都查找10000到50000之间的4万条记录
----------------------------------------------------------------------------------------
--测试带where条件的Select查询:查找Test_Int表中所有记录,都查找10000到50000之间的4万条记录----------------------------------------------------------------------------------------declare @startTime datetimeset @startTime=getdate()select * from Test_Int where TestId between 10000 and 50000 select datediff(second,@startTime,getdate()) as 秒,datediff(ms,@startTime,getdate()) as 毫秒
测试9:测试Test_Guid关联查询inner join
首先以Test_Guid中第一个Guid为外键,向Test_Guid_Detail中插入1万条记录
---------------------------------------------
--向Test_Guid子表:Test_Guid_Detail中插入1万条记录---------------------------------------------declare @num intdeclare @topGuid nvarchar(50)set @num=0;select top 1 @topGuid=Guid from Test_Guidwhile(@num<10000)begin insert into Test_Guid_Detail values(@topGuid,@num,'测试guid的子表',getdate()) set @num=@num+1end
然后开始测试:
---------------------------------------------
--测试连接查询:查找Test_Guid表和Test_Guid_Detail所有关联的记录---------------------------------------------declare @startTime datetimeset @startTime=getdate()select T.* from Test_Guid Tinner join Test_Guid_Detail T1 on T.Guid=T1.Guidselect datediff(second,@startTime,getdate()) as 秒,datediff(ms,@startTime,getdate()) as 毫秒
测试10:测试Test_Int关联查询inner join
首先以Test_Int中第一个id为外键,向Test_Int_Detail中插入1万条记录
---------------------------------------------
--向Test_Int子表:Test_Int中插入1万条记录---------------------------------------------declare @num intdeclare @topInt intset @num=0;select top 1 @topInt=Id from Test_Intwhile(@num<10000)begin insert into Test_Int_Detail values(@topInt,@num,'测试int的子表',getdate()) set @num=@num+1end
然后开始测试:
---------------------------------------------
--测试连接查询:查找Test_Int表和Test_Int_Detail所有关联的记录---------------------------------------------declare @startTime datetimeset @startTime=getdate()select T.* from Test_Int Tinner join Test_Int_Detail T1 on T.id=T1.idselect datediff(second,@startTime,getdate()) as 秒,datediff(ms,@startTime,getdate()) as 毫秒
测试11:测试Update:更新Test_Guid表中所有记录
---------------------------------------------
--测试Update:查找Test_Guid表中所有记录---------------------------------------------declare @startTime datetimeset @startTime=getdate()update Test_Guid set TestText='测试guid更新'select datediff(second,@startTime,getdate()) as 秒,datediff(ms,@startTime,getdate()) as 毫秒
测试12:测试Update:更新Test_Int表中所有记录
---------------------------------------------
--测试Update:查找Test_Int表中所有记录---------------------------------------------declare @startTime datetimeset @startTime=getdate()update Test_Int set TestText='测试int更新'select datediff(second,@startTime,getdate()) as 秒,datediff(ms,@startTime,getdate()) as 毫秒
测试13:测试Delete:删除Test_Guid表中所有记录
---------------------------------------------
--测试Delete:查找Test_Guid表中所有记录---------------------------------------------declare @startTime datetimeset @startTime=getdate()delete from Test_Guidselect datediff(second,@startTime,getdate()) as 秒,datediff(ms,@startTime,getdate()) as 毫秒delete from Test_Guid_Detail
测试14:测试Delete:删除Test_Int表中所有记录
---------------------------------------------
--测试Delete:查找Test_Int表中所有记录---------------------------------------------declare @startTime datetimeset @startTime=getdate()delete from Test_Intselect datediff(second,@startTime,getdate()) as 秒,datediff(ms,@startTime,getdate()) as 毫秒delete from Test_int_Detail
测试结果如下:
上所述,使用int做主键比用guid做主键各中情况下效率均有提高,特别是在有连接查询和删除记录效率提升明显。
而且本人今日在guid做主键的数据查询中因为嵌套几个子查询结果屡屡出现查询超时。因此本人赞同用int做主键,不赞同guid做主键。以上观点代表个人观点,欢迎大家各抒己见,说明guid和int各自做主键的优劣所在。
附上测试脚本供大家测试:
后续测试:
经过各位兄弟的提醒,今天在两个子表添加了非聚集索引:然后进行内连接查询,发现如@徐少侠说所的,效率确实不至于提示50%以上明显,基本只有23%左右的提升,这个还是可以接受的。
因此建议
1.在经常需要做数据迁移的系统中,建议用Guid。并且在相应的外键字段,也就是用来做连接查询的字段添加非聚集索引,对于改善性能有极大的好处。where条件的字段也可以适当添加非聚集索引。
2.在使用Guid类型作为主键时,数据类型应为uniqueidentifier,并且一定要记得取消主键的“聚集索引”
3.对于不需要做迁移,或小型系统,用int做主键还是很方便的,并且在效率方面还是有一定提升的。