Comment COMMANDER PAR un paramètre?

16

Je me demandais simplement si je pouvais solliciter des commentaires sur une procédure stockée que j'exécute et s'il existe un moyen plus efficace de gérer le scénario (je suis sûr qu'il y en aura!).

Fondamentalement, j'ai un seul SP que j'appelle pour renvoyer une liste d'enregistrements (Jobs) qui peuvent avoir un ou plusieurs statuts et un ordre de tri (j'utilise RowNum pour la pagination). En ce moment j'utilise WITH RECOMPILE car les variations sur les statuts peuvent changer tout le temps (selon l'utilisateur etc). Il y a aussi du filtrage.

J'utilise une instruction IF pour exécuter essentiellement le même bit de code, le seul changement étant l'ordre de tri.

Je suppose que mes questions sont les suivantes: existe-t-il une meilleure façon de procéder (peut-être différents SP pour différents statuts)? Suis-je en train de trop compliquer les choses en raison d'un manque de connaissances (très probablement) Le SP est-il vraiment correct, mais nécessite des ajustements mineurs pour réduire le nombre de lignes?

J'ai collé une partie du SP ci-dessous - la seule différence avec le code complet est les instructions IF supplémentaires pour les différents ordres de tri ...

J'apprécierais toute rétroaction.

Merci d'avance!

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 pour un autre tri des colonnes

VaticNZ
la source

Réponses:

16

Le tri peut être pris en charge avec une expression CASE, quelque chose comme:

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

Vous voudrez peut-être reconsidérer l'OR où les conditions sont susceptibles de générer de mauvais plans. L'un des meilleurs articles que j'ai lu sur ce sujet (et les approches alternatives) est conditions de recherche dynamiques dans T-SQL

Modifier: En examinant à nouveau votre liste de paramètres, les filtres principaux semblent être @CustomerId et @UserId. Je suggère de créer deux procs, spJobs_SelectByCustomerId et spJobs_SelectByUserId, qui filtrent en fonction de leurs paramètres respectifs afin d'éliminer les conditions '@Param = 0 ou Column = @Param'. Je suppose que le prochain paramètre important est @ShowCompleted (en supposant qu'une fois qu'un travail est `` terminé '', il n'est pas affiché sauf si @ ShowCompleted = 1), que je considérerais d'inclure dans les index sur CustomerId et UserId.

Edit2: C'est marrant comme ces questions viennent parfois à l'esprit! :) Lors de l'indexation de @ShowCompleted, c'est l'une des occasions où l' utilisation d'une colonne BIT à faible sélectivité peut être la meilleure stratégie . Les index filtrés doivent également être pris en compte.

Mark Storey-Smith
la source
Wooosh! Tout droit au-dessus de ma tête, mais je n'ai pas peur de lire et d'apprendre! Merci Mark d'avoir pris le temps de répondre. Il est en effet drôle de voir comment le subconscient continue de travailler à travers ces choses. Je trouve aussi la bière et la nicotine utiles :)
VaticNZ
Si quelque chose doit être clarifié, n'hésitez pas à étendre votre question ou à commencer un nouveau message.
Mark Storey-Smith
1
Merci Mark. J'ai mis en œuvre certaines de vos suggestions et tout va bien sauf un problème étrange ... J'ai posté sur un autre fil: dba.stackexchange.com/questions/4162/…
VaticNZ
Mon mauvais, n'a pas expliqué que vous devez gérer différents types d'expressions de casse séparés. Vous avez ajouté une réponse à votre nouvelle question.
Mark Storey-Smith,
cette solution ( CASEbasée sur) ne génèrera-t-elle pas aussi un mauvais plan d'exécution? Cela ne CASEsera- t-il pas évalué pour chaque ligne?
Andrei Rînea