Низкая производительность с помощью 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 позволит ему лучше использовать запрос.