Динамический SQL для выполнения большого количества строк из таблицы - PullRequest
0 голосов
/ 04 июня 2018

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

Я нашел метод объединения для добавления всех строк друг к другу, чтобы не быть эффективным для этого, особенно когда число строк, выполненных ввремя больше, чем ~ 100.

Предположим, что структура исходной таблицы является произвольной:

CREATE TABLE [dbo].[MyTable]
(
[ID] [int] IDENTITY(1,1) NOT NULL,
[DataField1] [int] NOT NULL,
[FK_ID1] [int] NOT NULL,
[LotsMoreFields] [NVARCHAR] (MAX),
CONSTRAINT [PK_MyTable] PRIMARY KEY CLUSTERED ([ID] ASC)
)

CREATE TABLE [dbo].[FK1]
(
[ID] [int] IDENTITY(1,1) NOT NULL,
[Name] [int] NOT NULL, -- Unique constrained value
CONSTRAINT [PK_FK1] PRIMARY KEY CLUSTERED ([ID] ASC)
)

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

CREATE TABLE [dbo].[ChangeTracking]
(
[ReferenceID] BIGINT IDENTITY(1,1),
[Src_ID] BIGINT,
[Dest_ID] BIGINT,
[TableName] NVARCHAR(255),
CONSTRAINT [PK_ChangeTracking] PRIMARY KEY CLUSTERED ([ReferenceID] ASC)
)

Мой существующий метод выполняет динамический sql, сгенерированный хранимой процедурой.Хранимая процедура выполняет поиск PK, поскольку исходная система имеет различные значения PK для таблицы [dbo]. [FK1].Например,

IF NOT EXISTS (<ignore this existence check for now>)
BEGIN
    INSERT INTO [Dest].[dbo].[MyTable] ([DataField1],[FK_ID1],[LotsMoreFields]) VALUES (333,(SELECT [ID] FROM [Dest].[dbo].[FK1] WHERE [Name]=N'ValueFoundInSource'),N'LotsMoreValues');
    INSERT INTO [Dest].[dbo].[ChangeTracking] ([Src_ID],[Dest_ID],[TableName]) VALUES (666,SCOPE_IDENTITY(),N'MyTable'); --666 is the PK in [Src].[dbo].[MyTable] for this inserted row
END

Итак, если у вас есть миллион таких, это не быстро.

Есть ли рекомендуемый эффективный способ сделать это?

Ответы [ 3 ]

0 голосов
/ 05 июня 2018

Похоже, вы делаете эти обновления как разработчик интерфейса, проверяя соответствие каждой строки и затем вставляя.Будет намного эффективнее делать вставки одним запросом.Ниже приведен пример, который ищет имена, которые находятся в таблице tblNewClient, но отсутствуют в таблице tblClient:

INSERT INTO tblClient
        ( [Name] ,
          TypeID ,
          ParentID 
          )
SELECT nc.[Name] ,
    nc.TypeID ,
    nc.ParentID
FROM tblNewClient nc
    LEFT JOIN tblClient cl
        ON nc.[Name] = cl.[Name]
WHERE cl.ID IS NULL;

Это будет способ более эффективным, чем это делает RBAR (строкамучительный ряд).

0 голосов
/ 06 июня 2018

Взяв два ответа из @RusselFox и соединив их, я нашел это предварительное решение (но выглядело МНОГО более эффективным):

MERGE INTO [Dest].[dbo].[MyTable] [MT_D]
USING (SELECT [MT_S].[ID] as [SrcID],[MT_S].[DataField1],[FK_1_D].[ID] as [FK_ID1],[MT_S].[LotsMoreFields]
FROM [Src].[dbo].[MyTable] [MT_S]
JOIN [Src].[dbo].[FK_1] ON [MT_S].[FK_ID1] = [FK_1].[ID]
JOIN [Dest].[dbo].[FK_1] [FK_1_D] ON [FK_1].[Name] = [FK_1_D].[Name]
) [SRC] ON 1 = 0 
WHEN NOT MATCHED THEN
INSERT([DataField1],[FL_ID1],[LotsMoreFields])
VALUES ([DataField1],[FL_ID1],[LotsMoreFields])
OUTPUT [SRC].[SrcID],INSERTED.[ID],0,N'MyTable' INTO [Dest].[dbo].[ChangeTracking]([Src_ID],[Dest_ID],[AlreadyExists],[TableName]);
0 голосов
/ 04 июня 2018

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

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