2013-05-06 2 views
0

Я написал довольно простую хранимую процедуру, которая принимает некоторые данные, выбирает значение, вставляет пару записей и затем возвращает это значение. Но выполнение слишком велико в нашей производственной среде, где я, возможно, в конечном итоге захочу, чтобы он запускал несколько сотен тысяч раз в день, и это отрицательно влияет на другие процессы, даже когда мы его запускаем только 30000 раз.Могу ли я улучшить производительность этого запроса или получить тот же результат с помощью более эффективного процесса?

Я начал с рассмотрения запросов и добавления индекса в поле даты, которое используется в предложениях where. Затем я запустил SQL Server Profiler - подачу результатов в Tuning Advisor и реализацию предложений по индексированию, с которыми он столкнулся. Раньше я видел, что этот инструмент вызывал действительно уродливые индексы, но на этот раз он просто хотел получить одно добавление, и я добавил его. Каждый из этих шагов помог. Но все еще слишком медленно.

Было легко понять, что первым запросом был захват, а не две вставки, где почти мгновенно. Так вот что я имел в то время, в том числе подзапросов времен хода:

--all combined, this typically takes in the range of 1200-1500 ms but occasionally spikes up to ~2200 ms 
select coalesce(
    ( 
     --when the following is run, this takes ~690 ms 
     select MIN(maxes.imbsn) 
     from (
      --when the following is run without the higher limiting scopes, this takes ~3600 ms 
      select imbsn, MAX(assignmentDate) maxAD 
      from imbsnAssignments 
      group by imbsn 
      ) maxes 
     where datediff(d, maxes.maxAD, GETDATE()) > 90 
    ) 
    , 
    (
     --this is rarely executed but takes ~0 ms when it is 
     select max(imbsn)+1 from imbsnAssignments 
    ) 
) 

Основываясь на те времена, казалось, что сливается был отвод вещи (это то, что я себе представить, я мог проверить с исполнением план, если бы я когда-либо выяснял, как его читать, но у меня нет - планы остаются в основном непрозрачными для моего бедного мозга). Чтобы избавиться от коалесценции, я изменил запрос на:

--this runs ~480-700 ms 
select MIN(maxes.imbsn) 
from (
    select imbsn, MAX(assignmentDate) maxAD 
    from imbsnAssignments 
    group by imbsn 
     union 
    select max(imbsn)+1, getDate() 
    from imbsnAssignments 
    ) maxes 
where datediff(d, maxes.maxAD, GETDATE()) > 90 

, что является большим улучшением. Но это все еще довольно медленно.

Я проверил, что советник по настройке профилировщика все еще не хотел, чтобы я вносил какие-либо изменения, прежде чем приходить сюда, чтобы спросить вас об этом. Я думаю, что это оставляет мне два подхода: 1) поддерживать базовый алгоритм, но сжимать большую эффективность из него или 2) переключиться на какой-то более умный способ получить тот же базовый эффект с помощью методов, о которых я не знаю, но одно будет очевидно к одному из вас, крупным мозгам, которые вынюхивают, что я занимаюсь каким-то анти-узором здесь.

Заранее благодарим за внимание и внимание!


Я не совсем уверен, какой ожидаемый формат для этой дополнительной информации, но я попробую. Стол:

CREATE TABLE [dbo].[imbsnAssignments](
    [id] [int] IDENTITY(1,1) NOT NULL, 
    [imbsn] [int] NOT NULL, 
    [assignmentDate] [date] NOT NULL, 
    [jobCode] [varchar](10) NOT NULL, 
    [name] [varchar](45) NOT NULL, 
    [a1] [varchar](45) NOT NULL, 
    [a2] [varchar](45) NOT NULL, 
    [a3] [varchar](45) NOT NULL, 
    [a4] [varchar](45) NOT NULL, 
    [city] [varchar](40) NOT NULL, 
    [state] [char](10) NOT NULL, 
    [zip] [varchar](10) NOT NULL, 
    [batchIdent] [varchar](256) NOT NULL, 
CONSTRAINT [PK_imbsnAssignments] PRIMARY KEY CLUSTERED 
(
    [id] ASC 
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] 
) ON [PRIMARY] 

, и я подозреваю, что это не 'правильный' способ показать индексы, но:

TableName   IndexName           IndexType 

imbsnAssignments  PK_imbsnAssignments        CLUSTERED 
imbsnAssignments  IX_imbsnAssignments_assignmentDate     NONCLUSTERED 
imbsnAssignments  _dta_index_imbsnAssignments_36_149575571__K2_3  NONCLUSTERED 

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

|--Stream Aggregate(DEFINE:([Expr1013]=MIN([partialagg1018]))) 
     |--Concatenation 
      |--Stream Aggregate(DEFINE:([partialagg1018]=MIN([IMB].[dbo].[imbsnAssignments].[imbsn]))) 
      | |--Filter(WHERE:([Expr1003]<dateadd(day,(-90),getdate()))) 
      |   |--Stream Aggregate(GROUP BY:([IMB].[dbo].[imbsnAssignments].[imbsn]) DEFINE:([Expr1003]=MAX([IMB].[dbo].[imbsnAssignments].[assignmentDate]))) 
      |    |--Index Scan(OBJECT:([IMB].[dbo].[imbsnAssignments].[_dta_index_imbsnAssignments_36_149575571__K2_3]), ORDERED FORWARD) 
      |--Stream Aggregate(DEFINE:([partialagg1018]=MIN([Expr1009]))) 
       |--Compute Scalar(DEFINE:([Expr1009]=[Expr1008]+(1))) 
         |--Stream Aggregate(DEFINE:([Expr1008]=MAX([IMB].[dbo].[imbsnAssignments].[imbsn]))) 
          |--Top(TOP EXPRESSION:((1))) 
           |--Index Scan(OBJECT:([IMB].[dbo].[imbsnAssignments].[_dta_index_imbsnAssignments_36_149575571__K2_3]), ORDERED BACKWARD) 
+0

Вы пробовали UNION все? Ваши профсоюзные запросы выглядят так, как будто они взаимно исключают мне. – HLGEM

+0

Опубликуйте план запроса и определение таблицы, включая любые ключи и индексы. – RBarryYoung

+0

Вы можете задать этот вопрос на странице [Обзор кода] (http://codereview.stackexchange.com/). – Jesse

ответ

1

Первый Я бы предложил взять ваше предложение где-то ближе к фактической таблице в вашем втором примере, и я бы проверил план выполнения, чтобы посмотреть, что он делает, может быть, расчет т. е. 90 дней назад проверяют его, а не DATEDIFF каждое значение maxAD. И просто позвольте изменить объединение на объединение, чтобы не было необходимости проверять уникальность между наборами данных.

select MIN(maxes.imbsn) 
from (
    select imbsn, MAX(assignmentDate) maxAD 
    from imbsnAssignments 
    group by imbsn 
    having max(assignmentdate) < dateadd(-90, d, GETDATE()) 
     union all 
    select max(imbsn)+1, getDate() 
    from imbsnAssignments 
) maxes 
+0

строка, которая должна иметь следующую строку: 'max (присваивание) clweeks

+0

Это замечательно; благодаря! Я протестировал каждый из трех предложенных вами изменений, и они были ценны. Интересно, что одна из вещей, которые я пробовал самостоятельно в этой первой версии запроса, заключалась в том, чтобы перенести место внутри на наличие, но это не изменило время выполнения. Теперь это ясно. – clweeks

+0

Похоже, что они равны примерно 10-12% -ному снижению времени выполнения. – clweeks

Смежные вопросы