Sql server SQL Server中游标用例的备选方案
我有两张桌子: tb1 ID、AccountId、更新时间,…,30多列 tb2 ID、AccountId、更新时间,…,30多列 如果tb2中有相同的行,我尝试更新tb1中的几个列值,否则如果表tb1中没有行,我需要插入tb2中的所有新值 我用过光标,但它运行得很慢 我的代码:Sql server SQL Server中游标用例的备选方案,sql-server,join,cursor,Sql Server,Join,Cursor,我有两张桌子: tb1 ID、AccountId、更新时间,…,30多列 tb2 ID、AccountId、更新时间,…,30多列 如果tb2中有相同的行,我尝试更新tb1中的几个列值,否则如果表tb1中没有行,我需要插入tb2中的所有新值 我用过光标,但它运行得很慢 我的代码: DECLARE @accountId INT, @id INT, @title NVARCHAR(1000), @num_questions INT, @type NVARCHAR(1
DECLARE @accountId INT, @id INT,
@title NVARCHAR(1000), @num_questions INT,
@type NVARCHAR(1000), @starts_at NVARCHAR(1000),
@finishes_at NVARCHAR(1000), @published_at NVARCHAR(1000),
@summary NVARCHAR(2000), @updated_at NVARCHAR(1000)
-- Data from tb2
DECLARE quizRecSet CURSOR FOR
SELECT
AccountId, ID, title, num_questions, type,
starts_at, finishes_at, published_at, summary, updated_at
FROM
tb2
WHERE
accountId = 1
ORDER BY
updated_at DESC
OPEN quizRecSet
FETCH NEXT FROM quizRecSet INTO @accountId, @id, @title, @num_questions, @type,
@starts_at, @finishes_at, @published_at, @summary, @updated_at
WHILE (@@FETCH_STATUS = 0)
BEGIN
IF ((SELECT COUNT(*) FROM tb1(nolock)
WHERE ID = @ID AND accountId = @accountId) = 0)
BEGIN
INSERT INTO tb1
VALUES (@accountId, @id, @title, @num_questions, @type,
@starts_at, @finishes_at, @published_at, @summary, @updated_at)
END
ELSE
BEGIN
UPDATE tb1
SET title = @title, num_questions = @num_questions,
type = @type, published_at = @published_at,
summary = @summary, updated_at = @updated_at
WHERE ID = @ID AND AccountId = @accountId
END
FETCH NEXT FROM quizRecSet INTO @accountId, @id, @title, @num_questions, @type,
@starts_at, @finishes_at, @published_at, @summary, @updated_at
END
CLOSE quizRecSet
DEALLOCATE quizRecSet
上面的代码运行非常慢,因为tb1和tb2中都有很多行,大约2米
如何修改此选项以实现更快的性能?也许此选项可以运行得更快:
insert into tb1 (accountId, ID, title, num_questions, type,
starts_at, finishes_at, published_at, summary, updated_at)
select AccountId, ID, title, num_questions, type,
starts_at, finishes_at, published_at, summary, updated_at
from tb2
where accountId = 1 -- from the previous cursor sample
and not exists
(select 1 from tb1 where ID=tb2.ID and accountId = tb2.accountId)
update tb1 set
title = tb2.title, num_questions = tb2.num_questions,
type=tb2.type, published_at = tb2.published_at,
summary = tb2.summary, updated_at = tb2.updated_at
from tb1
join tb2 on (tb1.ID = tb2.ID and tb1.accountId = tb2.accountId)
where tb1.accountId = 1 -- from the previous cursor sample
and not (tb1.title=tb2.title and tb1.num_questions=tb2.num_questions
and tb1.type=tb2.type and tb1.published_at=tb2.published_at
and tb1.summary=tb2.summary and tb1.updated_at=tb2.updated_at)
设置操作比光标操作快。以下sql可能会帮助您提高性能。在本例中,我们首先更新表tb1,然后将尚未存在的行从表tb2插入表tb1 使用merge语句--如果您的SQL Server版本支持它,即2008+。
UPDATE tb1 SET
title = t2.title,
num_questions = t2.num_questions,
type = t2.type,
published_at = t2.published_at,
summary = t2.summary,
updated_at = t2.updated_at
FROM tb1 AS t1
JOIN tb2 AS t2 ON (t1.ID = t2.ID AND t1.accountId = t2.accountId)
WHERE t1.accountId = 1
INSERT INTO tb1 (
t2.AccountId, t2.ID, t2.title, t2.num_questions, t2.type,
t2.starts_at, t2.finishes_at, t2.published_at, t2.summary, t2.updated_at)
SELECT
t2.AccountId, t2.ID, t2.title, t2.num_questions, t2.type,
t2.starts_at, t2.finishes_at, t2.published_at, t2.summary, t2.updated_at
FROM (
SELECT
AccountId, ID, title, num_questions, type,
starts_at, finishes_at, published_at, summary, updated_at
FROM tb2
EXCEPT
SELECT
t2.AccountId, t2.ID, t2.title, t2.num_questions, t2.type,
t2.starts_at, t2.finishes_at, t2.published_at, t2.summary, t2.updated_at
FROM tb2 AS t2
JOIN tb1 AS t1 ON (t1.ID = t2.ID AND t1.accountId = t2.accountId)
WHERE t2.accountId = 1
) AS TempTable