Как вы заказываете параметр?

16

Просто интересно, смогу ли я получить какие-либо отзывы о хранимой процедуре, которую я использую, и есть ли более эффективный способ обработки сценария (я уверен, что так и будет!).

По сути, у меня есть один SP, который я вызываю, чтобы вернуть список записей (заданий), которые могут иметь один или несколько статусов и порядок сортировки (я использую RowNum для пейджинга). В настоящее время я использую WITH RECOMPILE, потому что изменения в статусах могут меняться все время (в зависимости от пользователя и т. Д.). Там также происходит некоторая фильтрация.

Я использую оператор IF, чтобы, по сути, выполнить тот же бит кода, единственное изменение - порядок сортировки.

Я думаю, мои вопросы: есть ли лучший способ сделать это (возможно, разные SP для разных статусов)? Я слишком усложняю вещи из-за недостатка знаний (вполне вероятно) Действительно ли SP в порядке, но требует незначительных настроек, чтобы уменьшить количество строк?

Я вставил часть SP ниже - единственное отличие от полного кода - это дополнительные операторы IF для различных порядков сортировки ...

Буду признателен за любые отзывы.

Заранее спасибо!

PROCEDURE [dbo].[sp_Jobs] 

@PageNumber int, 
@PageSize int, 
@FilterExpression varchar(500), 
@OrderBy varchar(50), 
@CustomerID int, 
@ShowNotSet bit, 
@ShowPlaced bit, 
@ShowProofed bit, 
@ShowReProofed bit, 
@ShowApproved bit, 
@ShowOnTime bit, 
@ShowLate bit, 
@ShowProblem bit, 
@ShowCompleted bit, 
@ShowDispatched bit, 
@ShowUnapproved bit, 
@ShowClosed bit, 
@ShowReturned bit, 
@UserID int

WITH RECOMPILE 

AS

--JobNumber DESC 
if @OrderBy='JobNumberDESC' 
BEGIN 

WITH Keys AS (SELECT TOP (@PageNumber * @PageSize) ROW_NUMBER() OVER (ORDER BY JobNumber DESC) as rn,P1.jobNumber,P1.CustID,P1.DateIn,P1.DateDue,P1.DateOut,p1.client,p1.MasterJobStatusID,p1.MasterJobStatusTimestamp,p1.OwnerID 

FROM 
vw_Jobs_List P1 WITH (NOLOCK) 

WHERE 
(@CustomerID = 0 OR CustID = @CustomerID) 
AND (@UserID = 0 OR OwnerID = @UserID) 
AND ((@ShowNotSet = 1 AND MasterJobStatusID=1) OR (@ShowPlaced = 1 AND MasterJobStatusID=2) OR (@ShowProofed = 1 AND MasterJobStatusID=3) OR (@ShowReProofed = 1 AND MasterJobStatusID=4) OR (@ShowApproved = 1 AND MasterJobStatusID=5) OR (@ShowOnTime = 1 AND MasterJobStatusID=6) OR (@ShowLate = 1 AND MasterJobStatusID=7) OR (@ShowProblem = 1 AND MasterJobStatusID=8) OR (@ShowCompleted = 1 AND MasterJobStatusID=9) OR (@ShowDispatched = 1 AND MasterJobStatusID=10) OR (@ShowUnapproved = 1 AND MasterJobStatusID=11) OR (@ShowClosed = 1 AND MasterJobStatusID=12) OR (@ShowReturned = 1 AND MasterJobStatusID=13)) AND (Search LIKE '%'+@FilterExpression+'%')

ORDER BY 
P1.JobNumber DESC ),SelectedKeys AS (
SELECT TOP (@PageSize)SK.rn,SK.JobNumber,SK.CustID,SK.DateIn,SK.DateDue,SK.DateOut 

FROM 
Keys SK 

WHERE 
SK.rn > ((@PageNumber-1) * @PageSize) 

ORDER BY 
SK.JobNumber DESC) 

SELECT SK.rn,J.JobNumber,J.OwnerID,J.Description,J.Client,SK.CustID,OrderNumber, CAST(DateAdd(d, -2, CAST(isnull(SK.DateIn,0) AS DateTime)) AS nvarchar) AS DateIn, CAST(DateAdd(d, -2, CAST(isnull(SK.DateDue,0) AS DateTime)) AS nvarchar) AS DateDue,CAST(DateAdd(d, -2, CAST(isnull(SK.DateOut,0) AS DateTime)) AS nvarchar) AS DateOut, Del_Method,Ticket#, InvoiceEmailed, InvoicePrinted, InvoiceExported, InvoiceComplete, JobStatus,j.MasterJobStatusID,j.MasterJobStatusTimestamp,js.MasterJobStatus 

FROM SelectedKeys SK JOIN vw_Jobs_List J WITH (NOLOCK) ON j.JobNumber=SK.JobNumber JOIN tbl_SYSTEM_MasterJobStatus js WITH (NOLOCK) ON j.MasterJobStatusID=js.MasterJobStatusID 

ORDER BY 
SK.JobNumber DESC 
END

--ELSE IF для сортировки других столбцов

VaticNZ
источник

Ответы:

16

С сортировкой можно позаботиться с помощью выражения CASE, что-то вроде:

ORDER BY
    CASE WHEN @SortDirection = 'A' THEN
        CASE 
           WHEN @SortBy = 'JobNumber' THEN JobNumber
           WHEN @SortBy = 'JobId' THEN JobId 
        END
    END ASC
    , CASE WHEN @SortDirection = 'D' THEN
        CASE 
           WHEN @SortBy = 'JobNumber' THEN JobNumber
           WHEN @SortBy = 'JobId' THEN JobId 
        END
    END DESC

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

Изменить: Снова глядя на список параметров, первичные фильтры выглядят как @CustomerId и @UserId. Я бы предложил создать два процесса, spJobs_SelectByCustomerId и spJobs_SelectByUserId, которые фильтруют по их соответствующим параметрам, поэтому вы устраняете условия «@Param = 0 или Column = @Param». Я предполагаю, что следующим важным параметром является @ShowCompleted (при условии, что после того, как работа «выполнена», она не отображается, если только @ ShowCompleted = 1), которую я хотел бы включить в индексы CustomerId и UserId.

Edit2: Забавно, как эти вопросы иногда всплывают у вас в голове! :) При индексировании @ShowCompleted это один из случаев, когда использование BIT-столбца с низкой селективностью может быть лучшей стратегией . Отфильтрованные индексы также должны быть рассмотрены.

Марк Стори-Смит
источник
Wooosh! Все прямо над головой, но я не боюсь читать и учиться! Спасибо Марк, что нашли время ответить. Это действительно забавно, как подсознание продолжает работать через эти вещи. Мне тоже помогают пиво и никотин :)
VaticNZ
Если что-то нуждается в разъяснении, не стесняйтесь расширить свой вопрос или начать новый пост.
Марк Стори-Смит
1
Спасибо Марк. Я реализовал некоторые из ваших предложений, и все хорошо, кроме странной проблемы ... Я написал в другой ветке: dba.stackexchange.com/questions/4162/…
VaticNZ
Мой плохой, не объяснил, что вам приходится иметь дело с разными типами в отдельных выражениях. Добавили ответ на ваш новый вопрос.
Марк Стори-Смит
не приведет ли это решение (на CASEоснове) к плохому плану выполнения? Разве это не CASEбудет оцениваться для каждой строки?
Андрей Ринея,