Как оптимизировать эту динамическую хранимую процедуру - PullRequest
1 голос
/ 16 ноября 2011

У меня есть хранимая процедура, которая извлекает данные, используя 20 таблиц.Пример процедуры:

     CREATE PROCEDURE GetEnquiries 
     (
        @EnquiryDate    DATETIME        = NULL
     )
     AS

     DECLARE @querySELECT           VARCHAR(MAX) = ''
     DECLARE @queryWHERE            VARCHAR(MAX) = ''
     DECLARE @queryExtraColumns     VARCHAR(MAX) = ''
     DECLARE @queryReturnResults    VARCHAR(MAX) = ''

     -----------------------------------------------------
     --Create temp table
     -----------------------------------------------------
     SET    @querySELECT = '
                CREATE  TABLE   #tempResults 
                (   
                    EnquiryId       INT, 
                    Cost            Decimal(18,2),
                    CustomerName    VARCHAR(50),
                    EnquiryStatus   VARCHAR(50),
                    ContactNumber   VARCHAR(50),
                    NumberOfVisits  INT 
                ) '

     -----------------------------------------------------
     --Insert into temp table
     -----------------------------------------------------  
     SET    @querySELECT = '            
                INSERT INTO #tempResults 
                (   
                    EnquiryId       , 
                    Cost            ,
                    CustomerName    ,
                    EnquiryStatus   ,
                    ContactNumber   
                ) '
     -----------------------------------------------------
     --SELECT
     -----------------------------------------------------
     SET    @querySELECT = '
            SELECT          
                    e.EnquiryId     , 
                    e.Cost          ,
                    c.CustomerName  ,
                    e.EnquiryStatus ,
                    c.ContactNumber 
            FROM    Enquiry e
                    INNER JOIN Customers c ON e.CustomerId = c.CustomerId '

     -----------------------------------------------------
     -- WHERE 
     -----------------------------------------------------
     IF(@EnquiryDate IS NOT NULL)
        BEGIN
            SET @queryWHERE = @queryWHERE + ' CONVERT(VARCHAR(10),e.EnquiryDate,23) >= '  + ''''+ CONVERT(VARCHAR(10),@EnquiryDate,23) + ''''
        END

     --- There are at least 14 parameters used in WHERE operation the above is just one of them
     -----------------------------------------------------
     -- Count NumberOfVisits
     -----------------------------------------------------
      SET   @queryExtraColumns = '
            ;WITH NumberOfVisits AS
            (
                SELECT  t.EnquiryId, COUNT(EnquiryId) AS NumberOfVisits 
                FROM    NumberOfVisits v 
                        INNER JOIN #tempResults t ON v.EnquiryId = t.EnquiryId
                GROUP   BY t.EnquiryId
            ) 


        UPDATE  #tempResults
        SET     NumberOfVisits = u.NumberOfVisits
        FROM    #tempResults t
                INNER JOIN NumberOfVisits u ON u.EnquiryId = t.EnquiryId

'

     -----------------------------------------------------
     -- return the results
     -----------------------------------------------------      
     SET    @queryReturnResults = '
            SELECT          
                    EnquiryId       , 
                    Cost            ,
                    CustomerName    ,
                    EnquiryStatus   ,
                    ContactNumber   ,
                    NumberOfVisits
            FROM    #tempResults t 
                     '

     -----------------------------------------------------
     -- Combine all the strings + DROP the temp table
     -----------------------------------------------------  
     -- PRINT(  @querySELECT + ' WHERE ' +  @queryWHERE + @queryExtraColumns +  @queryReturnResults + '  DROP TABLE #tempResults ') 
      EXEC( @querySELECT + ' WHERE ' +  @queryWHERE + @queryExtraColumns +  @queryReturnResults + '  DROP TABLE #tempResults ') 

Некоторые факты:

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

  • Я использую SQL Server 2008

  • Моя фактическая процедура имеет 15 параметров, все они используются в предложении WHERE.Если для параметра задано значение, этот параметр включается в предложение WHERE, в противном случае - нет.

  • Существует не менее 10 столбцов, значение которых получается из условия GROUP BY, например, "NumberOfVisits "указано в приведенной выше процедуре.

  • У меня есть индексы для всех первичных и внешних ключей.

  • У меня есть индексы для всехстолбцы, которые используются в предложении WHERE.

  • У меня есть индексы для всех столбцов, которые используются в предложении GROUP BY.

Вопросы :

  • Q1: Это в соответствии с передовой практикой для создания динамических хранимых процедур, следующих выше шаблону?

  • Q2: я получил выходной SQL этой процедуры, используя: - PRINT (@querySELECT + 'WHERE' + @queryWHERE + @queryExtraColumns + @queryReturnResults + 'DROP TABLE #tempResults'), когда я запускаю этот SQL, это заняло то же времячто было принято хранимой процедурой, почему?разве SQL не должен занимать меньше времени?почему нет никакой разницы?

  • Q3: Является ли приведенное выше рекомендацией для получения значения столбцов сводки ("NumberOfVisits")?

  • Q4: является ли приведенное выше наилучшим способом динамического создания предложения WHERE?

  • Q5: Можно ли избежать использования временной таблицы, используя альтернативу в приведенном выше сценарии?

  • Q6: Что я могу сделать, чтобы оптимизировать эту процедуру?

Пожалуйста, прости меня, если мой вопрос НЕ ясен или не является правильным вопросом.

Спасибо за ваше драгоценное время и помощь.

Ответы [ 2 ]

1 голос
/ 16 ноября 2011

Для динамических отчетов лучше настроить SSRS (службы отчетов SQL Server), которая является частью SQL Server 2005 по 2008 R2. Затем используйте BIDS для создания проекта модели данных для запуска построителя отчетов. Построитель отчетов поставляется с SSRS и представляет собой приложение, запускаемое нажатием одной кнопки.

В наши дни попытки идти в ногу с динамическими отчетами с помощью собственных запросов уже не так эффективны.

0 голосов
/ 17 ноября 2011

Этот же вопрос был также размещен мной на другом сайте. На этот вопрос ответил Grant Fritchey Вы можете увидеть ответ здесь Я скопировал ответ с этого сайта, см. Ниже:

Как правило, вместо построения и выполнения строки, которая может подвергаться атакам SQL-инъекций, я бы предложил создать строку с параметрами и использованием sp_executesql для его выполнения, обеспечивая параметры. Это больше работы, но это более безопасно, И это больше вероятно, улучшится повторное использование плана.

Нет, запрос является длинной частью выполнения. Строим несколько струны довольно безболезненно.

С точки зрения сводных столбцов, нет, это дополнительный проход. Вместо этого я бы выполнить объединение против суб-выбора (обычно, иногда нарушая его ступеньки могут работать лучше).

Неа. Смотри выше. sp_executesql лучше.

Да, спланируйте это как одно утверждение выбора. Временная таблица просто удержание для агрегации, которая может быть сделана как производная таблица.

Оптимизация? Более жесткий вопрос. Просто видя что у тебя есть, КОНВЕРТ заявление на e.EnquiryDate будет вызывать сканирование, несмотря ни на что. Если это столбец datetime, вам нужно сравнить его с datetime значение, без конверсий. Кроме того, я не мог сказать, не видя целые запросы, планы выполнения, данные, структура, все это.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...