SQL Server表perf比较 - 临时表还是表变量?或者是其他东西?

时间:2010-10-18 16:05:24

标签: sql sql-server performance

在SQL Server中,我试图在给定不同键的插入性能方面对两个不同的表结构进行比较分析。如果我使用表变量进行此测试,或者我应该使用临时表,这是否重要?或者我是否需要解决实际创建表和索引的问题?

具体来说,我目前正在使用以下脚本:

DECLARE @uniqueidentifierTest TABLE
(
    --yes, this is terrible, but I am looking for numbers on how bad this is :)
    tblIndex UNIQUEIDENTIFIER PRIMARY KEY CLUSTERED,
    foo INT,
    blah VARCHAR(100)
)

DECLARE @intTest TABLE
(
    tblindex INT IDENTITY(1,1) PRIMARY KEY CLUSTERED,
    foo INT,
    blah VARCHAR(100)
)

DECLARE @iterations INT = 250000
DECLARE @ctrl INT = 1

DECLARE @guidKey UNIQUEIDENTIFIER
DECLARE @intKey INT

DECLARE @foo INT = 1234
DECLARE @blah VARCHAR(100) = 'asdfjifsdj fds89fsdio23r'

SET NOCOUNT ON

--test uniqueidentifier pk inserts
PRINT 'begin uniqueidentifier insert test at ' + CONVERT(VARCHAR(50), GETDATE(), 109)
WHILE @ctrl < @iterations
BEGIN
    SET @guidKey = NEWID()

    INSERT INTO @uniqueidentifierTest (tblIndex, foo, blah)
        VALUES (@guidKey, @foo, @blah)

    SET @ctrl = @ctrl + 1
END
PRINT 'end uniqueidentifier insert test at ' + CONVERT(VARCHAR(50), GETDATE(), 109)

SET @CTRL = 1

--test int pk inserts
PRINT 'begin int insert test at ' + CONVERT(VARCHAR(50), GETDATE(), 109)
WHILE @ctrl < @iterations
BEGIN
    INSERT INTO @intTest (foo, blah)
        VALUES (@foo, @blah)

    SET @ctrl = @ctrl + 1
END
PRINT 'end int insert test at ' + CONVERT(VARCHAR(50), GETDATE(), 109)

SET NOCOUNT OFF

DECLARE @uniqueidentifierTest TABLE ( --yes, this is terrible, but I am looking for numbers on how bad this is :) tblIndex UNIQUEIDENTIFIER PRIMARY KEY CLUSTERED, foo INT, blah VARCHAR(100) ) DECLARE @intTest TABLE ( tblindex INT IDENTITY(1,1) PRIMARY KEY CLUSTERED, foo INT, blah VARCHAR(100) ) DECLARE @iterations INT = 250000 DECLARE @ctrl INT = 1 DECLARE @guidKey UNIQUEIDENTIFIER DECLARE @intKey INT DECLARE @foo INT = 1234 DECLARE @blah VARCHAR(100) = 'asdfjifsdj fds89fsdio23r' SET NOCOUNT ON --test uniqueidentifier pk inserts PRINT 'begin uniqueidentifier insert test at ' + CONVERT(VARCHAR(50), GETDATE(), 109) WHILE @ctrl < @iterations BEGIN SET @guidKey = NEWID() INSERT INTO @uniqueidentifierTest (tblIndex, foo, blah) VALUES (@guidKey, @foo, @blah) SET @ctrl = @ctrl + 1 END PRINT 'end uniqueidentifier insert test at ' + CONVERT(VARCHAR(50), GETDATE(), 109) SET @CTRL = 1 --test int pk inserts PRINT 'begin int insert test at ' + CONVERT(VARCHAR(50), GETDATE(), 109) WHILE @ctrl < @iterations BEGIN INSERT INTO @intTest (foo, blah) VALUES (@foo, @blah) SET @ctrl = @ctrl + 1 END PRINT 'end int insert test at ' + CONVERT(VARCHAR(50), GETDATE(), 109) SET NOCOUNT OFF

3 个答案:

答案 0 :(得分:3)

如果要比较实际性能,则需要创建表和索引(以及所涉及的所有其他内容)。虽然临时表比表变量更好,但如果您正在寻求性能指标,它们都不能替代实际的永久表结构。

但是,您应该避免使用uniqueidentifier作为主键,或者至少使用newsequentialid()而不是newid()。拥有聚簇索引意味着行实际上将以物理顺序存储 。如果插入的值不按顺序排列,则SQL Server必须重新排列行以将其插入到适当的位置。

答案 1 :(得分:3)

首先,在使用newid()时,永远不会在uniqueidentifier上进行集群,如果必须使用GUID,则会导致碎片,从而导致页面拆分,然后按照这样做

create table #test (id uniqueidentifier primary key defualt newsequentialid())

newsequentialid()不会导致页面拆分

仍然是一个int作为PK仍然更好,因为现在所有非聚集索引和外键都会更小,现在你需要更少的IO才能获得相同数量的行

答案 2 :(得分:0)

我不知道为什么,但我想引用Remus Rusanu [1]:

  

首先,您需要在每个[censored]下重复运行查询并对结果取平均值,丢弃具有最大时间的查询。这将消除缓冲区预热影响:您希望所有运行都在一个热缓存上,没有一个查询加热缓存并支付相应的惩罚。

     

接下来,您需要确保在真实并发场景下进行测量。如果您将在现实生活中进行更新/插入/删除,则必须将它们添加到测试中,因为它们会在各种隔离级别下极大地影响读取。你想要的最后一件事是得出结论'可序列化的读取是最快的,让我们在任何地方使用它们',然后观察系统在生产中融化,因为一切都是序列化的。

     

1)在冷缓存上运行查询不准确。您的生产查询不会在冷缓存上运行,您将优化不切实际的情况并且您不测量查询,您实际上是在测量磁盘读取吞吐量。您还需要在热缓存上测量性能,并跟踪两者(冷运行时间,暖运行时间)。

     

在正常情况下,对于特定数据只运行一次的大型查询(数百万行)的缓存有多相关?    仍然非常相关。即使数据太大以至于它永远不适合内存并且每次运行都必须重新读取表的每一页,仍然存在非叶页面的缓存(即表中的热页,根或近根) ),较窄的非聚集索引的缓存,表元数据的缓存。不要认为你的桌子是ISAM文件

[1]为什么更好的隔离级别意味着更好的SQL Server性能
Why better isolation level means better performance in SQL Server