Как имитировать «массовую» вставку с помощью DataTable в SQL Server - PullRequest
0 голосов
/ 25 сентября 2018

У меня есть хранимая процедура, в которую я отправляю определенный пользователем тип, который является таблицей.Я упростила, чтобы было легче читать.

 CREATE TYPE [dbo].[ProjectTableType] AS TABLE(
     [DbId] [uniqueidentifier] NOT NULL,
     [DbParentId] [uniqueidentifier] NULL,
     [Description] [text] NULL
 )

 CREATE PROCEDURE [dbo].[udsp_ProjectDUI] (@cmd varchar(10), 
      @tblProjects ProjectTableType READONLY) AS BEGIN
      DECLARE @myNewPKTable TABLE (myNewPK uniqueidentifier)

      IF(LOWER(@cmd) = 'insert')
      BEGIN
          INSERT INTO 
            dbo.Project 
            (
                DbId,
                DbParentId,
                Description)
        OUTPUT INSERTED.DbId INTO @myNewPKTable
        SELECT NEWID(),
                DbParentId,
                Description
        FROM @tblProjects;

        SELECT * FROM dbo.Project WHERE dbid IN (SELECT myNewPK FROM @myNewPKTable);
  END

Это для DLL, которую будут использовать другие приложения, поэтому мы не несем ответственности за проверку.Я хочу имитировать BULK INSERT, где, если одна строка не может быть вставлена, но другие строки в порядке, правильные будут вставлены.Есть ли способ сделать это?Я хочу сделать это для ОБНОВЛЕНИЯ, а также, если в случае одного сбоя хранимая процедура будет продолжать пытаться обновить другие.

Единственный вариант, который я могу придумать, - это делать только по одному за раз (либо цикл в коде, где хранимый процесс вызывается несколько раз, либо цикл в хранимой процедуре), но мне было интересно, чтоснижение производительности может быть для этого или если есть лучшее решение.

1 Ответ

0 голосов
/ 25 сентября 2018

Не уверен, на каких ошибках вы хотите продолжить, но если вы не столкнетесь с неожиданными ошибками, я бы постарался пока не переходить в RBAR.

ПроверкаЯвные нарушения

Основное, что я думаю, это колебания ПК, которых вы можете избежать, просто проверив существование перед вставкой (и обновлением).Если есть другие условия сбоя бизнес-логики, вы также можете проверить их здесь.

insert into dbo.Project 
(
    DbId,
    DbParentId,
    Description
)
output insert.DbId 
into @myNewPKTable (DbId)
select
    DbId = newid(),
    DbParentId = s.DbParentId,
    Description = s.Description
from @tblProjects s -- source
-- LOJ null check makes sure we don't violate PK
-- NOTE: I'm pretending this is an alternate key of the table. 
left outer join dbo.Project t -- target
    on s.dbParentId = t.dbParentId 
where t.dbParentId is null

Если это вообще возможно, я бы попытался придерживаться пакетного обновления и использовать предикаты соединения, чтобы исключить возможностьбольшинство ошибок, которые вы ожидаете увидеть.Переход на обработку RBAR, потому что вы беспокоитесь о том, что «может» получить сбой при отключении системы, вероятно, пустая трата времени.Затем, если вы столкнулись с действительно неприятной ошибкой, которую вы не можете восстановить, законно проваливайте пакет.

RBAR

В качестве альтернативы, если вам абсолютно необходим построчный-крупность гранул успехов или неудач, вы можете попробовать / перехватить все операторы и заставить блок catch ничего не делать (или регистрировать что-либо).

declare 
    @DBParentId int, 
    @Description nvarchar(1000),
    @Ident int

declare c cursor local fast_forward for
    select
        DbParentId = s.DbParentId,
        Description = s.Description
    from @tblProjects
open c

fetch next from c into @DBParentId, @Description

while @@fetch_status = 0
begin

    begin try

        insert into dbo.Project 
        (
            DbId,
            DbParentId,
            Description
        )
        output insert.DbId 
        into @myNewPKTable (DbId)
        select
            newid(),
            @DBParentId,
            @Description

    end try
    begin catch
        -- log something if you want
        print error_message()
    end catch

    fetch next from c into @DBParentId, @Description

end

Hybrid Возможно, вы сможетеумничать и скрещивать вещи.Один из вариантов может заключаться в том, чтобы сделать процедуру вставки с веб-интерфейсом фактически вставленной в облегченную таблицу с минимальными ключами / ограничениями (например, в очередь).Затем каждую минуту или около того, чтобы задание агента выполнялось через зарегистрированные вызовы, и работайте с ними в пакете.Здесь принципиально не меняется ни один из шаблонов, но это делает обработку асинхронной, поэтому вызывающему не нужно ждать, и, объединяя запросы в группы, вы можете сэкономить вычислительную мощность, совмещая то, что лучше всего работает с SQL;операции на основе набора.

Другой вариант может заключаться в том, чтобы выполнять максимально возможную обработку на основе набора (используя проверки для предотвращения нарушения бизнес-правил или ограничений).Если что-то не получится, вы можете запустить процесс RBAR для оставшихся строк.Однако если все удастся, этот процесс RBAR никогда не будет запущен.

Заключение Несколько способов сделать это.Я бы постарался использовать как можно больше операций на основе множеств, если у вас нет действительно веской причины для необходимости построчной детализации.

  • Вы можете избежать большинства ошибок, просто создавВаш insert/update оператор правильно.

  • Если вам нужно, вы можете использовать try/catch с «пустым» блоком catch, чтобы сбои не останавливали общую обработку

  • В зависимости от случайных шансов и целей вашей конкретной ситуации, вы можете захотеть или вам нужно объединить эти два подхода

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...