测试机器:dell2850,2cpu,2G内存,数据库为简单模式,避免日志记录影响(不过似乎一般的应用场景都是完整模式)
Int自增表
Code
USE [TestGUID]
GO
/****** 对象: Table [dbo].[Int] 脚本日期: 07/31/2009 10:59:58 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Int](
[intID] [int] IDENTITY(1,1) NOT NULL,
[name] [nchar](10) NOT NULL CONSTRAINT [DF_Int_name] DEFAULT ((1234567890)),
CONSTRAINT [PK_Int] PRIMARY KEY CLUSTERED
(
[intID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GUID表
Code
USE [TestGUID]
GO
/****** 对象: Table [dbo].[GUID] 脚本日期: 07/31/2009 11:01:02 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[GUID](
[GUIDID] [uniqueidentifier] NOT NULL,
[name] [nchar](10) NOT NULL CONSTRAINT [DF_GUID_name] DEFAULT ((123456789)),
CONSTRAINT [PK_GUID] PRIMARY KEY CLUSTERED
(
[GUIDID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
顺序GUID表
Code
USE [TestGUID]
GO
/****** 对象: Table [dbo].[OGUID] 脚本日期: 07/31/2009 11:01:55 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[OGUID](
[OGUIDID] [uniqueidentifier] NOT NULL,
[name] [nchar](10) NOT NULL CONSTRAINT [DF_OGUID_name] DEFAULT ((123456789)),
CONSTRAINT [PK_OGUID] PRIMARY KEY CLUSTERED
(
[OGUIDID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
测试插入的脚本:
Code
declare @tmp int;
declare @time datetime;
set @time = getdate();
print @time;
set @tmp = 0;
while @tmp<10000
begin
insert into [Int] values (default);
set @tmp = @tmp+1;
end
select datediff(millisecond,@time,getdate());
Int表插入1w条记录是61626微妙,61560微妙,两次测试结果相差不大。
GUID表插入1w条记录是63156微妙,62436微妙。
基于上两次测试没有测试OGUID表了。
每次测试均truncate了表。
再测试10w条记录的插入情况:
10w
int 620330 618093
GUID
686923 667780
OGUID
635436 642013
从数据能看出int是最快的,其次是顺序化的GUID插入,再次是无序GUID。
再测试一下全表扫描的IO:
set statistics time on
set statistics io on
checkpoint;
dbcc dropcleanbuffers;
select * from [int];
select * from [guid];
select * from [oguid];
统计情况如下:
SQL Server 分析和编译时间:
CPU 时间 = 0 毫秒,占用时间 = 2 毫秒。
SQL Server 执行时间:
CPU 时间 = 0 毫秒,占用时间 = 1 毫秒。
SQL Server 执行时间:
CPU 时间 = 0 毫秒,占用时间 = 1 毫秒。
SQL Server 执行时间:
CPU 时间 = 0 毫秒,占用时间 = 66 毫秒。
DBCC 执行完毕。如果 DBCC 输出了错误信息,请与系统管理员联系。
SQL Server 执行时间:
CPU 时间 = 0 毫秒,占用时间 = 12 毫秒。
(100000 行受影响)
表 'Int'。扫描计数 1,逻辑读取 411 次,物理读取 1 次,预读 450 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。
SQL Server 执行时间:
CPU 时间 = 78 毫秒,占用时间 = 2095 毫秒。
(100000 行受影响)
表 'GUID'。扫描计数 1,逻辑读取 823 次,物理读取 2 次,预读 862 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。
SQL Server 执行时间:
CPU 时间 = 94 毫秒,占用时间 = 2487 毫秒。
(100000 行受影响)
表 'OGUID'。扫描计数 1,逻辑读取 564 次,物理读取 1 次,预读 552 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。
SQL Server 执行时间:
CPU 时间 = 63 毫秒,占用时间 = 1511 毫秒。
从IO上看,GUID表是int的一倍,OGUID是int的120%。
再看聚集索引查找:
set statistics time on
set statistics io on
checkpoint;
dbcc dropcleanbuffers;
select * from [int] where intID = 99999;
select * from [guid] where guidid = 'F0EE26A1-9F55-4D7B-B580-7F7164ECA028';
select * from [oguid] where oguidid = 'D29145E7-957D-DE11-B7EE-001143D7A3BE';
结果如下:
从计划以及统计信息上来看,在10w单位这个层次上,树的高度是一致的,所以在查找上,性能没有差异。
再来看看连表查询:
set statistics time on
set statistics io on
checkpoint;
dbcc dropcleanbuffers;
select * from [int] with(index(0)) inner join int2 on int.intid = int2.intid;
select * from [guid] inner join guid2 on guid.guidid = guid2.guidid;
输出如下:
SQL Server 分析和编译时间:
CPU 时间 = 0 毫秒,占用时间 = 1 毫秒。
SQL Server 执行时间:
CPU 时间 = 0 毫秒,占用时间 = 1 毫秒。
SQL Server 分析和编译时间:
CPU 时间 = 0 毫秒,占用时间 = 64 毫秒。
SQL Server 执行时间:
CPU 时间 = 0 毫秒,占用时间 = 1 毫秒。
SQL Server 执行时间:
CPU 时间 = 0 毫秒,占用时间 = 1 毫秒。
SQL Server 执行时间:
CPU 时间 = 0 毫秒,占用时间 = 61 毫秒。
DBCC 执行完毕。如果 DBCC 输出了错误信息,请与系统管理员联系。
SQL Server 执行时间:
CPU 时间 = 0 毫秒,占用时间 = 2 毫秒。
(1000 行受影响)
表 'Worktable'。扫描计数 0,逻辑读取 0 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。
表 'Int'。扫描计数 1,逻辑读取 411 次,物理读取 1 次,预读 450 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。
表 'int2'。扫描计数 1,逻辑读取 7 次,物理读取 1 次,预读 8 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。
(1 行受影响)
SQL Server 执行时间:
CPU 时间 = 47 毫秒,占用时间 = 1576 毫秒。
(1000 行受影响)
表 'GUID'。扫描计数 1,逻辑读取 823 次,物理读取 2 次,预读 862 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。
表 'guid2'。扫描计数 1,逻辑读取 8 次,物理读取 0 次,预读 5 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。
(1 行受影响)
SQL Server 执行时间:
CPU 时间 = 46 毫秒,占用时间 = 4850 毫秒。
SQL Server 分析和编译时间:
CPU 时间 = 0 毫秒,占用时间 = 1 毫秒。
SQL Server 执行时间:
CPU 时间 = 0 毫秒,占用时间 = 1 毫秒。
如果没有索引提示的情况:
所以在连表查找方面无论是哪种情况性能也是相差不少。
可能还有其他的应用场景我就没有再一一测试了,不过我自己调优数据库经验来看,主要是还是要分应用场景,对于性能只是相差几倍的,没有必要调优,除非不是在一个数量级。另外,要看应用场景的执行频繁度,如果这个sql平均每秒执行1000次,而你节省他每次10个IO,都是很有意义的,比起N长时间才执行一次,你花大力气去调优节省它1wIO,也是毫无意义的。
另外从需求上来说,有些应用场景比如数据迁移,不能让外部猜测下一个ID(比如你的用户ID,不想让别人知道你的网站用户增长速度),都有可能是GUID的应用场景。当然也有可能是有些场景需要用户有一个简而易记的ID,比如订单号,当当的订单号如果是个GUID,那我每次打电话跟他们客服沟通,都需要念半天号码。
总而言之,仅从性能考虑,GUID肯定是不如INT,但是天生我才必有用,总有他适合的场景。