我有一个带有主键(int)和唯一值(nvarchar(255))的两列表
当我向此表插入一个值时,我可以使用Scope_identity()返回刚刚插入的值的主键。但是,如果该值已经存在,我必须执行另外的选择以返回主键以进行后续操作(将该主键插入第二个表)
我认为必须有一个更好的方法来做到这一点 - 我考虑使用覆盖索引但是表只有两列,我在覆盖索引上阅读的大部分内容表明它们只能帮助表格明显更大比索引。
有没有更快的方法呢?覆盖的索引是否会更快,即使它与表的大小相同?
答案 0 :(得分:1)
构建索引不会获得任何好处,因为您已经将值列创建为唯一(在后台构建索引)。实际上,全表扫描与您的方案中的索引扫描没有什么不同。
我假设你想要一种insert-if-not-exists -sts行为。没有办法绕过第二个选择
if not exists (select ID from where name = @...)
insert into ...
select SCOPE_IDENTITY()
else
(select ID from where name = @...)
如果该值恰好存在,则查询通常会被缓存,因此第二个ID select的性能不会受到影响。
答案 1 :(得分:0)
为第二个条目创建唯一索引,然后:
if not exists (select null from ...)
insert into ...
else
select x from ...
你无法摆脱索引,而且开销不是很大 - SQL Server支持最多900字节的索引列,并且没有区别对待。
模型的需求比任何感知到的性能问题更重要,象征字符串(这是你正在做的)是减少数据库大小的常用方法,这间接(通常)意味着更好的性能。
- 编辑 -
安抚蒂莫西:
declare @x int = select x from ...
if (@x is not null)
return x
else
...
答案 2 :(得分:0)
[Update statment here]
IF (@@ROWCOUNT = 0)
BEGIN
[Insert statment here]
SELECT Scope_Identity()
END
ELSE
BEGIN
[SELECT id statment here]
END
我不了解性能,但没有太大的开销
答案 3 :(得分:0)
正如已经提到的,这实际上不应该是一个缓慢的操作,特别是如果你索引两列。但是,如果您决定减少此操作的费用,那么我认为没有理由不能完全删除表,只是直接使用唯一值而不是在此表中查找它。像这样的1-1映射(理论上)是多余的。我在理论上说,因为使用nvarchar而不是int可能会对性能产生影响。
答案 4 :(得分:0)
我会发布这个答案,因为其他人似乎都说你必须在记录存在的情况下查询表格两次 ...这不是真的。
步骤1)在另一列上创建唯一索引:
我建议将其作为索引:
- 我们包含“ID”列,以便在“WHERE”子句完成后SQL不必查看远。
CREATE INDEX MyLilIndex ON dbo.MyTable (Column2) INCLUDE (ID)
步骤2)
DECLARE @TheID INT
SELECT @TheID = ID from MyTable WHERE Column2 = 'blah blah'
IF (@TheID IS NOT NULL)
BEGIN
-- See, you don't have to query the table twice!
SELECT @TheID AS TheIDYouWanted
END
ELSE
INSERT...
SELECT SCOPE_IDENTITY() AS TheIDYouWanted
答案 5 :(得分:0)
您可以使用OUTPUT clause在同一语句中返回值。这是一个例子。
DDL:
CREATE TABLE ##t (
id int PRIMARY KEY IDENTITY(1,1),
val varchar(255) NOT NULL
)
GO
-- no need for INCLUDE as PK column is always included in the index
CREATE UNIQUE INDEX AK_t_val ON ##t (val)
DML:
DECLARE @id int, @val varchar(255)
SET @val = 'test' -- or whatever you need here
SELECT @id = id FROM ##t WHERE val = @val
IF (@id IS NULL)
BEGIN
DECLARE @new TABLE (id int)
INSERT INTO ##t (val)
OUTPUT inserted.id INTO @new -- put new ID into table variable immediately
VALUES (@val)
SELECT @id = id FROM @new
END
PRINT @id