如果某些参数未传递给过程,则参数化存储过程将绕过左联接



我已向存储过程添加左联接,但是即使我不传递联接所需的参数,查询现在也需要 4 到 10 倍的时间才能运行。

这是我的存储过程:

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

因此,如果我不传入@BillingEmail@BillingFirstName@BillingLastName,就像仍然考虑左连接一样:

如果我注释掉左连接,我的查询再次非常快:

/*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

如果@BillingEmail@BillingFirstName@BillingLastName都为空,我怎样才能一起绕过该查询。

我想也许是这样的事情,但这是不对的:

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

我查看了索引,但我认为我无法为这 3 个参数创建索引。 任何想法如何绕过左连接?

让我们尝试在过滤subquery中移动left join表。

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

若要根据您的条件绕过左联接,可以使用以下代码。

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

作为替代方法,您可以将其保留为单个查询,如下所示:

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)

请注意,仅当其中一个计费变量具有值时,才会尝试联接。

最新更新