【问题标题】:Creating a Primary Key on a temp table - When?在临时表上创建主键 - 何时?
【发布时间】:2010-11-04 23:46:39
【问题描述】:

我有一个处理大量数据的存储过程。我将该数据插入到临时表中。事件的整体流程类似于

CREATE #TempTable (
    Col1    NUMERIC(18,0) NOT NULL,    --This will not be an identity column.
    ,Col2   INT NOT NULL,
    ,Col3   BIGINT,

    ,Col4   VARCHAR(25) NOT NULL,
    --Etc...

    --
    --Create primary key here?
)


INSERT INTO #TempTable
SELECT ...
FROM MyTable
WHERE ...

INSERT INTO #TempTable
SELECT ...
FROM MyTable2
WHERE ...

--
-- ...or create primary key here?

我的问题是在我的#TempTable 表上创建主键的最佳时间是什么时候?我认为我应该在插入所有数据后创建主键约束/索引,因为索引在创建主键信息时需要重新组织。但我意识到我强调的假设可能是错误的......

如果相关,我使用的数据类型是真实的。在#TempTable 表中,Col1Col4 将构成我的主键。

更新:就我而言,我正在复制源表的主键。我知道构成我的主键的字段将始终是唯一的。如果我在最后添加主键,我不担心更改表失败。

不过,除此之外,我的问题仍然是假设两者都会成功,哪个更快

【问题讨论】:

    标签: sql-server indexing primary-key temp-tables


    【解决方案1】:

    非常依赖

    如果你在加载后使主键索引聚集,整个表将被重写,因为聚集索引不是真正的索引,它是数据的逻辑顺序。您的插入执行计划将取决于计划确定时的索引,如果聚集索引到位,它将在插入之前排序。您通常会在执行计划中看到这一点。

    如果您使主键成为一个简单的约束,它将是一个常规(非聚集)索引,并且该表将简单地按照优化器确定的任何顺序填充并更新索引。

    我认为(加载临时表的过程中)整体最快的性能通常是将数据写入堆,然后应用(非聚集)索引。

    但是,正如其他人所指出的,索引的创建可能会失败。此外,临时表并不是孤立存在的。大概有一个最佳索引可以从中读取数据以进行下一步。该索引将需要到位或创建。 是您必须在此处权衡速度以换取可靠性(首先应用 PK 和任何其他约束)和稍后的速度(如果要拥有聚集索引,则至少要有一个聚集索引) )。

    【讨论】:

    • 有趣。谢谢你。有帮助。你能举一些例子吗?
    • @Cade,对于聚集索引,您的意思是磁盘上的物理顺序,而不是逻辑顺序(表没有逻辑顺序)。
    • 不,磁盘上的物理顺序可以是任何东西。聚集索引只是存储在 btree 索引而不是堆中的叶子中的数据。 SQL Server 和磁盘上仍然可能存在碎片。
    • 我明白你的意思。得分。
    【解决方案2】:

    如果您的数据库的恢复模式设置为简单或批量记录,SELECT ... INTO ... UNION ALL 可能是最快的解决方案。 SELECT .. INTO 是一个批量操作,批量操作的日志记录最少。

    例如:

    -- first, create the table
    SELECT ...
    INTO #TempTable
    FROM MyTable
    WHERE ...
    UNION ALL
    SELECT ...
    FROM MyTable2
    WHERE ...
    
    -- now, add a non-clustered primary key:
    -- this will *not* recreate the table in the background
    -- it will only create a separate index
    -- the table will remain stored as a heap
    ALTER TABLE #TempTable ADD PRIMARY KEY NONCLUSTERED (NonNullableKeyField)
    
    -- alternatively:
    -- this *will* recreate the table in the background
    -- and reorder the rows according to the primary key
    -- CLUSTERED key word is optional, primary keys are clustered by default
    ALTER TABLE #TempTable ADD PRIMARY KEY CLUSTERED (NonNullableKeyField) 
    

    否则,Cade Roux 有很好的建议:之前或之后。

    【讨论】:

      【解决方案3】:

      您也可以在插入之前创建主键 - 如果主键位于标识列上,那么无论如何插入都会按顺序完成,不会有任何区别。

      【讨论】:

      • 我不会使用身份。你在我更新我的问题时发布了这个。我的主键将由 NUMERIC(18,0) 和 VARCHAR(25) 字段组成。
      • 主键默认是集群的。这将根据 PK 值对您的数据进行顺序排序。我同意这个答案,它应该在你插入之前发生。另请注意:如果您添加额外的非聚集索引。之后创建聚簇 PK 会导致 SQL Server 重建非聚簇索引。
      • @Justin 如何在插入之前创建主键。你能用一个小的示例查询来完成你的建议吗?
      【解决方案4】:

      比性能考虑更重要的是,如果您不是绝对、100% 确定您将有唯一值插入到表中,请先创建主键。否则主键创建失败。

      这可以防止您插入重复/错误的数据。

      【讨论】:

      • 这对我来说不是问题。我知道这对某些人来说可能是问题,但对我来说根本不是问题。
      • 我认为这是有道理的,因为它更清楚地展示了您在逻辑上试图做的事情,并让引擎在过去是安全的假设时为您提供帮助(即确定不会出现重复数据)在插入后的表中)不再安全(例如,由于数据库不同部分的某些更改)。
      【解决方案5】:

      如果您在创建表时添加主键,第一个插入将是免费的(不需要检查)。第二个插入只需查看它是否与第一个不同。第三个插入必须检查两行,依此类推。检查将是索引查找,因为存在唯一约束。

      如果您在所有插入之后添加主键,则每一行都必须与其他每一行匹配。所以我的猜测是尽早添加主键更便宜。

      但也许 Sql Server 有一个非常聪明的方法来检查唯一性。因此,如果您想确定,请测量它!

      【讨论】:

      • SQL Server 确实有一种非常聪明的方法来检查唯一性。
      【解决方案6】:

      我想知道我是否可以改进一个非常“昂贵”的存储过程,需要在跨表的每个插入时进行一堆检查,然后遇到了这个答案。在 Sproc 中,打开了几个临时表并相互引用。我将主键添加到 CREATE TABLE 语句中(即使我的选择使用 WHERE NOT EXISTS 语句来插入数据并确保唯一性)并且我的执行时间被大大缩短了。我强烈推荐使用主键。即使您认为不需要它,也请始终至少尝试一下。

      【讨论】:

      • 问题的上下文不是关于是否创建主键,而是在哪个时间点更有效 - 数据前填充或数据后填充。这个问题之前的结论是键/索引有助于缩短执行时间。
      【解决方案7】:

      我认为这对您的情况没有任何重大影响:

      • 要么你每次支付一点点罚金,每​​次插入
      • 否则您将在所有插入完成后支付更大的罚款,但只有一次

      当您在插入开始之前预先创建它时,如果 PK 值不是系统创建的,您可能可能会在插入数据时发现 PK 违规。

      但除此之外 - 真的没有太大区别。

      马克

      【讨论】:

      • 范围分割和日志记录之类的?这不需要考虑?
      【解决方案8】:

      我不打算回答这个问题,因为我对我对此的了解并不是 100% 有信心。但是因为看起来你没有得到太多回应......

      我的理解是 PK 是一个唯一索引,当您插入每条记录时,您的索引会更新和优化。所以……如果先添加数据,再创建索引,索引只优化一次。

      所以,如果您确信您的数据是干净的(没有重复的 PK 数据),那么我会说插入,然后添加 PK。

      但是如果你的数据可能有重复的PK数据,我会说先创建PK,所以它会尽快炸毁。

      【讨论】:

      • 感谢您的回复。事实上,我确信我不会遇到重复问题...
      【解决方案9】:

      当您在创建表时添加 PK - 插入检查是 O(Tn)(其中 Tn 是“第 n 个三角形数”,即 1 + 2 + 3 ... + n)因为当您插入第 x 行时,它会被检查之前插入“x - 1”行

      当您插入所有值之后添加 PK - 检查器是 O(n^2),因为当您插入第 x 行时,它会针对所有 n 现有行进行检查。

      第一个显然更快,因为O(Tn) 小于O(n^2)

      附:示例:如果插入 5 行,则为 1 + 2 + 3 + 4 + 5 = 15 操作 vs 5^2 = 25 操作

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-03-06
        • 1970-01-01
        相关资源
        最近更新 更多