Як ви ЗАМОВЛЮєте за параметром?


16

Мені цікаво, чи можу я попросити відгук про збережену процедуру, яку я запускаю, і чи є більш ефективний спосіб управління сценарієм (я впевнений, що це буде!).

В основному у мене є одне СП, яке я закликаю повернути список записів (Вакансії), які можуть мати один або більше статусів і порядку сортування (я використовую RowNum для підкачки). На даний момент я використовую RECOMPILE, тому що зміни статусів можуть змінюватися постійно (залежно від користувача тощо). Також відбувається деяка фільтрація.

Я використовую оператор IF, щоб по суті запустити той самий біт коду, єдиною зміною є порядок сортування.

Я думаю, мої запитання: Чи є кращий спосіб зробити це (можливо, різні ІП для різних статусів)? Чи я надмірно ускладнюю речі через брак знань (цілком ймовірно) Чи справді 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 для іншого сортування стовпців

Відповіді:


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-колонки з низькою селективністю вперше може стати найкращою стратегією . Також слід враховувати відфільтровані індекси .


Вуош! Все прямо над головою, але я не боюся читати та вчитися! Дякую Марку, що знайшли час для відповіді. Дійсно смішно, як підсвідомість продовжує працювати через ці речі. Я знаходжу також пиво та нікотин, щоб допомогти :)
VaticNZ

Якщо що-небудь потребує роз'яснення, не соромтесь поставити своє запитання або почати нову публікацію.
Марк Сторі-Сміт

1
Спасибі Марку. Я реалізував деякі ваші пропозиції, і все добре, крім дивної проблеми ... Я розмістив іншу тему: dba.stackexchange.com/questions/4162/…
VaticNZ

Мій поганий, не пояснив, що вам доведеться мати справу з різними типами в окремих виразах відмінків. Ви додали відповідь на ваше нове запитання.
Марк Сторі-Сміт

це рішення не буде (CASE основі) породжувати поганий план виконання? Чи не буде це CASEоцінено для кожного ряду?
Андрій Ронеа
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.