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

时间:2008-11-06 06:43:44

标签: 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)

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

现在..我担心的问题是我们得到了大量的命中...所以有可能这个词可以从SELECT和INSERT之间的另一个进程中插入...然后会抛出约束错误? (即a Race Condition)。

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

INSERT INTO Words (Word)
SELECT @Word
WHERE NOT EXISTS (SELECT WordID FROM Words WHERE Word = @Word)

基本上,在不存在时插入一个单词。

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

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

我希望有一个简单的插入和'catch'来表示任何错误。

7 个答案:

答案 0 :(得分:28)

您的解决方案:

INSERT INTO Words (Word)
    SELECT @Word
WHERE NOT EXISTS (SELECT WordID FROM Words WHERE Word = @Word)

......几乎和它一样好。您可以将其简化为:

INSERT INTO Words (Word)
    SELECT @Word
WHERE NOT EXISTS (SELECT * FROM Words WHERE Word = @Word)

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

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

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

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

答案 1 :(得分:4)

我认为我找到了一个更好(或至少更快)的答案。 创建一个索引,如:

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]

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

答案 2 :(得分:3)

如果您使用的是MS SQL Server,则可以在表的列上创建一个唯一的索引,该索引必须是唯一的(记录为here):

CREATE UNIQUE [ CLUSTERED | NONCLUSTERED ] INDEX <index_name>
    ON Words ( word [ ASC | DESC ])

根据您的情况指定ClusteredNonClustered。此外,如果您希望对其进行排序(以便更快地进行搜索),请为排序顺序指定ASCDESC

如果您想了解有关索引架构的更多信息,请参阅here

否则,您可以使用UNIQUE CONSTRAINTS,例如记录的here

ALTER TABLE Words
ADD CONSTRAINT UniqueWord
UNIQUE (Word); 

答案 3 :(得分:3)

我有类似的问题,这就是我解决它的方式

insert into Words
( selectWord , Fixword)
SELECT word,'theFixword'
FROM   OldWordsTable
WHERE 
(
    (word LIKE 'junk%') OR
     (word LIKE 'orSomthing') 

)
and word not in 
    (
        SELECT selectWord FROM words WHERE selectWord = word
    ) 

答案 4 :(得分:1)

虽然唯一约束是一种可行的方法,但您也可以将它用于插入逻辑: http://www.sqlteam.com/article/application-locks-or-mutexes-in-sql-server-2005

基本上你没有在下面的桌子上放任何锁,因此不用担心读取 而你的存在检查将会执行。

它是sql代码中的互斥锁。

答案 5 :(得分:0)

我无法谈论MS SQL的细节,但SQL中主键的一点是确保唯一性。因此,根据通用SQL术语的定义,主键是一个或多个对表而言唯一的字段。虽然有不同的方法来强制执行此行为(将旧条目替换为新条目而不是拒绝新条目)如果MS SQL都没有强制执行此行为的机制并且不是拒绝新条目。只需确保将主键设置为Word字段, 即可。

再一次,我不承认这完全来自我对MySQL编程和我的数据库类的了解,所以如果我对MS SQL的复杂性感到抱歉,那就道歉了。

答案 6 :(得分:-3)

declare @Error int

begin transaction
  INSERT INTO Words (Word) values(@word)
  set @Error = @@ERROR
  if @Error <> 0 --if error is raised
  begin
      goto LogError
  end
commit transaction
goto ProcEnd

LogError:
rollback transaction