主键错误Vs select命令

时间:2011-04-13 07:16:52

标签: sql sql-server-2005 stored-procedures query-optimization

我正在创建一个名为URL Counter的应用程序。 我创建了一个表来存储网址及其数量。

CREATE TABLE [dbo].[tblurlcounter](
    [id] [bigint] IDENTITY(1,1) NOT NULL,
    [type] [varchar](500) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
    [count] [bigint] NULL,
 CONSTRAINT [PK_tblurlcounter] PRIMARY KEY CLUSTERED 
(
    [id] ASC
)WITH (PAD_INDEX  = OFF, IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]

我创建了一个存储过程来在表中插入/更新url。 表示当使用存储过程将值“URL”插入该表时,我检查它是否存在然后更新其计数,如果没有,则将其插入到count = 1的表中。

我的存储过程就像:

declare @count int

select @count= [count] from tblurlcounter where [type] = @type
if @count > 0
begin
update tblurlcounter set [count]=@count + 1 where [type] = @type
select @count + 1

end
else 
begin
INSERT INTO [dbcounter].[dbo].[tblurlcounter]
           ([type]
           ,[count])
     VALUES
           (@type
           ,1)
end

此应用程序将在一分钟内获得大约80,000到100,000次点击。所以我希望我的存储过程应该以良好的速度执行操作。我的意思是我的解决方案应该优化。

有人建议我在我的表中更改并创建其名为“type”(我用来存储url)的字段作为主键,在存储过程中我应该首先尝试插入记录,如果它抛出错误然后在下一行检查错误并执行更新操作。

所以我很困惑哪一个会更快,主键错误apporach或我应该选择查询和基于select的结果我应该执行插入/更新操作

现在我需要专家建议,哪种方法是正确的,如果有其他好方法可用,请建议我。

感谢

4 个答案:

答案 0 :(得分:2)

您可以尝试进行更新,如果不存在,则不会更新任何行,您可以使用@@rowcount进行检查。如果没有,则可以添加它,否则值已经增加。您不需要@count变量,因此您必须锁定该行,以便在您分配之后但在更新表之前没有任何内容可以更改该值。

update tblurlcounter set [count] = [count] + 1 where [type] = @type

if @@rowcount = 0 
begin
  insert into tblurlcounter 
  ([type],[count])
  values
  (@type, 1)
end

答案 1 :(得分:2)

当您执行多个语句时,您的方法将无法正常工作。即,在这一行发生之间:

select @count = [count] from tblurlcounter where [type] = @type

并且您的INSERT或UPDATE实际执行,单独执行存储过程也可能会添加一行,因此您最终可能会同时发生两个INSERTS。

相反,试试这个:

INSERT INTO [dbcounter].[dbo].[tblurlcounter]
           ([type]
           ,[count])
     VALUES
           (@type
           ,0)
WHERE NOT EXISTS(select 1 from tblurlcounter where [type] = @type)

UPDATE tblurlcounter SET [count]=[count] + 1 where [type] = @type

如果已经存在匹配的行,则将添加新行,将INSERT与存在性检查相结合。在知道已经存在要更新的行的情况下,可以安全地运行update语句。

您还需要在“类型”列上添加索引。

答案 2 :(得分:2)

对于那个负载,你需要有点聪明。我之前发过这个

基本上,不要先测试:尝试INSERT。如果失败,请运行更新

https://stackoverflow.com/search?q=user%3A27535+JFDI

答案 3 :(得分:-1)

本文非常好地解释了如果不存在插入方法,if exists update vs update。

显然,由于表锁,选择它以检查它是否存在的成本更低。这样我们就可以避免使用更新,这会锁定比选择更多的数据。

http://weblogs.sqlteam.com/mladenp/archive/2007/07/30/60273.aspx

你可以使用:

如果存在(从tblurlcounter中选择*,其中[type] = @type)