Я не очень умный парень, и у меня нет большого опыта работы с методом SqlClient.SqlBulkCopy, но вот мои 2 цента за то, что он стоит. Я надеюсь, что это поможет вам и другим (или, по крайней мере, заставит людей вызывать мое невежество;).
Вы никогда не будете соответствовать скорости копирования необработанного файла, если ваш файл данных базы данных (mdf) не находится на отдельном физическом диске от файла журнала транзакций (ldf). Кроме того, любые кластерные индексы также должны находиться на отдельном физическом диске для более справедливого сравнения.
Ваша необработанная копия не регистрирует или не поддерживает порядок сортировки выбранных полей (столбцов) для целей индексации.
Я согласен с Портманом в создании некластеризованного идентификатора и замене существующего некластеризованного индекса на кластеризованный индекс.
Что касается конструкции, которую вы используете на клиентах ... (адаптер данных, набор данных, данные и т. Д.). Если ваш дисковый ввод на сервере составляет 100%, я не думаю, что вам лучше всего тратить время на анализ клиентских конструкций, так как они выглядят быстрее, чем сервер в настоящее время может обрабатывать.
Если вы перейдете по ссылкам Портмана о минимальном ведении журнала, я не думаю, что окружение ваших массовых копий транзакциями очень поможет, если таковые имеются, но я много раз ошибался в своей жизни;)
Это не обязательно поможет вам прямо сейчас, но если вы выясните свою текущую проблему, этот следующий комментарий может помочь с следующим узким местом (пропускная способность сети) - особенно если это через Интернет ...
Чопин тоже задал интересный вопрос. Как вы решили использовать 300 блоков записей для вставки? SQL Server имеет размер пакета по умолчанию (я считаю, что он составляет 4096 байт), и для меня будет иметь смысл определить размер ваших записей и убедиться, что вы эффективно используете пакеты, передаваемые между клиентом и сервером. (Обратите внимание, что вы можете изменить размер пакета в клиентском коде, в отличие от опции сервера, которая, очевидно, изменит его для всех соединений с сервером - вероятно, не очень хорошая идея.) Например, если размер вашей записи приводит к 300 пакетам записей, требующим 4500 байт, вы отправите 2 пакета, причем второй пакет в основном потрачен впустую. Если счетчик записей партии был назначен произвольно, возможно, имеет смысл сделать небольшую простую математику.
Из того, что я могу сказать (и помните о размерах типов данных), у вас есть ровно 20 байтов для каждой записи (если int = 4 байта и smallint = 2 байта). Если вы используете 300 записей по количеству записей, то вы пытаетесь отправить 300 x 20 = 6000 байтов (плюс я предполагаю, что для соединения потребуются небольшие накладные расходы и т. Д.). Возможно, вам будет эффективнее отправить их в 200 пакетах по количеству записей (200 x 20 = 4000 + место для накладных расходов) = 1 пакет. С другой стороны, узким местом по-прежнему является диск сервера io.
Я понимаю, что вы сравниваете передачу необработанных данных в SqlBulkCopy с тем же аппаратным обеспечением / конфигурацией, но здесь я бы также остановился, если бы проблема была моей:
Этот пост, вероятно, вам больше не поможет, так как он довольно старый, но я хотел бы спросить, какова конфигурация RAID вашего диска и какую скорость вы используете? Попробуйте поместить файл журнала на диск, который использует RAID 10 с RAID 5 (в идеале 1) в файле данных. Это может помочь уменьшить большую часть перемещения шпинделя в различных секторах на диске и привести к большему времени чтения / записи вместо непродуктивного «движущегося» состояния. Если вы уже отделяете свои данные и файлы журналов, у вас есть индекс на другом физическом диске, чем файл данных (вы можете сделать это только с кластерными индексами). Это позволило бы не только одновременно обновлять информацию журналов со вставкой данных, но и одновременно выполнять вставку индекса (и любые дорогостоящие операции над страницей индекса).