Альтернативы для варианта использования курсора в SQL Server - PullRequest
0 голосов
/ 24 марта 2019

У меня есть две таблицы:

  • tb1 (ID, AccountId, updated_at, ..., 30+ столбцов)
  • tb2 (ID, AccountId, updated_at, ..., 30+ столбцов)

Я пытаюсь обновить несколько значений столбцов в tb1, если в tb2 есть такая же строка, иначе мне нужно вставить все новые значения из tb2, еслистрок нет в таблице tb1.

Я использовал курсор, но он работает очень медленно.

Мой код:

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 есть много строк (около 2M)

Как я могу изменить это для достижения более высокой производительности?

Ответы [ 2 ]

1 голос
/ 24 марта 2019

Может быть, это может работать быстрее:

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)
0 голосов
/ 24 марта 2019

Операции установки выполняются быстрее, чем операции курсора.Следующий sql может помочь вам улучшить производительность.В этом случае мы сначала обновляем таблицу tb1, затем вставляем строки, которых там еще нет, из таблицы tb2 в таблицу tb1.

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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...