【问题标题】:SQL Server table perf comparison -- temp tables, or table variables? Or something else?SQL Server 表性能比较——临时表还是表变量?或者是其他东西?
【发布时间】:2010-10-19 14:24:38
【问题描述】:

在 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

【问题讨论】:

    标签: sql sql-server performance


    【解决方案1】:

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

    尽管如此,您应该避免使用uniqueidentifier 作为主键,或者至少使用newsequentialid() 而不是newid()。拥有聚集索引意味着这些行实际上将按物理顺序存储。如果插入的值乱序,SQL Server 将不得不重新排列行以便将其插入到正确的位置。

    【讨论】:

    • 为什么临时表不一样?编辑:我可以想到记录行为。
    • @Martin:在所有条件相同的情况下,它会,但是要清楚地了解表将如何实际执行意味着您需要所有相关的性能影响数据库对象(索引、统计信息、约束、触发器等)。
    • 一个表变量之所以可怕的一个原因是您无法创建索引等。临时表更好,但实际上对于测试实际表,您应该将实际表设置为他们将拥有的约束和索引。
    【解决方案2】:

    首先,当使用newid() 时,永远不要聚集在唯一标识符上,它会导致碎片,从而导致页面拆分,如果您必须使用 GUID,那么就这样做

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

    newsequentialid() 不会造成分页

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

    【讨论】:

    • 是的先生,这就是我正在寻找确定性能指标的野兽。
    【解决方案3】:

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

    首先,您需要在每个 [censored] 下重复运行查询并平均结果,丢弃时间最长的那个。这将消除缓冲区预热的影响:您希望所有运行都在一个热缓存上,而不是让一个查询预热缓存并支付惩罚。

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

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

    对于在正常情况下只针对特定数据运行一次的大型查询(数百万行),缓存的相关性如何? 还是很相关的。即使数据太大以至于它永远无法放入内存并且每次运行都必须重新读取表的每一页,仍然存在非叶页的缓存(即表中的热页,根或接近根),较窄的非聚集索引的缓存,表元数据的缓存。不要将您的餐桌视为 ISAM 文件

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

    【讨论】:

      猜你喜欢
      • 2015-10-05
      • 2018-11-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-11-06
      • 1970-01-01
      • 1970-01-01
      • 2018-01-15
      相关资源
      最近更新 更多