INSERT INTO идет намного медленнее в SQL Server 2012

У нас очень большая база данных WriteDB, в которой хранятся необработанные торговые данные, и мы используем эту таблицу для быстрой записи. Затем с помощью сценариев sql я импортирую данные из WriteDB в ReadDB в сравнительно той же таблице, но расширен с добавлением некоторых дополнительных значений + отношения. Сценарий импорта такой:

TRUNCATE TABLE [ReadDB].[dbo].[Price]
GO
INSERT INTO [ReadDB].[dbo].[Price]
SELECT a.*, 0 as ValueUSD, 0 as ValueEUR
from [WriteDB].[dbo].[Price] a
JOIN [ReadDB].[dbo].[Companies] b ON a.QuoteId = b.QuoteID

Итак, изначально существует около 130 мил. строк в этой таблице (~ 50 ГБ). Каждый день некоторые из них добавляются, некоторые из них меняются, поэтому сейчас мы решаем не слишком усложнять логику, а просто повторно импортировать все данные. Проблема в том, что по какой-то причине со временем этот скрипт работает дольше и дольше, практически на одном и том же объеме данных. Первый запуск занимает ~ 1 час, теперь уже 3 часа

Также SQL Server после импорта работает не очень хорошо. После импорта (или во время него), если я пытаюсь выполнить разные запросы, даже самые простые они часто терпят неудачу с ошибками тайм-аута.

В чем причина такого плохого поведения и как это исправить?

7 голосов | спросил Ph0en1x 21 PMpTue, 21 Apr 2015 15:23:37 +030023Tuesday 2015, 15:23:37

1 ответ


0

Одна из теорий заключается в том, что ваш первый набор данных объемом 50 ГБ заполнил доступную память для кэширования. После усечения таблицы ваш кеш теперь фактически пуст. Такое чередующееся поведение затрудняет эффективное использование кэша и приводит к значительному количеству пропаданий кэша /увеличению времени ввода-вывода.

Рассмотрим следующую последовательность событий:

  1. Вы загружаете свой начальный набор данных в WriteDb. Во время операции загрузки страницы в WriteDb кэшируются. Очень мало конфликтов памяти, потому что есть только одна копия набора данных и достаточно памяти.
  2. Вы изначально заполняете ReadDb. Страницы, необходимые для заполнения ReadDb (данные в WriteDb), уже в значительной степени кэшированы. Меньше чтений требуется с диска, и ваше время ввода-вывода может быть посвящено записи вставленных данных для ReadDb. (Это ваш быстрый первый запуск.)
  3. Вы загружаете свой второй набор данных в WriteDb. Во время операции загрузки недостаточно памяти для кэширования как существующих данных в ReadDb, так и новых данных, записанных в WriteDb. Этот конфликт памяти приводит к уменьшению количества страниц в кэше WriteDb.
  4. Вы усекаете ReadDb. Это делает недействительной существенную часть вашего кэша (то есть 50 ГБ данных ReadDb, которые были кэшированы).
  5. Затем вы пытаетесь выполнить вторую загрузку ReadDb. Здесь у вас очень мало кеширования WriteDb, поэтому ваше время ввода-вывода делится между чтением страниц WriteDb (ваш запрос) и записью страниц ReadDb (ваша вставка). (Это ваша медленная вторая пробежка.)

Вы можете проверить эту теорию, сравнив коэффициент пропадания кэша SQL Server во время первой и второй операций загрузки.

Некоторые способы улучшить производительность могут быть следующими:

  • Используйте отдельные дисковые массивы для ReadDb /WriteDb для увеличения производительности параллельного ввода-вывода.
  • Увеличьте доступный кэш (объем памяти сервера), чтобы вместить объединенный размер ReadDb + WriteDb, и минимизируйте потери в кеше.
  • Минимизируйте влияние каждой операции загрузки на существующие кэшированные страницы, используя инструкцию MERGE вместо выгрузки /загрузки 50 ГБ данных в время.
ответил Michael Petito 21 PMpTue, 21 Apr 2015 16:10:10 +030010Tuesday 2015, 16:10:10

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132