У меня есть хранимая процедура, которая в основном выбирает из сложного представления, объединенного с несколькими другими столбцами.При запуске хранимой процедуры через SSMS требуется около 6 секунд, чтобы вернуть пару тысяч строк, но запуск ее с точно такими же параметрами из C # занимает более минуты.
Я добавил ведение журнала, когда он извлекал каждую запись,и кажется, что он извлекает 75 записей почти одновременно, а затем сидит там, ничего не делая в течение приблизительно 1,5 секунд, затем еще 75 строк.Точнее говоря, он приостанавливается каждый раз, когда достигает 74 по модулю 75, то есть 74, 149, 224 и т. Д. Задержки варьируются от 1,2 до 1,8 секунд.
Далее я вставил запрос из хранимой процедуры прямо вкод C #, и задержки ушли.При использовании встроенного SQL вместо хранимой процедуры запуск занимает всего 6 секунд.
Задержки кажутся очень странными и совершенно загадочными.Это не просто «этот запрос плохо оптимизирован в этой ситуации» или «слишком много данных».Ни один из данных не поступает с постоянными приращениями 3, 5, 15 или 75 с.Ни одно из полей не должно превышать 30 символов, нет полей varbinary (max) или varchar (max), всего 12 полей и около 2500 записей.Единственная причина, по которой при правильных условиях это занимает 6 секунд, заключается в том, что представление в SQL настолько сложное, а не потому, что оно перегружено, отправляя обратно огромные объемы данных.
Может быть, все следующие детали не имеют отношения к вопросу,Я в основном включаю их, чтобы прояснить, что нет ничего необычного ни в одном из задействованных кодов.
Вот общий обзор того, что делает код C # (ничего особенного):
using (var cmd = connection.CreateCommand())
{
cmd.CommandText = "myprocedure";
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add("@startValue", SqlDbType.NVarChar).Value = DBNull.Value;
cmd.Parameters.Add("@endValue", SqlDbType.NVarChar).Value = DBNull.Value;
var result = new List<MyObject>();
using (var reader = cmd.ExecuteReader())
{
while (reader.Read())
{
var myObj = new MyObject();
myObj.Value1 = reader["Value1"] as string;
myObj.Value2 = reader["Value2"] as int?;
myObj.Value3 = reader["Value3"] as decimal?;
result.Add(myObj);
}
}
return result;
}
На практике реальный код немного сложнее, потому что он использует отражение в первый раз, когда его вызывают для создания установщиков для каждого из устанавливаемых полей:
(PropertyInfo property) =>
{
var param1 = Expression.Parameter(typeof(t));
var param2 = Expression.Parameter(typeof(object));
return Expression.Lambda<Action<t, object>>(
Expression.Call(
Expression.Convert(param1, property.ReflectedType),
property.GetSetMethod(false),
Expression.Convert(param2, property.PropertyType)),
param1, param2).Compile();
}
Но я уверен, что это непроблема с этими установщиками, потому что код C # используется очень широко, и это единственный вызов базы данных, где происходит эта 1,5-секундная задержка.
Запрос к базе данных выглядит примерно так, когда он встроен, и хранимая процедура довольноочень похоже:
DECLARE @startValue varchar(20) = NULL
DECLARE @endValue varchar(20) = NULL
SELECT MyView.*, OtherTable.Name
FROM MyView
INNER JOIN OtherTable ON MyView.PK = OtherTable.PK
WHERE (MyView.Value3 > 0 OR MyView.Value4 > 0)
AND (@startValue IS NULL OR MyView.Value1 >= @startValue)
AND (@endValue IS NULL OR MyView.Value1 <= @endValue)
Что может быть причиной задержки ~ 1,5 секунды в читателе evровно 75 записей?