Влияет ли длина CommandText команды SqlCommand? Я не говорю о тысячах персонажей. Вот что у меня есть:
SqlCommand cmd = new SqlCommand();
cmd.Connection = conn;
cmd.CommandText = sql;
for (int i=0; i<1000; ++i)
{
string name = i.ToString() + "Bob" + i.ToString();
string email = i.ToString() + "Jim" + i.ToString();
// etc...
cmd.Parameters.Clear();
cmd.Parameters.Add(new SqlParameter("@name", name));
cmd.Parameters.Add(new SqlParameter("@country", country));
DateTime cmdStart = DateTime.Now;
cmd.ExecuteNonQuery();
DateTime cmdEnd = DateTime.Now;
TimeSpan len = cmdEnd - cmdStart;
}
Если я использую следующий sql, первая итерация займет 0,5 секунды. Второй занимает 1,1 секунды. Третий занимает 3,3 секунды. И так до тех пор, пока он просто не сработает в течение тайм-аута.
string sql =
"INSERT INTO Test " +
" ([name] " +
" ,[email] " +
" ,[country] " +
" ,[comment] " +
" ,[date] " +
" ,[key_v0] " +
" ,[key_v1] " +
" ,[expires_v1] " +
" ,[expires_v2] " +
" ) " +
" VALUES " +
" (@name " +
" ,@email " +
" ,@country " +
" ,' ' " +
" ,@date " +
" ,@key_v0 " +
" ,@key_v1 " +
" ,@expires_v1 " +
" ,@expires_v2 " +
" )";
Однако, если я использую следующий sql, весь цикл выполняется менее чем за секунду.
string sql =
"INSERT INTO Test " +
"([name] " +
",[email] " +
",[country] " +
",[comment] " +
",[date] " +
",[key_v0] " +
",[key_v1] " +
",[expires_v1] " +
",[expires_v2] " +
") " +
"VALUES " +
"(@name " +
",@email " +
",@country " +
",' ' " +
",@date " +
",@key_v0 " +
",@key_v1 " +
",@expires_v1 " +
",@expires_v2 " +
")";
Единственная разница - это пробел. Удаление пробела привело к тому, что общее количество символов увеличилось с 428 до 203. Мне не удалось найти ничего, ссылающегося на длину CommandText, кроме ссылок на ограничения 4k и 8k. Я не близко к этому.
Я запустил обе версии с запущенным профилировщиком, и его продолжительность не превышает 10 мс для всех вызовов. Кажется, что задержка происходит с момента завершения команды внутри механизма SQL до возврата ExecuteNonQuery.
Я знаю, что есть альтернативные способы сделать это. Я не спрашиваю о лучших способах сделать это. Я спрашиваю об источнике замедления.
UPDATE:
В качестве теста я добавил пробелы в конец запроса. Как только я набрал более 400 символов, он замедлился. Интересно, что при 414 символах первые 99 вставок выполняются быстро. В 415 символов, первые 9 вставок являются быстрыми. Так как я изменяю некоторые строки на основе номера итерации, это имеет смысл. например 10-я вставка немного длиннее 9-й, а 100-я вставка немного длиннее 99-й.
Хотя я вроде понимаю, что более длинные вставки должны занимать больше времени, я не могу понять четкое разделение между быстрой и медленной и абсолютной величиной разницы. Я также не понимаю, почему увеличивается время.
ОБНОВЛЕНИЕ 2:
(Дополнительная информация в ответ на ответ Питера Элерта):
Вся база данных чистая. Других таблиц нет, и тестовая таблица удаляется и воссоздается для каждого запуска. Здесь нет индексов, триггеров или внешних ключей. Существует столбец id, который является первичным ключом.
Это код, извлеченный из консольного приложения, написанного специально для устранения этой проблемы. Он содержит только необходимый код для воспроизведения этого поведения.
(дополнительная информация о профилировщике):
При запуске средства профилирования SQL существует столбец с именем TextData, который показывает, что это за команда и данные. Пример таков:
exec sp_executesql N'INSERT INTO Test ([name] ,[email] ,[country] ,[comment] ,[date] ,[key_v0] ,[key_v1] ,[expires_v1] ,[expires_v2] ) VALUES (@name ,@email ,@country ,'' '' ,@date ,@key_v0 ,@key_v1 ,@expires_v1 ,@expires_v2 ) ',N'@name nvarchar(4),@country nvarchar(2),@email nvarchar(3),@date datetime,@key_v0 nvarchar(4000),@key_v1 nvarchar(4000),@expires_v1 datetime,@expires_v2 datetime',@name=N'9Bob',@country=N'us',@email=N'Jim',@date='2009-08-28 15:35:36.5770000',@key_v0=N'',@key_v1=N'',@expires_v1='2009-08-28 15:35:36.5770000',@expires_v2='2009-08-28 15:35:36.5770000'
Эта строка имеет длину 796 символов и работает быстро. Изменение имени с «9Bob» на «10Bob» приводит к медленной вставке. Ни 796, ни 797 не кажутся значительными цифрами. Удаление части exec sp_executesql означает длину 777 и 778. Они также не кажутся значительными.
Я в тупике.
Обновление:
Выложенный здесь след: http://www.jere.us/WierdInserts.trc