在临时表上创建主键 - 何时?

时间:2009-06-22 21:09:59

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

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

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将构成我的主键。

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

虽然,除此之外,我的问题仍然存在,假设两者都会成功会更快?

P.S。如果这是重复,我很抱歉。它基本就足够了,但我找不到类似的东西。

9 个答案:

答案 0 :(得分:15)

取决于很多。

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

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

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

然而,正如其他人所指出的那样,索引的创建可能会失败。此外,临时表不是孤立存在的。据推测,有一个最佳索引可以从下一步读取数据。该索引需要就位或创建。 这个是你必须在这里权衡速度以获得可靠性(首先应用PK和任何其他约束)和以后的速度(如果你有一个,至少要有聚集索引) )。

答案 1 :(得分:6)

如果数据库的恢复模型设置为简单或批量记录,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有很好的建议:在之前或之后。

答案 2 :(得分:3)

您也可以在插入之前创建主键 - 如果主键位于标识列上,那么插入将按顺序完成,并且没有区别。

答案 3 :(得分:2)

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

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

答案 4 :(得分:1)

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

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

但也许Sql Server有一种非常聪明的方法来检查唯一性。所以,如果你想确定,请测量它!

答案 5 :(得分:1)

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

答案 6 :(得分:0)

我认为这不会对你的案件产生任何重大影响:

  • 要么每次支付一点点罚款,每次插入
  • 或者在完成所有插入后,您将支付更大的罚款,但只需支付一次

在插入开始之前预先创建它时,如果PK值不是系统创建的,那么可能可能会在插入数据时捕获PK违规。

但除此之外 - 没有什么大不同,真的。

马克

答案 7 :(得分:0)

我不打算回答这个问题,因为我对这方面的知识并不是100%自信。但是,因为它看起来不像你得到了很多回应......

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

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

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

答案 8 :(得分:0)

当您在创建表格时添加PK时 - 插入检查为O(Tn)(其中Tn为"第n个三角形数字",即1 + 2 + 3 ... + n)因为当你插入第x行时,它会根据之前插入的" x - 1"进行检查。行

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

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

P.S。示例:如果您插入5行,则1 + 2 + 3 + 4 + 5 = 15操作与5^2 = 25操作