Производительность вставки увеличивается под нагрузкой: почему?

19

У меня есть кусок кода, который выполняет вставки в сильно денормализованные таблицы. Таблицы имеют количество столбцов в диапазоне от ~ 100 до 300+. Это SQL Server 2008 R2, работающий на Windows Server 2008.

Каждая вставка состоит из вставки в несколько таблиц в рамках одной транзакции. Некоторые вставки пакетируются NHibernate, но некоторые не могут, но тем не менее все они находятся в одной транзакции.

Когда я выполняю вставки, скажем, 500 раз, неоднократно вызывая фрагмент кода, который выполняет вставку, я получаю в среднем ~ 360 мс.

Странно то, что когда я запускаю тестовый код одновременно, используя 4 процесса (один и тот же exe-файл запускается из 4 разных командных строк в Windows Server 2008), производительность вставки для вызова становится намного выше. Я вижу всплески, которые идут со скоростью 90 мс (почти X4 быстрее). Я измеряю время вставки из кода.

Поскольку 4 процесса ничего не знают друг о друге, я предполагаю, что это как-то связано с SQL Server, но я понятия не имею, почему. Я хотел бы знать, почему это происходит, и если есть какая-либо конфигурация, которая позволила бы мне получить такую ​​же производительность, когда вставки не так часто.

Предложения, касающиеся методов мониторинга SQL Server, чтобы понять, что происходит на уровне БД, также приветствуются.

mahonya
источник

Ответы:

15

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

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

Ищите внутренние пределы достижимы. В SQL Server 2008 R2 может быть не более 32 ожидающих (асинхронных) операций сброса журнала в каждой базе данных в 64-разрядных версиях (только 8 в 32-разрядных). Существует также ограничение на общий размер выдающихся операций ввода-вывода в 3840 КБ.

Больше информации и дальнейшее чтение:

Пол Уайт говорит, что GoFundMonica
источник
12

Все, что говорит @PaulWhite, плюс ...

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

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

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

Это также может быть эффективным планом кэширования, и ваши запросы должны быть скомпилированы в первый раз, а последующие вызовы смогут избежать этого этапа.

Роб Фарли
источник
Спасибо, Роб. Моя проблема с производительностью связана с большим количеством таблиц, используемых во время вставки. Внешних ключей нет, я удалил их по соображениям производительности, и мои требования к модели и домену позволяют мне это делать. Я не загружаю данные в оперативную память, и мои вставки динамически формируются входящими запросами, которые постоянно меняются. Я в основном неправильно использую схему «звезда / снежинка» для OLTP и пытаюсь добиться максимальной производительности.
Махоня
2
@mahonya, даже если вы явно не загружаете данные в ОЗУ, SQL Server должен сначала прочитать необходимый индекс и страницы данных в буферный кеш перед выполнением операции вставки. Параллельные потоки вставки могут иметь эффект разогрева кеша, так что один поток переносит накладные расходы на чтение, а другой обращается к данным в кеше.
Дан Гузман
Спасибо @DanGuzman - и да, Махоня, есть большая вероятность того, что ваш кеш приятно нагревается. Я бы проверил ваши ожидания, чтобы увидеть, не является ли физический ввод-вывод причиной вашего узкого места.
Роб Фарли
Спасибо @DanGuzman Согласен, ускорение кэша индекса db - это то, что я привык видеть в postgres. Я, вероятно, неправильно понял ввод Роба.
Махоня
-3

некоторые серверы / процессоры / операционные системы запоминают шаблоны. как кеш.

Поскольку вы делаете одно и то же 4 раза, я уверен, что есть способы, которые могут срезать углы. Я предполагаю, что в первом случае вы думаете об этом как об одном долгом процессе (пример 1), но вторым способом is видит повторно использованный код и запускает его как кеш (example2), или это может быть первый процесс, который должен вместить его в (ram example3).

пример1: 0111110000110111110000111011111000011110111110000

пример2: 0111110000 | 11 | 0111110000 | 111 | 0111110000 | 1111 | 0111110000

пример3: 0111110000011111000001111100000111110000 пример3: цикл: 0111110000

Я знаю, что сервер Ubuntu делает это с повторными запросами MySQL. Я могу сохранить их в кеше, хотя на самом деле единственная разница во времени составляет 10-40 мм, но это складывается. Когда я учился в школе, были классы, которые показали, что вы должны заставить программы (perl / php) использовать этот кеш, чтобы быть быстрее.

Но это может зависеть от программы, на каком языке, на каком языке она была скомпилирована или как она была запрограммирована.

Bryku
источник