Reputation: 331
I have added a left join to my stored procedure, but my query now takes 4 to 10 times longer to run even if I don't pass the parameters required for the join.
Here is my stored procedure:
USE [Test]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[OrderLoadAllPaged]
@OrderId int = 0,
@WarehouseId int = 0,
@PaymentMethodSystemName nvarchar(max) = null,
@OrderStatusId int = 0,
@PaymentStatusId int = 0,
@ShippingStatusId int = 0,
@BillingEmail nvarchar(max) = null,
@BillingFirstName nvarchar(max) = null,
@BillingLastName nvarchar(max) = null,
@ShippingMethod nvarchar(max) = null,
@CreatedFromUtc datetime = null,
@CreatedToUtc datetime = null
AS
BEGIN
DECLARE
@sql nvarchar(max)
SET NOCOUNT ON;
SELECT TOP 100 *
FROM [Test].[dbo].[Order] o with (NOLOCK)
LEFT join [Test].[dbo].[Address] a on (a.Id LIKE o.BillingAddressId)
WHERE (@BillingEmail IS null OR a.[Email] = @BillingEmail)
AND (@BillingFirstName IS null OR a.[FirstName] = @BillingFirstName)
AND (@BillingLastName IS null OR a.[LastName] = @BillingLastName)
AND
o.[Deleted] = 0
AND (o.[Id] = @OrderId OR @OrderId = 0)
AND (o.[WarehouseId] = @WarehouseId OR @WarehouseId = 0)
AND (@PaymentMethodSystemName IS null OR o.[PaymentMethodSystemName] = @PaymentMethodSystemName)
AND (o.[OrderStatusId] = @OrderStatusId OR @OrderStatusId = 0)
AND (o.[PaymentStatusId] = @PaymentStatusId OR @PaymentStatusId = 0)
AND (o.[ShippingStatusId] = @ShippingStatusId OR @ShippingStatusId = 0)
AND (@ShippingMethod IS null OR o.[ShippingMethod] = @ShippingMethod)
AND o.[CreatedOnUtc] >= ISNULL(@CreatedFromUtc, '1/1/1900')
AND o.[CreatedOnUtc] < ISNULL(@CreatedToUtc, '1/1/2999')
ORDER BY o.[CreatedOnUtc] DESC
END
So if I don't pass in @BillingEmail
, @BillingFirstName
or @BillingLastName
it's like the left join is still considered:
If I comment out the left join, my query is really quick again:
/*LEFT join [Test].[dbo].[Address] a on (a.Id LIKE o.BillingAddressId)
WHERE (@BillingEmail IS null OR a.[Email] = @BillingEmail)
AND (@BillingFirstName IS null OR a.[FirstName] = @BillingFirstName)
AND (@BillingLastName IS null OR a.[LastName] = @BillingLastName)*/
WHERE --need to change
o.[Deleted] = 0
How can I bypass that query all together, if @BillingEmail
, @BillingFirstName
or @BillingLastName
are all null.
I thought maybe something like this, but it's not right:
case
when (ISNULL(@BillingEmail) OR ISNULL(@BillingFirstName) OR ISNULL(@BillingLastName))
then
WHERE
o.[Deleted] = 0
ELSE
LEFT join [Test].[dbo].[Address] a on (a.Id LIKE o.BillingAddressId)
WHERE (@BillingEmail IS null OR a.[Email] = @BillingEmail) --LIKE '%' + @BillingEmail + '%'
AND (@BillingFirstName IS null OR a.[FirstName] = @BillingFirstName)
AND (@BillingLastName IS null OR a.[LastName] = @BillingLastName)
AND
o.[Deleted] = 0
end
I looked at indexes but I don't think I can create indexes for those 3 parameters. Any ideas how I can bypass that left join?
Upvotes: 0
Views: 147
Reputation: 27290
As an alternative you could keep it as a single query as follows:
SELECT TOP 100 *
FROM [Test].[dbo].[Order] o with (NOLOCK)
LEFT join [Test].[dbo].[Address] a on a.Id = o.BillingAddressId and (
coalesce(@BillingEmail,'') <> ''
or coalesce(@BillingFirstName,'') <> ''
or coalesce(@BillingLastName,'') <> ''
)
WHERE (@BillingEmail IS null OR a.[Email] = @BillingEmail)
AND (@BillingFirstName IS null OR a.[FirstName] = @BillingFirstName)
AND (@BillingLastName IS null OR a.[LastName] = @BillingLastName)
Note the join is only attempted if one of the Billing variables has a value.
Upvotes: 1
Reputation: 13006
Lets try to move your left join
table in a filtered subquery
.
left join
(select * from [Test].[dbo].[Address] a
where (@BillingEmail IS null OR a.[Email] = @BillingEmail)
AND (@BillingFirstName IS null OR a.[FirstName] = @BillingFirstName)
AND (@BillingLastName IS null OR a.[LastName] = @BillingLastName)) t1
ON t1.Id = o.BillingAddressId
to bypass left join based on your criteria, you can use below code.
if (ISNULL(@BillingEmail, '') = '' and ISNULL(@BillingFirstName, '') = '' and ISNULL(@BillingLastName, '') = '')
begin
SELECT TOP 100 *
FROM [Test].[dbo].[Order] o with (NOLOCK)
WHERE o.[Deleted] = 0
AND (o.[Id] = @OrderId OR @OrderId = 0)
AND (o.[WarehouseId] = @WarehouseId OR @WarehouseId = 0)
AND (@PaymentMethodSystemName IS null OR o.[PaymentMethodSystemName] = @PaymentMethodSystemName)
AND (o.[OrderStatusId] = @OrderStatusId OR @OrderStatusId = 0)
AND (o.[PaymentStatusId] = @PaymentStatusId OR @PaymentStatusId = 0)
AND (o.[ShippingStatusId] = @ShippingStatusId OR @ShippingStatusId = 0)
AND (@ShippingMethod IS null OR o.[ShippingMethod] = @ShippingMethod)
AND o.[CreatedOnUtc] >= ISNULL(@CreatedFromUtc, '1/1/1900')
AND o.[CreatedOnUtc] < ISNULL(@CreatedToUtc, '1/1/2999')
ORDER BY o.[CreatedOnUtc] DESC
end
else
begin
SELECT TOP 100 *
FROM [Test].[dbo].[Order] o with (NOLOCK)
left join
(select * from [Test].[dbo].[Address] a
where (@BillingEmail IS null OR a.[Email] = @BillingEmail)
AND (@BillingFirstName IS null OR a.[FirstName] = @BillingFirstName)
AND (@BillingLastName IS null OR a.[LastName] = @BillingLastName)) t1
ON t1.Id = o.BillingAddressId
WHERE o.[Deleted] = 0
AND (o.[Id] = @OrderId OR @OrderId = 0)
AND (o.[WarehouseId] = @WarehouseId OR @WarehouseId = 0)
AND (@PaymentMethodSystemName IS null OR o.[PaymentMethodSystemName] = @PaymentMethodSystemName)
AND (o.[OrderStatusId] = @OrderStatusId OR @OrderStatusId = 0)
AND (o.[PaymentStatusId] = @PaymentStatusId OR @PaymentStatusId = 0)
AND (o.[ShippingStatusId] = @ShippingStatusId OR @ShippingStatusId = 0)
AND (@ShippingMethod IS null OR o.[ShippingMethod] = @ShippingMethod)
AND o.[CreatedOnUtc] >= ISNULL(@CreatedFromUtc, '1/1/1900')
AND o.[CreatedOnUtc] < ISNULL(@CreatedToUtc, '1/1/2999')
ORDER BY o.[CreatedOnUtc] DESC
end
Upvotes: 1