See below stored procedure.
It is in use by an app which does searches takes user input for orders and displays them. Most of the time, it returns the expected results in a few seconds. However, when a specific vendor is searched for, it returns the answer in 5-10 seconds. If it includes @vendorsOnly = true, then it is very fast. If @vendorsOnly = 0, then it is slow.
I have tried putting an index on the VendorId, and that seemed to help for a while, but it is running slow again.
I think there is an optimization issue here, but I am not sure what should be done.
ALTER PROCEDURE [dbo].[SearchOrderInfos_v21]
(
@orderId int = null,
@customerFileNo nvarchar(max) = null,
@orderDate Date = null,
@countyId nvarchar(max) = null,
@clientName nvarchar(max) = null,
@orderStatusId int = null,
@vendorId int = null,
@vendorETA nvarchar(max) = null,
@dueDate DateTime = null,
@guid nvarchar(max) = null,
@orderStatusCsv nvarchar(max) = null,
@researcherOrManagerId nvarchar(max) = null,
@vendorsOnly bit = false,
@researchersOnly bit = false,
@includeDeletedRows bit = 0,
@researcherId nvarchar(max) = null,
@managerId nvarchar(max) = null,
@allowViewArchive bit = 0
)
AS
BEGIN
declare @timeZone varchar(25) = 'Eastern Standard Time' -- bake it in!
SET NOCOUNT ON
BEGIN
Select top (Select ts.MaxRecords from TableSettings ts where ts.TableName = 'Order')
O.*,
C.CountyName,
CU.DisplayName AS CustomerName,
OS.OrderStatus,
SR.Code AS SearchRequestCode,
IsNull(V.DisplayName, V.CompanyName) AS Vendor,
V.EmailAddress,
O.CustomerDueDate AS DueDate,
SP.StateProvinceName as StateProvince,
U.UserName as Manager,
M.UserName as Researcher
FROM [dbo].[Order] O
left JOIN [dbo].[County] C ON O.CountyId = C.CountyId
left JOIN [dbo].[Customer] CU ON O.CustomerId = CU.CustomerId
left JOIN [dbo].[OrderStatus] OS ON O.OrderStatusId = OS.OrderStatusId
left JOIN [dbo].[Vendor] V ON O.VendorId = V.VendorId
left JOIN [dbo].[SearchRequest] SR ON O.SearchRequestId = SR.SearchRequestId
left JOIN StateProvince SP ON SP.StateProvinceId = O.StateProvinceId
left join AspNetUsers U on U.Id = O.ManagerId
left join AspNetUsers M on M.Id = O.ResearcherId
WHERE
(@vendorsOnly = 0 or o.VendorId is not null) and
(@researchersOnly = 0 or O.ResearcherId is not null) and
(@orderId IS NULL OR O.OrderId = @orderId) AND
(@customerFileNo IS NULL OR O.CustomerFileNo LIKE '%' + trim(@customerFileNo) + '%') AND
(@orderDate IS NULL OR Cast(O.OrderDateTime at time zone @timeZone as Date) = @orderDate) AND
(@countyId IS NULL OR C.CountyId = @countyId) AND
(@clientName IS NULL OR CU.DisplayName LIKE '%' + trim(@clientName) + '%') AND
(@orderStatusId IS NULL OR OS.OrderStatusId = @orderStatusId) AND
(@vendorId IS NULL OR V.VendorId = @vendorId) AND
(@vendorETA IS NULL OR O.VendorETA LIKE '%' + trim(@vendorETA) + '%') AND
(@dueDate IS NULL OR O.CustomerDueDate = @dueDate) and
(@guid IS NULL OR O.Guid = @guid) and
( --If @researcherOrManagerId is not null, then ensure that the order is assigned to the id as Manager or Researcher
@researcherOrManagerId IS NULL or
(
O.ResearcherId = @researcherOrManagerId or
O.ManagerId = @researcherOrManagerId or
-- if @allowViewArchive is true, then allow to view if the Order in a status of Client Delivered.
(@allowViewArchive = 1 and O.OrderStatusId = 4) )
) and
(@researcherId is null or O.ResearcherId = @researcherId) and
(@managerId is null or O.ManagerId = @managerId) and
(@orderStatusCsv IS NULL or O.OrderStatusId in (Select value from STRING_SPLIT(@orderStatusCsv, ','))) and
(@includeDeletedRows = 1 or O.DeletedDate is null)
--order by OrderId -- For testing only
ORDER BY OS.SortOrder, O.OrderId DESC
end
END
Like mentioned in the comments, the easiest method to "fix" this would be to add
OPTION (RECOMPILE)
at the end of your statement, in this case this would go after theORDER BY
:As also, however, mentioned, if this SP is being run frequently, or generating the plan is costly itself, then using a dynamic approach is better, but is a much more complex solution. Taking your query, I believe the below would be the correct implementation, but I cannot test this. You will need to use your "best friend" to help you with that: