Подтвердить что ты не робот

Вставьте время запроса в веб-приложение С#, отлично работает с SQL Server Management Studio

Я пытаюсь получить запрос на вставку для запуска из моего веб-приложения С#. Когда я запускаю запрос из SQL Server Management Studio, запрос на ввод занимает около пяти минут. При запуске из приложения он истекает через тридцать минут (да минут, а не секунд).

Я захватил фактический оператор SQL из отладчика VS и запустил его из Mgmt Studio, и он отлично работает.

Все это выполняется из моей среды разработки, а не из рабочей среды. Во время выполнения запроса нет других действий SQL Server. Я использую SQL Server 2008 R2 для разработки. MS VS 2010 Express, Asp.Net 4.0. SQL Server Mgmt Studio 10.

Есть аналогичный вопрос, на который никогда не отвечали: SQL Server timeout 2000 из С#.NET

Здесь параметры SET: dbcc useroptions

Option                  MgtStudio      Application
----------------------- -------------- --------------
textsize                2147483647     -1
language                us_english     us_english
dateformat              mdy            mdy
datefirst               7              7
lock_timeout            -1             -1
quoted_identifier       SET            SET
arithabort              SET            NOT SET
ansi_null_dflt_on       SET            SET
ansi_warnings           SET            SET
ansi_padding            SET            SET
ansi_nulls              SET            SET
concat_null_yields_null SET            SET
isolation level         read committed read committed

Только textize и arithabort различаются.

Любые идеи, почему существует такая разница во времени выполнения запроса и что я могу сделать, чтобы сузить эту разницу?

Я не уверен, насколько полезен, в том числе и запрос, тем более, что было бы слишком сложно включить схему. Во всяком случае, вот оно:

INSERT INTO GeocacherPoints
            (CacherID,
             RegionID,
             Board,
             Control,
             Points)
SELECT z.CacherID,
       z.RegionID,
       z.Board,
       21,
       z.Points
FROM   (SELECT CacherID,
               gp.RegionID,
               Board=gp.Board + 10,
               ( CASE
                   WHEN (SELECT COUNT(*)
                         FROM   Geocache g
                                JOIN GeocacheRegions r
                                  ON ( r.CacheID = g.ID )
                         WHERE  r.RegionID = gp.RegionID
                                AND g.FinderPoints >= 5) < 20 THEN NULL
                   ELSE (SELECT SUM(y.FinderPoints) / 20
                         FROM   (SELECT x.FinderPoints,
                                        ROW_NUMBER() OVER (ORDER BY x.FinderPoints DESC, x.ID) AS Row
                                 FROM   (SELECT g.FinderPoints,
                                                g.ID
                                         FROM   Geocache g
                                                JOIN Log l
                                                  ON ( l.CacheID = g.ID )
                                                JOIN Geocacher c
                                                  ON ( c.ID = l.CacherID )
                                                JOIN GeocacheRegions r
                                                  ON ( r.CacheID = g.ID )
                                         WHERE  YEAR(l.LogDate) = @Year
                                                AND g.FinderPoints >= 5
                                                AND c.ID = gp.CacherID
                                                AND r.RegionID = gp.RegionID) x) y
                         WHERE  y.Row <= 20)
                 END ) Points
        FROM   GeocacherPoints gp
               JOIN Region r
                 ON r.RegionID = gp.RegionID
        WHERE  gp.Control = 21
               AND r.RegionType IN ( 'All', 'State' )
               AND gp.Board = @Board - 10) z
WHERE  z.Points IS NOT NULL
       AND z.Points >= 1 
4b9b3361

Ответ 1

ARITHABORT часто ошибочно определяется как причина.

Фактически с версии 2005, когда ANSI_WARNINGS включен (как и в ваших соединениях) ARITHABORT неявно в любом случае, и этот параметр не имеет реального эффекта.

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

План выполнения, кэшированный для вашего приложения, не может быть повторно использован при запуске запроса в SSMS, за исключением того, что оба они имеют один и тот же ключ кеша плана, поэтому он получает новый план, скомпилированный, который "обнюхивает" значения параметров, которые в настоящее время тестируются. План для вашего приложения, скорее всего, был скомпилирован для разных значений параметров. Эта проблема известна как "обнюхивание параметров".

Вы можете получить и сравнить оба плана выполнения с чем-то вроде

SELECT usecounts, cacheobjtype, objtype, text, query_plan, value as set_options
FROM sys.dm_exec_cached_plans 
CROSS APPLY sys.dm_exec_sql_text(plan_handle) 
CROSS APPLY sys.dm_exec_query_plan(plan_handle) 
cross APPLY sys.dm_exec_plan_attributes(plan_handle) AS epa
where text like '%INSERT INTO GeocacherPoints (CacherID,RegionID,Board,Control,Points)%' 
and attribute='set_options' and text not like '%this query%'

Раздел параметров в XML сообщает вам значение времени компиляции параметров.

См. Медленное приложение, быстро в SSMS? Понимание тайн производительности для более.

Планы выполнения

Вы предоставили оценочные планы выполнения, а не фактические планы выполнения, но видно, что только первый план запроса параметризуется, и он был скомпилирован для следующих значений.

        <ParameterList>
          <ColumnReference Column="@Dec31" ParameterCompiledValue="'2013-12-31'" />
          <ColumnReference Column="@Jan1" ParameterCompiledValue="'2013-01-01'" />
          <ColumnReference Column="@Board" ParameterCompiledValue="(71)" />
        </ParameterList>

Второй план выполнения использует переменные, а не параметры. Это существенно меняет ситуацию.

DECLARE @Board INT
DECLARE @Jan1 DATE
DECLARE @Dec31 DATE

SET @Board=71
SET @Jan1='January 1, 2013'
SET @Dec31='December 31, 2013'

INSERT INTO GeocacherPoints

SQL Server не нюхает определенное значение переменных и генерирует общий план, аналогичный использованию OPTIMIZE FOR UNKNOWN подсказки. Оценочные подсчеты строк в этом плане намного выше, чем в первом плане.

Вы не указываете, что является быстрым планом, и это медленный план. Если тот, у кого есть переменные, быстрее, то, вероятно, вам нужно обновить статистику, вы можете столкнуться с проблемой, описанной здесь. Статистика, оценки строк и столбец с возрастающей датой если тот, который использует параметры, будет быстрее, вы сможете достичь переменного нюхания и заставить его принимать во внимание фактические значения переменных с помощью подсказки OPTION (RECOMPILE).

Ответ 2

Если вы используете SqlCommand, и вы не указываете значение для CommandTimeout, он автоматически истечет через 30 секунд.