我有一个处理大量数据的存储过程。我将数据插入到临时表中。事件的整体流程类似于
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
表中,Col1
和Col4
将构成我的主键。
更新:就我而言,我正在复制源表的主键。我知道构成我的主键的字段将始终是唯一的。如果我在最后添加主键,我不关心失败的alter table。
虽然,除此之外,我的问题仍然存在,假设两者都会成功会更快?
P.S。如果这是重复,我很抱歉。它基本就足够了,但我找不到类似的东西。
答案 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
操作