Копирование данных из одной таблицы в другую с помощью функции «Вставить в» - PullRequest
0 голосов
/ 20 апреля 2020

У меня есть две таблицы. Оба имеют одинаковую структуру, за исключением того, что в таблице 2 есть дополнительный столбец В настоящее время я копирую данные из table1 в table2, используя сохраненный pro c, как показано ниже.

Однако, из-за огромного количества записей (20 миллионов +) и структуры хранимого pro c, в настоящее время для запуска требуется несколько часов.

У кого-нибудь есть предложения по оптимизации кода?

CREATE PROCEDURE dbo.insert_period @period INT AS

DECLARE @batchsize INT
DECLARE @start INT
DECLARE @numberofrows INT

SELECT @numberofrows = COUNT(*) from daily_table

SET @batchsize = 150000
SET @start = 1

WHILE @start < @numberofrows
BEGIN
    INSERT INTO dbo.main_table WITH (TABLOCK) (
    col1,
    col2,
    ....,
    col26,
    time_period
    )
    SELECT *, @period FROM dbo.daily_table
    ORDER BY id

    OFFSET @start ROWS
            FETCH NEXT @batchsize ROWS ONLY

    SET @start += @batchsize + 1
END

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

Ответы [ 2 ]

1 голос
/ 20 апреля 2020

Сначала я хотел бы отметить, что логика c в вашей вставке некорректна.

Когда @start начинается с 1, вы всегда пропускаете первую строку исходной таблицы. Затем добавление 1 к нему в конце вашего l oop приводит к тому, что он пропускает еще одну строку при каждом последующем запуске l oop.

. Если ваш набор использует пакетные вставки, я предлагаю вам прочитать о том, как это работает на MSSQLTips .

Чтобы помочь вам с производительностью, я бы посоветовал взглянуть на следующее:

SELECT *

Удалите SELECT * и замените имена столбцов. Это поможет оптимизатору получить лучший план запросов. Дальнейшее чтение о том, почему SELECT * плохо, можно найти в этом SO Вопросе .

ORDER BY

Что ORDER BY, вероятно, замедляется ты вниз Не видя ваш план запроса, мы не можем знать наверняка. Каждый раз, когда ваш l oop выполняет, он запрашивает исходную таблицу и должен отсортировать все эти записи. Сортировать 20+ фрезерных записей, что много раз - много работы. Взгляните на мой упрощенный пример ниже.

CREATE TABLE #Test (Id INT);
INSERT INTO #Test VALUES (1), (2), (3), (4), (5);

DECLARE @batchsize INT;
DECLARE @start INT;
DECLARE @numberofrows INT;

SELECT  @numberofrows = COUNT(*) FROM   #Test;

SET @batchsize = 2;
SET @start = 0;

WHILE @start < @numberofrows
BEGIN
    SELECT
        *
        , 10
    FROM
        #Test
    ORDER BY
        Id OFFSET @start ROWS FETCH NEXT @batchsize ROWS ONLY;

    SET @start += @batchsize;
END;

Ниже приведена часть плана запроса, созданного образцом. Обратите внимание на операцию сортировки, выделенную желтым цветом. Его стоимость составляет 78% от этого плана запроса.

enter image description here

Если мы добавим индекс, который уже отсортирован в столбце Id исходной таблицы, мы можно устранить род. Теперь, когда запускается l oop, он не должен выполнять никакой сортировки.

CREATE INDEX ix_Test ON #Test (Id)

enter image description here

Другие варианты исследования

  1. Индексы Columnstore
  2. Пакетный режим в RowStore
  3. Параллельные вставки
0 голосов
/ 20 апреля 2020

Вы копируете таблицу строка за строкой, поэтому это занимает так много времени. Самый простой способ достичь того, что вы хотите - это INSERT в сочетании с оператором SELECT. Таким образом, вы вставите данные в один пакет.

CREATE TABLE dbo.daily_table (id INT PRIMARY KEY IDENTITY,
                              value1 NVARCHAR(100) NULL,
                              value2 NVARCHAR(100) NULL);
GO

CREATE TABLE dbo.main_table (id INT PRIMARY KEY IDENTITY,
                             value1 NVARCHAR(100) NULL,
                             value2 NVARCHAR(100) NULL,
                             value3 NVARCHAR(100) NULL);
GO

INSERT INTO dbo.daily_table (value1, value2)
VALUES('1', '2');

-- Insert with Select
INSERT INTO dbo.main_table (value1, value2)
SELECT  value1,     value2
FROM    dbo.daily_table;

Кроме того, лучше не использовать звездочку в выражении SELECT, поскольку результат может быть непредсказуемым.

...