SQL Server - 如何插入记录并确保它是唯一的

Pur*_*ome 22 sql-server insert unique

我试图找出将记录插入单个表的最佳方法,但前提是该项目尚不存在.在这种情况下,KEY是NVARCHAR(400)字段.对于此示例,我们假设它是牛津英语词典中单词的名称/在此处插入您的fav词典.另外,我猜我需要将Word字段作为主键.(该表也将具有唯一标识符PK).

所以...我可能会得到这些我需要添加到表格中的单词...

例如.

  • 酒吧
  • PewPew
  • 等等...

所以传统上,我会尝试以下(伪代码)

SELECT WordID FROM Words WHERE Word = @Word
IF WordID IS NULL OR WordID <= 0
    INSERT INTO Words VALUES (@Word)
Run Code Online (Sandbox Code Playgroud)

即.如果该单词不存在,则插入它.

现在..我担心的问题是我们得到了大量的命中..所以有可能这个词可以从SELECT和INSERT之间的另一个进程插入...这会引发一个约束错误?(即比赛条件).

然后我想我可能会做以下事情......

INSERT INTO Words (Word)
SELECT @Word
WHERE NOT EXISTS (SELECT WordID FROM Words WHERE Word = @Word)
Run Code Online (Sandbox Code Playgroud)

基本上,当它不存在时插入一个单词.

除了错误的语法之外,我不确定这是坏还是好因为它如何锁定表(如果它确实)并且不是表上的表现,它会获得大量读取和大量写入.

那么 - 你的Sql大师怎么想/做什么?

我希望有一个简单的插入和"捕获",任何错误抛出.

Rog*_*mbe 28

你的解决方案

INSERT INTO Words (Word)
    SELECT @Word
WHERE NOT EXISTS (SELECT WordID FROM Words WHERE Word = @Word)
Run Code Online (Sandbox Code Playgroud)

......几乎和它一样好.你可以简化它:

INSERT INTO Words (Word)
    SELECT @Word
WHERE NOT EXISTS (SELECT * FROM Words WHERE Word = @Word)
Run Code Online (Sandbox Code Playgroud)

...因为EXISTS实际上不需要返回任何记录,因此查询优化器不会费心查看您要求的字段.

但是,正如您所提到的,这不是特别高效,因为它会在INSERT期间锁定整个表.除此之外,如果你添加一个唯一索引(它并不需要是主键)到Word,然后它会只需要锁定相关页面.

您最好的选择是模拟预期的负载并使用SQL Server Profiler查看性能.与任何其他领域一样,过早优化是一件坏事.定义可接受的性能指标,然后在执行任何其他操作之前进

如果仍然没有给你足够的性能,那么数据仓库领域的一系列技术可能有所帮助.


Web*_*sel 5

我想我找到了一个更好的(或至少更快的)答案。创建一个像这样的索引:

CREATE UNIQUE NONCLUSTERED INDEX [IndexTableUniqueRows] ON [dbo].[table] 
(
    [Col1] ASC,
    [Col2] ASC,

)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = ON, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
Run Code Online (Sandbox Code Playgroud)

包括所有定义唯一性的列。重要的部分是IGNORE_DUP_KEY = ON。这会将非唯一插入内容转换为警告。SSIS会忽略这些警告,您仍然可以使用fastload。