Низкая производительность с помощью sqlparameter
У меня есть веб-сервис, поэтому обработчик вызывается несколько раз одновременно.
Внутри я создаю SqlConnection и SqlCommand. Я должен выполнить около 7 различных команд. Для разных команд требуются различные параметры, поэтому я просто добавляю их один раз:
command.Parameters.Add(new SqlParameter("@UserID", userID));
command.Parameters.Add(new SqlParameter("@AppID", appID));
command.Parameters.Add(new SqlParameter("@SID", SIDInt));
command.Parameters.Add(new SqlParameter("@Day", timestamp.Date));
command.Parameters.Add(new SqlParameter("@TS", timestamp));
Затем во время выполнения я просто изменяю правомочность CommandText, а затем вызываю ExecuteNonQuery(); или ExecuteScalar();
И я столкнулся с проблемой производительности.
Например, небольшие отладки и профилирования показывают, что команда
command.CommandText = "SELECT LastShowTS FROM LogForAllTime WHERE UserID = @UserID";
занимает около 50 мс. Если я изменю его на:
command.CommandText = "SELECT LastShowTS FROM LogForAllTime WHERE UserID = '" + userID.Replace("\'", "") + "'";
тогда он занимает всего 1 мс в avarage!
Я просто не могу понять, где искать проблему.
Ответы
Ответ 1
Похоже, он кэшировал план запроса для нетипичного значения @UserID
(один из ранних) и повторно использует плохой план для последующих запросов. Это не проблема во втором случае, поскольку каждый из них имеет отдельный план. Я подозреваю, что вам просто нужно добавить:
OPTION (OPTIMIZE FOR UNKNOWN)
что сделает его менее желательным для повторного использования планов вслепую.
Альтернативная теория:
У вас может быть несоответствие между типом userID
(в С#) и типом userID
(в базе данных). Это может быть так же просто, как unicode vs ANSI, или может быть int
vs varchar[n]
и т.д. Если у вас есть сомнения, будьте очень конкретными при настройке параметра, чтобы добавить его с правильной подкатегорией, тип и размер.
Разъяснение
В самом деле, похоже, проблема здесь заключается в различии между С# string
(unicode) и базой данных varchar(n)
(ANSI). Поэтому SqlParameter
должно быть явно добавлено как таковое (DbType.AnsiString
).
Ответ 2
Вы отправляете на сервер на семь раз больше данных, поэтому он будет медленнее.
Кроме того, если ваши строки userID
имеют разную длину, установка явной длины в параметре SQL позволит ему лучше использовать запрос.