У нас есть база данных для продукта, который тяжело писать. Мы только что купили новую серверную машину с SSD, чтобы помочь. К нашему удивлению, вставки были не быстрее, чем на нашей старой машине с гораздо более медленным хранилищем. Во время бенчмаркинга мы заметили, что частота операций ввода-вывода, демонстрируемая процессом SQL Server, была очень низкой.
Например, я запустил скрипт, найденный на этой странице , за исключением того, что я добавил BEGIN TRAN и COMMIT вокруг цикла. В лучшем случае я видел, как использование диска достигало 7 Мбит / с, а процессор едва касался 5%. На сервере установлено 64 ГБ, и он использует 10. Общее время выполнения составило 2 минуты 15 секунд для первого вызова и примерно до 1 минуты для последующих вызовов. База данных находится на простом восстановлении и не работала во время теста. Я бросил стол между каждым звонком.
Почему такой простой скрипт такой медленный? Аппаратное обеспечение практически не используется. Как специализированные инструменты для тестирования дисков, так и SQLIO указывают на то, что твердотельный накопитель работает правильно со скоростью более 500 Мбит / с для чтения и записи. Я понимаю, что случайные записи выполняются медленнее, чем последовательные записи, но я ожидаю, что простая вставка, подобная этой, в таблицу без кластерной индексации будет намного быстрее.
В конечном итоге наш сценарий намного сложнее, но я чувствую, что сначала мне нужно разобраться в простом случае. В двух словах, наше приложение удаляет старые данные, затем использует SqlBulkCopy для копирования новых данных в промежуточные таблицы, выполняет некоторую фильтрацию и, наконец, использует MERGE и / или INSERT INTO в зависимости от случаев для копирования данных в финальные таблицы.
-> РЕДАКТИРОВАТЬ 1: Я следовал процедуре, связанной Мартином Смитом, и получил следующий результат:
[Wait Type] [Wait Count] [Total Wait (ms)] [T. Resource Wait (ms)] [T. Signal Wait (ms)]
NETWORK_IO 5008 46735 46587 148
LOGBUFFER 901 5994 5977 17
PAGELATCH_UP 40 866 865 1
SOS_SCHEDULER_YIELD 53279 219 121 98
WRITELOG 5 145 145 0
PAGEIOLATCH_UP 4 58 58 0
LATCH_SH 5 0 0 0
Я нахожу странным, что NETWORK_IO занимает большую часть времени, учитывая, что нет никакого результата, который нужно отображать, и нет данных, которые нужно передавать куда-либо, кроме файлов SQL. Включает ли тип NETWORK_IO все операции ввода-вывода?
-> РЕДАКТИРОВАТЬ 2: Я создал 20 ГБ RAM-диск и оттуда смонтировал базу данных. Лучшее время, которое у меня было на SSD - 48 с, а с RAM-диска оно уменьшилось до 37 секунд. NETWORK_IO по-прежнему самое большое ожидание. Максимальная скорость записи на RAM-диск составляла около 250 Мбит / с, тогда как он способен обрабатывать несколько гигабайт в секунду. Он по-прежнему не использует много процессора, так что же удерживает SQL?
SET NOCOUNT ON
к этому тоже.NETWORK_IO
могут быть сообщения из 3 миллионов сообщений, "затронутых 1 строкой". Вы пробовали добавитьSET NOCOUNT ON
в скрипт?EE_WaitStats*.xel
так что старые будут загрязнять ваши результаты.Ответы:
Я знаю, что это старый Вопрос, но он все еще может помочь поисковикам, и эта проблема возникает время от времени.
Основная причина, по которой вы достигаете предела производительности, не видя узких мест в ресурсах, заключается в том, что вы достигли предела того, что можно обрабатывать в одном сеансе одного потока. Цикл не обрабатывается параллельно, но все вставки выполняются последовательно.
В моем случае для вставки 3 миллионов строк требуется 36 секунд. Это означает, что 36/30000000 = 0,000012 секунд на строку. Это довольно быстро. В моей системе просто требуется 0,000012, чтобы пройти все необходимые шаги.
Единственный способ сделать это быстрее - запустить второй сеанс параллельно.
Если я начну 2 сеанса параллельно, оба будут делать 15 миллионов вставок. Они оба финишируют за 18 секунд. Я мог бы масштабировать больше, но мои текущие настройки теста достигают 95% ЦП с двумя параллельными сессиями, поэтому выполнение 3 исказит результаты, поскольку я попаду в узкое место ЦП.
Если я начну 2 параллельных сеанса, вставляя 3 миллиона строк, они оба завершат работу за 39 секунд. так что теперь 6 миллионов строк за 39 секунд.
Хорошо, это все еще оставляет нас с ожиданием NETWORK_IO.
Ожидания NETWORK_IO добавляются тем фактом, что вы используете расширенные события для их отслеживания. В моем случае вставка занимает 36 секунд (в среднем). При использовании расширенного способа события (по ссылке выше в самом первом комментарии) это то, что регистрируется:
Вы можете видеть, что зарегистрировано 68 секунд NETWORK_IO. Но поскольку цикл вставки является однопоточным действием, которое занимает 36 секунд, этого не может быть. (Да, используются несколько потоков, но операции являются последовательными, а не параллельными, поэтому вы не можете накапливать больше времени ожидания, чем общая продолжительность запроса)
Если я не использую расширенные события, а только DMVs статистики ожидания в тихом экземпляре (только я запускаю вставку), я получаю это:
Таким образом, NETWORK_IO, который вы видели в расширенном журнале событий, не был связан с вашим циклом вставки. (Если вы не включите nocount, у вас будет массовый асинхронный ввод-вывод в сети, +1 Мартин)
Однако я не знаю, почему NETWORK_IO отображается в расширенной трассировке событий. Конечно, запись в целевой файл асинхронного файла событий накапливает ASYNC_NETWORK_IO, но, безусловно, все это делается на другом SPID, чем тот, по которому мы фильтруем. Я мог бы задать это как новый вопрос сам)
источник
Как правило, вы начинаете с рассмотрения
sys.dm_exec_requests
, в частностиwait_time
,wait_type
иwait_resource
ваших запросов INSERT. Это даст четкое представление о том, что блокирует вашу вставку. Результаты покажут, является ли конфликт блокировкой, событиями роста файла, ожиданием сброса журнала, конфликтом выделения (проявляется как конфликт блокировки страницы PFS) и т. Д. И т. Д. И т. Д. И т. Д. И т. Д. После измерения обновите свой вопрос соответствующим образом. Я настоятельно призываю вас остановиться сейчас и прочитать методологию устранения неполадок, связанных с ожиданием и очередями, прежде чем продолжить.источник
Я запустил тестовый скрипт на странице, связанной в OP, с BEGIN TRAN / COMMIT вокруг цикла. На моей машине это заняло 1:28, чтобы закончить в первый раз.
Затем я переместил эти две команды за пределы цикла:
Это закончилось через 28 секунд после этого.
Я не знаю наверняка, что происходит, но я предполагаю, что в
RAND()
коде может быть какой-то сон , возможно, как часть алгоритма, который они используют для генерации энтропии (лучше случайные числа).Кстати, твердотельные накопители не всегда являются лучшей технологией для приложений с интенсивной записью. Для лучшей производительности убедитесь, что ваш журнал БД находится на другой букве диска, чем данные БД, файл журнала предварительно увеличен до максимального размера и никогда не обрезайте журнал.
источник
Другой DMV, который я использую для определения медлительности, это sys.dm_os_waiting_tasks . Если ваш запрос не загружает процессор, вы можете найти дополнительную информацию об ожиданиях от этого DMV.
источник
Я проверяю список событий ожидания для SQL 2008 и не вижу NETWORK_IO в списке: http://technet.microsoft.com/en-us/library/ms179984(v=sql.100).aspx
Я подумал, что NETWORK_IO теперь только что перечислен как ASYNC_NETWORK_IO, поэтому я хотел спросить, можете ли вы еще раз проверить вашу версию SQL, потому что мне просто любопытно, как / почему это событие ожидания появляется для этой версии.
Что касается ожидания сети, то это может произойти, даже если вы работаете на автономном сервере. Вы проверили настройки для своих сетевых карт? Мне интересно, если они являются проблемой.
В конце концов, существует только несколько узких мест в ресурсах: память, процессор, дисковый ввод-вывод, сеть и блокировка. Вы указали, что проблема не связана с процессором и вводом-выводом, и у вас есть событие ожидания NETWORK_IO, поэтому я предлагаю вам сначала посмотреть на эти платы NIC.
источник
NETWORK_IO
Показано , потому что OP использует расширенные события. Это никогда не обновлялось вsys.dm_xe_map_values