Насколько я могу сказать, вы можете оптимизировать массовую вставку очень похожим образом, как если бы вы оптимизировали обычную вставку. Как правило, план запроса для простой вставки не очень информативен, поэтому не беспокойтесь об отсутствии плана. Я рассмотрю несколько способов оптимизации вставки, но большинство из них, вероятно, не подходят для вставки, указанной вами в вопросе. Однако они могут быть полезны, если в будущем вам потребуется загружать большие объемы данных.
1. Вставьте данные в порядке ключей кластеризации.
SQL Server часто сортирует данные перед вставкой в таблицу с кластерным индексом. Для некоторых таблиц и приложений вы можете повысить производительность, отсортировав данные в плоском файле и сообщив SQL Server, что данные отсортированы по ORDER
аргументу BULK INSERT
:
ЗАКАЗ ({столбец [ASC | DESC]} [, ... n])
Определяет, как данные в файле данных сортируются. Производительность массового импорта улучшается, если импортируемые данные сортируются в соответствии с кластеризованным индексом в таблице, если таковой имеется.
Поскольку вы используете IDENTITY
столбец в качестве кластерного ключа, вам не нужно беспокоиться об этом.
2. Используйте, TABLOCK
если возможно
Если у вас гарантированно будет только один сеанс вставки данных в вашу таблицу, вы можете указать TABLOCK
аргумент для BULK INSERT
. Это может уменьшить конфликт блокировок и может привести к минимальному ведению журнала в некоторых сценариях. Однако вы вставляете в таблицу с кластеризованным индексом, который уже содержит данные, поэтому вы не получите минимальное ведение журнала без флага трассировки 610, который упоминается далее в этом ответе.
Если TABLOCK
это невозможно, потому что вы не можете изменить код , не вся надежда потеряна. Рассмотрите возможность использования sp_table_option
:
EXEC [sys].[sp_tableoption]
@TableNamePattern = N'dbo.BulkLoadTable' ,
@OptionName = 'table lock on bulk load' ,
@OptionValue = 'ON'
Другой вариант - включить флаг трассировки 715 .
3. Используйте соответствующий размер партии
Иногда вы сможете настроить вставки, изменив размер пакета.
ROWS_PER_BATCH = row_per_batch
Указывает приблизительное количество строк данных в файле данных.
По умолчанию все данные в файле данных отправляются на сервер в виде одной транзакции, а количество строк в пакете неизвестно оптимизатору запросов. Если вы укажете ROWS_PER_BATCH (со значением> 0), сервер использует это значение для оптимизации операции массового импорта. Значение, указанное для ROWS_PER_BATCH, должно приблизительно соответствовать фактическому количеству строк. Дополнительные сведения о производительности см. В разделе «Замечания» далее в этом разделе.
Вот цитата позже в статье:
Если число страниц, подлежащих очистке в одном пакете, превышает внутренний порог, может произойти полное сканирование пула буферов, чтобы определить, какие страницы необходимо очистить при фиксации пакета. Такое полное сканирование может снизить производительность массового импорта. Вероятный случай превышения внутреннего порога происходит, когда большой буферный пул объединяется с медленной подсистемой ввода-вывода. Чтобы избежать переполнения буфера на больших компьютерах, либо не используйте подсказку TABLOCK (которая удалит массовые оптимизации), либо используйте меньший размер пакета (который сохраняет массовые оптимизации).
Поскольку компьютеры различаются, мы рекомендуем вам тестировать пакеты разных размеров при загрузке данных, чтобы выяснить, что лучше всего подходит для вас.
Лично я бы просто вставил все 695 строк в одну партию. Настройка размера пакета может иметь большое значение при вставке большого количества данных.
4. Убедитесь, что вам нужен IDENTITY
столбец
Я ничего не знаю о вашей модели данных или требованиях, но не попадаюсь в ловушку добавления IDENTITY
столбца к каждой таблице. Аарон Бертран имеет статью об этом, которая называется « Плохие привычки»: размещение столбца IDENTITY на каждой таблице . Чтобы было ясно, я не говорю, что вы должны удалить IDENTITY
столбец из этой таблицы. Однако, если вы определите, что IDENTITY
столбец не нужен, и удалите его, это может повысить производительность вставки.
5. Отключить индексы или ограничения
Если вы загружаете большой объем данных в таблицу по сравнению с тем, что у вас уже есть, то может быть быстрее отключить индексы или ограничения перед загрузкой и включить их после загрузки. Для больших объемов данных, как правило, более неэффективно для SQL Server создавать индекс сразу, а не по мере загрузки данных в таблицу. Похоже, вы вставили 695 строк в таблицу с 11500 строками, поэтому я бы не рекомендовал этот метод.
6. Рассмотрим TF 610
Trace Flag 610 позволяет минимально регистрировать в некоторых дополнительных сценариях. Для вашей таблицы с IDENTITY
кластеризованным ключом вы получите минимальное ведение журнала для любых новых страниц данных, если ваша модель восстановления является простой или с массовой регистрацией. Я считаю, что эта функция не включена по умолчанию, потому что она может ухудшить производительность в некоторых системах. Вам нужно тщательно протестировать, прежде чем включить этот флаг трассировки. Рекомендуемое руководство Microsoft по-прежнему выглядит как Руководство по повышению производительности загрузки данных.
Влияние ввода-вывода на минимальное ведение журнала под флагом трассировки 610
Когда вы фиксируете транзакцию массовой загрузки, которая была минимально записана в журнал, все загруженные страницы должны быть сброшены на диск до завершения фиксации. Любые сброшенные страницы, не уловленные более ранней операцией контрольной точки, могут создавать много случайных операций ввода-вывода. Сравните это с полностью зарегистрированной операцией, которая вместо этого создает последовательный ввод-вывод для записей журнала и не требует загрузки загруженных страниц на диск во время фиксации.
Если ваш сценарий загрузки - небольшие операции вставки на деревьях, которые не пересекают границы контрольных точек, и у вас медленная система ввода-вывода, использование минимального ведения журнала может фактически снизить скорость вставки.
Насколько я могу судить, это не имеет ничего общего с флагом трассировки 610, а скорее с минимальным ведением журнала. Я полагаю, что предыдущая цитата о ROWS_PER_BATCH
тюнинге была связана с этой концепцией.
В заключение, вероятно, не так много, что вы можете сделать, чтобы настроить свой BULK INSERT
. Я не буду беспокоиться о количестве операций чтения, которые вы наблюдали со своей вставкой. SQL Server будет сообщать о чтениях каждый раз, когда вы вставляете данные. Рассмотрим следующее очень просто INSERT
:
DROP TABLE IF EXISTS X_TABLE;
CREATE TABLE X_TABLE (
VAL VARCHAR(1000) NOT NULL
);
SET STATISTICS IO, TIME ON;
INSERT INTO X_TABLE WITH (TABLOCK)
SELECT REPLICATE('Z', 1000)
FROM dbo.GetNums(10000); -- generate 10000 rows
Выход из SET STATISTICS IO, TIME ON
:
Таблица «X_TABLE». Сканирование 0, логическое чтение 11428
У меня 11428 сообщений о прочтении, но это не действующая информация. Иногда количество зарегистрированных операций чтения может быть уменьшено путем минимального ведения журнала, но, конечно, разницу нельзя напрямую перевести в выигрыш в производительности.