Using: MS SQL SERVER 2008R2 to 2016
I have a stored procedure (simplified version below) which returns a list of products filtered by any of several parameters. The data I return only comes from the primary table (Products) but can be filtered by cross referenced data in any of the other tables.
The code below will function, however efficiency wise if a parameter is not supplied for a join, the server still takes the efficiency hit of linking to that table, even though the data implies there is no filtering required.
I can build this in dynamic sql and add the joins dependant on the parameters, but I'm trying to avoid dynamic as much as possible - it always becomes difficult to maintain.
Does anyone have any better solutions that they have used or can think of? I do have several working options, but looking at the code I feel there has to be a better option.
Many thanks.
CREATE PROC FilteredProducts
@CatalogueID INT = NULL
, @ManufacturerID INT = NULL
, @BrandID INT = NULL
AS
BEGIN
SELECT Products.*
FROM Products P
JOIN Catalogue C ON P.ID = C.ProductID
AND (@CatalogueID IS NULL
OR C.ID = @CatalogueID
)
JOIN Manufacturers M ON P.ID = M.Products_ID
AND (@ManufacturerID IS NULL
OR M.ID = @ManufacturerID
)
JOIN Brands B ON P.ID = B.Products_ID
AND (@BrandID IS NULL
OR B.ID = @BrandID
)
END
Edit:
Added example of code,
DECLARE @InstockOnly AS BIT = 0
SELECT AP.*
FROM ABCD.AllowedProducts AP
JOIN ABCD.DatabaseStockLevels DSL ON DSL.ProductGUID = AP.ProductGUID
AND (@InstockOnly = 0
OR DSL.StockLevel > 0
)
OPTION (RECOMPILE)
When executing the code above to filter specifically by stock level the actual execution plan shows that the join is evaluated despite having InstockOnly = 0. Although my data is a 1 to 1 relationship, SQL Server doesn't know that, so the join is performed in case there is a 1 to many relationship. While the option (recompile) does simplify the join, I'm looking for a way to remove the join completely.