Простой тайм-аут запросов только в .net SqlDataAdapter - PullRequest
1 голос
/ 25 марта 2011

Хорошо, у меня есть этот запрос, который занимает 2-5 секунд для запуска в Sql Management Studio.Но когда я запускаю его через приложение .net, он превышает CommandTimeout 5 минут каждый раз.

Я знаю, что код .net работает, потому что этот же код (ниже) прекрасно выполняет другие запросы,и доставляет результаты.

public DataTable ExecuteQuery()
    {
        DataTable result = new DataTable();
        FoSqlConn con = new FoSqlConn(ConnectionToUse, ApplicationName); // connection string factory
        List<string> parameterNames = GetAllParametersFromQueryString(QueryString);
        using (SqlConnection sqlCon = new SqlConnection(con.GetConnectionString()))
        {
            using (SqlCommand cmd = new SqlCommand(QueryString, sqlCon))
            {
                if (DefaultTimeout.HasValue == true)
                {
                    cmd.CommandTimeout = DefaultTimeout.Value;
                }
                foreach (string paramName in parameterNames)
                {
                    if (Context.ParameterExists(paramName))
                    {
                        cmd.Parameters.AddWithValue(paramName, Context.GetParameterByName(paramName));
                    }
                    else
                    {
                        cmd.Parameters.AddWithValue(paramName, DBNull.Value);
                    }
                }
                sqlCon.Open();
                using (SqlDataAdapter adapter = new SqlDataAdapter(cmd))
                {
                    adapter.Fill(result);
                }
                if (sqlCon.State == ConnectionState.Open)
                {
                    con.CloseConnection();
                }
            }
        }

        return result;
    }

Ниже приведен запрос, но таблицы переименованы:

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
IF (@StartDate IS NULL)
BEGIN 
    SET @StartDate = DATEADD(Day, -60, GETDATE())
END 

IF (@EndDate IS NULL)
BEGIN
    SET @EndDate = DATEADD(DAY, -1, GETDATE())
END

SELECT
    P.ProductionObjDimId
    ,Dim.ProductionObjSourceId
    ,Dim.Name as WellName
    ,Dim.CurrentStatus
    ,Dim.ApiCode
    ,Dim.CurrentType
    ,Dim.StateProvidenceCode
FROM 
    ProductionDetail as P with(nolock)

JOIN DataWarehouse.dbo.ProductionObjMetaData as M
ON  P.ProductionObjDimId = M.ProductionObjDimId
AND M.OperationType = 1

JOIN DataWarehouse.dbo.ProductionObjDim as Dim
ON P.ProductionObjDimId = Dim.ProductionObjDimId

LEFT OUTER JOIN ProductionForecastingLinksView as Forcast
ON  Dim.ProductionObjSourceId = Forcast.comp_sk
AND Forcast.StartDate <= @EndDate
AND Forcast.EndDate > @StartDate

LEFT OUTER JOIN DataWarehouse.dbo.ForecastingUpload as Upload
ON Forcast.propnum = Upload.ForecastingWellSourceId
AND Upload.StartDate <= @EndDate
AND Upload.EndDate > @StartDate
AND (Upload.UploadDaily = 1 OR Upload.UploadMonthly = 1)
WHERE 
    P.ProductionDate >= @StartDate
AND
    Upload.ForecastingWellSourceId IS NULL
GROUP BY
    P.ProductionObjDimId
    ,Forcast.propnum        
    ,Dim.ProductionObjSourceId
    ,Dim.Name
    ,Dim.CurrentStatus
    ,Dim.ApiCode
    ,Dim.CurrentType
    ,Dim.StateProvidenceCode
Having 
    SUM(P.GrossOilProduction) > 0
OR  SUM(P.GrossGasSale) > 0
order by WellName

Пожалуйста, помогите, я в полном недоумении, почему этот запрос имеет проблемы.

ОБНОВЛЕНИЕ (старое, найдено, хотя приведенное ниже является интересным, проблема не вызывает) Итак, я запустил трассировку, ища запрос, он появился, когда я запустил запросвручную, но когда я запустил его через код, он вообще не появлялся и получил то же сообщение об ошибке.Поэтому я действительно посмотрел на строку подключения и заметил нечто странное.Во время передачи имени пользователя и пароля в свойстве ConnectionString объекта SqlConnection отсутствовал пароль.Я не знаю, указывает ли это на решение, но сейчас я в замешательстве.

ОБНОВЛЕНИЕ # 2 Я не позволил трассировке пройти достаточно долго.Я смог перехватить звонок, который был очень длинным.

exec sp_executesql N'SET TRANSACTION ISOLATION...[SAME CODE AS ABOVE]' ,@StartDate=NULL,@EndDate=NULL   

Выполняя этот точный запрос, я получаю тот же результат (на самом деле он завершается, просто требуется 5+ минут, чтобы запустить его с помощью этого метода, а не 3 секунды, когда запрос выполняется напрямую). Примечание Я попытался запустить запрос с параметрами, указанными как nvarchar (4000), но просто выполнение запроса в Sql Management Studio работает нормально.

UPDATE # 3 Я обновил статистику для всех таблиц, которые объединены в запросе, не повезло.Запрос sp_executeSQL по-прежнему занимает около 5 минут (это примерно на 30 секунд меньше, чем до перестройки статистики).На данный момент я в растерянности.Есть идеи?

ОБНОВЛЕНИЕ # 4 наконец-то нашли решение!проблема была из-за «Обнаружения параметра», который я использовал, если условия предшествовали моему запросу генерации результата.механизм плана выполнения предполагал, что параметры, если они передаются как нулевые, будут попадать в запрос как нулевые, что не соответствует действительности.Они всегда будут иметь ценность.Чтобы исправить проблему, я удалил условия if в начале запроса и поместил проверки ISNULL везде, где использовался параметр.это уведомило план выполнения о моих намерениях, и вызов sp_executeSQL выполнялся с той же скоростью, что и выполнение моего Sql Management Studio.Спасибо всем за помощь!

Ответы [ 2 ]

1 голос
/ 25 марта 2011

Это почти наверняка неверно кэшированный план запроса (это классический признак). Это часто является результатом устаревшей статистики.

Я предлагаю вам обновить статистику .

Один из способов проверить, является ли статистика «перекошенной» или устаревшей, состоит в том, чтобы выполнить запрос с включенным планом фактического выполнения, а затем проверить предполагаемые строки в сравнении с фактическими строками в каждом операторе.

ОБНОВЛЕНИЕ (в ответ на комментарии): Вы можете попробовать перестроить все ваши индексы. В качестве последнего средства вы можете попробовать пометить хранимую процедуру AS RECOMPILE, что, по сути, и происходит при запуске через SQL Server Management Studio (SSMS). Это окончательно определит, является ли это неподходящим планом кэшированных запросов. Если это так, то можно пометить сохраненный процесс с помощью OPTIMIZE FOR.

1 голос
/ 25 марта 2011

Попробуйте протестировать с помощью SQL Profiler.

Проверьте, не поступила ли команда sql в базу данных, если вы считаете, что это происходит и не задерживается.

Кроме того, проверьте фактический текст запроса, полученный базой данных, а затем запустите этот текст в Management Studio. Возможно, база данных получает что-то не совсем то, что вы ожидаете.

...