22

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

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

例如。

  • 酒吧
  • 皮尤
  • ETC...

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

SELECT WordID FROM Words WHERE Word = @Word
IF WordID IS NULL OR WordID <= 0
    INSERT INTO Words VALUES (@Word)

IE。如果该词不存在,则插入它。

现在..我担心的问题是我们得到了很多点击..那么这个词是否有可能从另一个进程插入到 SELECT 和 INSERT 之间.. 然后会抛出一个约束错误? (即竞争条件)。

然后我认为我可能能够做到以下几点......

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

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

抛开语法错误不谈,我不确定这是好是坏,因为它如何锁定表(如果确实如此),并且在表上的性能不高,以至于它获得大量读取和大量写入。

那么 - 你的 Sql 大师认为/做什么?

我希望有一个简单的插入并“捕获”任何抛出的错误。

4

7 回答 7

31

您的解决方案:

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 查看性能。与任何其他领域一样,过早优化是一件坏事。定义可接受的性能指标,然后在做任何其他事情之前进行测量。

如果这仍然不能为您提供足够的性能,那么数据仓库领域的许多技术可以提供帮助。

于 2008-11-06T07:31:11.670 回答
6

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

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。

于 2011-10-20T16:05:52.010 回答
3

如果您使用的是 MS SQL Server,则可以在需要唯一的表列上创建唯一索引(在此处记录):

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

指定ClusteredNonClustered,具体取决于您的情况。此外,如果您希望对其进行排序(以实现更快的搜索),请指定ASCDESC作为排序顺序。

如果您想了解有关索引架构的更多信息,请参见此处。

否则,您可以使用此处UNIQUE CONSTRAINTS记录的内容:

ALTER TABLE Words
ADD CONSTRAINT UniqueWord
UNIQUE (Word); 
于 2008-11-06T07:33:19.993 回答
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
    ) 
于 2009-05-27T11:11:18.077 回答
1

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

基本上,您不会在下表上放置任何锁,因此不必担心读取,而您的存在性检查将可以正常执行。

它是 sql 代码中的互斥锁。

于 2008-11-06T10:46:48.200 回答
0

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

不过,我再次声明这一切都来自我从 MySQL 编程和我的数据库课程中获得的知识,所以如果我对 MS SQL 的复杂性不感兴趣,我深表歉意。

于 2008-11-06T08:29:08.337 回答
-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
于 2008-11-06T11:02:04.380 回答