删除 where 子句然后添加回来时的执行计划优化
Posted
技术标签:
【中文标题】删除 where 子句然后添加回来时的执行计划优化【英文标题】:Execution Plan Optimization when where clause is removed then added back 【发布时间】:2012-10-15 21:34:00 【问题描述】:我有一个使用表值函数的存储过程,该函数在 9 秒内执行。如果我更改表值函数并删除 where 子句,则存储过程将在 3 秒内执行。如果我重新添加 where 子句,查询仍会在 3 秒内执行。
我查看了执行计划,似乎在删除 where 子句后,执行计划包括并行性,并且我的 2 个表的扫描计数从 50000 和 65000 下降到 5 和 3。添加后where 子句返回,优化的执行计划仍然运行,除非我运行 DBCC FREEPROCCACHE。
问题 1. 为什么只有在我第一次删除 where 子句时,SQL Server 才开始对两个查询使用优化的执行计划?
-
有没有办法强制 SQL Server 使用这个执行计划?
此外,这是一个参数化的一体式查询,它在 where 子句中使用(参数为 null 或参数),我认为这对性能不利。
RETURNS TABLE
AS
RETURN
(
SELECT TOP (@PageNumber * @PageSize)
CASE
WHEN @SortOrder = 'Expensive' THEN ROW_NUMBER() OVER (ORDER BY SellingPrice DESC)
WHEN @SortOrder = 'Inexpensive' THEN ROW_NUMBER() OVER (ORDER BY SellingPrice ASC)
WHEN @SortOrder = 'LowMiles' THEN ROW_NUMBER() OVER (ORDER BY Mileage ASC)
WHEN @SortOrder = 'HighMiles' THEN ROW_NUMBER() OVER (ORDER BY Mileage DESC)
WHEN @SortOrder = 'Closest' THEN ROW_NUMBER() OVER (ORDER BY P1.Distance ASC)
WHEN @SortOrder = 'Newest' THEN ROW_NUMBER() OVER (ORDER BY [Year] DESC)
WHEN @SortOrder = 'Oldest' THEN ROW_NUMBER() OVER (ORDER BY [Year] ASC)
ELSE ROW_NUMBER() OVER (ORDER BY InventoryID ASC)
END as rn,
P1.InventoryID,
P1.SellingPrice,
P1.Distance,
P1.Mileage,
Count(*) OVER () RESULT_COUNT,
dimCarStatus.[year]
FROM (SELECT InventoryID, SellingPrice, Zip.Distance, Mileage, ColorKey, CarStatusKey, CarKey FROM facInventory
JOIN @ZipCodes Zip
ON Zip.DealerKey = facInventory.DealerKey) as P1
JOIN dimColor
ON dimColor.ColorKey = P1.ColorKey
JOIN dimCarStatus
ON dimCarStatus.CarStatusKey = P1.CarStatusKey
JOIN dimCar
ON dimCar.CarKey = P1.CarKey
WHERE
(@ExteriorColor is NULL OR dimColor.ExteriorColor like @ExteriorColor) AND
(@InteriorColor is NULL OR dimColor.InteriorColor like @InteriorColor) AND
(@Condition is NULL OR dimCarStatus.Condition like @Condition) AND
(@Year is NULL OR dimCarStatus.[Year] like @Year) AND
(@Certified is NULL OR dimCarStatus.Certified like @Certified) AND
(@Make is NULL OR dimCar.Make like @Make) AND
(@ModelCategory is NULL OR dimCar.ModelCategory like @ModelCategory) AND
(@Model is NULL OR dimCar.Model like @Model) AND
(@Trim is NULL OR dimCar.Trim like @Trim) AND
(@BodyType is NULL OR dimCar.BodyType like @BodyType) AND
(@VehicleTypeCode is NULL OR dimCar.VehicleTypeCode like @VehicleTypeCode) AND
(@MinPrice is NULL OR P1.SellingPrice >= @MinPrice) AND
(@MaxPrice is NULL OR P1.SellingPrice < @MaxPrice) AND
(@Mileage is NULL OR P1.Mileage < @Mileage)
ORDER BY
CASE
WHEN @SortOrder = 'Expensive' THEN -SellingPrice
WHEN @SortOrder = 'Inexpensive' THEN SellingPrice
WHEN @SortOrder = 'LowMiles' THEN Mileage
WHEN @SortOrder = 'HighMiles' THEN -Mileage
WHEN @SortOrder = 'Closest' THEN P1.Distance
WHEN @SortOrder = 'Newest' THEN -[YEAR]
WHEN @SortOrder = 'Oldest' THEN [YEAR]
ELSE InventoryID
END
)
【问题讨论】:
您可以通过在参数 where 子句中使用 ISNULL 而不是 OR 来获得更好的性能。 WHERE dimColor.ExteriorColor like ISNULL(@ExteriorColor,'%') 【参考方案1】:问题 1:SQL server 仍然继续使用对没有 where 子句的语句有效的执行计划。基本上 SQL Server 认为 where 子句不存在。
问题2:使用OPTION(USE PLAN N'')文章:http://technet.microsoft.com/en-us/library/cc917694.aspx
个人推荐:
-
更改查询,使您至少拥有一个强制过滤器并将其编入索引。
或
将其更改为动态,并动态应用过滤器。文章:http://msdn.microsoft.com/en-us/library/ms188001.aspx
希望这会有所帮助。
【讨论】:
以上是关于删除 where 子句然后添加回来时的执行计划优化的主要内容,如果未能解决你的问题,请参考以下文章
使用 WHERE 子句中的过滤器优化 OUTER JOIN 查询。(查询规划器)
在 SQL 中动态构建 WHERE 子句,无需硬解析即可执行
PostgreSQL 中的 SQL JOIN - WHERE 子句中的执行计划与 ON 子句中的不同