非常抱歉,这是一个有点长的问题,但没有简单的表达方式。
我有以下查询:
SELECT
S.*
FROM
Stock S
LEFT JOIN
Stock_Category SC ON SC.StockId = S.Id
WHERE
S.Published = 1
AND (@CategoryId IS NULL OR
(SELECT COUNT(*)
FROM GetParentCategoriesByCategoryId(SC.CategoryId)
WHERE Id = @CategoryId) > 0)
在 GetParentCategoriesByCategoryId()
函数中,我使用了以下通用表达式 (CTE):
DECLARE @TableOutput TABLE(Id UNIQUEIDENTIFIER,
PosDissectionId INT,
PosFamilyClassId INT,
ParentId UNIQUEIDENTIFIER,
Code NVARCHAR(25),
[Name] NVARCHAR(100),
Description NVARCHAR(1000),
AzureId UNIQUEIDENTIFIER,
Extension NVARCHAR(10),
Visible BIT,
OrderIndex INT,
StockCount INT,
Depth INT)
BEGIN
DECLARE @TotalVisible INT,
@TotalRows INT
;WITH CategoryStructure (Id, ParentId, ParentName, Name, Depth, Visible)
As
(
SELECT
C.Id,
C.ParentId,
CAST('' AS NVARCHAR(500)) AS ParentName,
C.Name,
0 AS Depth,
C.Visible
FROM
Category C
WHERE
Id = @LocalCategoryId
UNION ALL
SELECT
ParentCategory.Id,
ParentCategory.ParentId,
CategoryStructure.Name AS ParentName,
ParentCategory.Name,
CategoryStructure.Depth + 1,
ParentCategory.Visible
FROM
Category ParentCategory
INNER JOIN
CategoryStructure ON ParentCategory.Id = CategoryStructure.ParentId
)
INSERT INTO @TableOutput
SELECT
C.*,
SC.StockCount,
CS.Depth
FROM
CategoryStructure CS
INNER JOIN
Category C ON C.Id = CS.Id
LEFT JOIN
(SELECT CategoryId, COUNT(*) AS StockCount
FROM Stock_Category SC
INNER JOIN Stock S ON S.Id = SC.StockId
WHERE S.Published = 1 AND
((S.WidthMM IS NOT NULL AND
S.HeightMM IS NOT NULL AND
S.DepthMM IS NOT NULL AND
S.WeightG IS NOT NULL)) AND
CategoryId IN(SELECT CategoryId FROM CategoryStructure)
GROUP BY CategoryId
) SC ON SC.CategoryId = CS.Id
WHERE (@IncludeSelf = 1 OR CS.Id != @CategoryId)
SELECT
@TotalVisible = SUM(CONVERT(INT, Visible)),
@TotalRows = COUNT(*)
FROM @TableOutput
IF @TotalVisible <> @TotalRows
DELETE FROM @TableOutput
RETURN
END
我的查询执行计划看起来是这样的。
不幸的是,我对于2000行查询需要超过7秒的时间。我相信我已经添加了正确的索引(并且似乎显示查询正在使用它们)。
我已经能够将问题缩小到CTE中的LEFT JOIN。
SELECT CategoryId, COUNT(*) AS StockCount
FROM Stock_Category SC
INNER JOIN Stock S ON S.Id = SC.StockId
WHERE S.Published = 1 AND blah blah blah....
因为当我删除它时,性能显著提高,但这是我目前能推断出的全部。
我并不期望得到解决方案,因为我知道这基于许多因素,但我离SQL专家还很远,希望有人能提供任何关于我需要查找什么的指导?
表模式可以在此处找到:https://www.dropbox.com/s/tpetq6fky58fhti/schemas.sql?dl=0
(SELECT COUNT(*) FROM GetParentCategoriesByCategoryId(SC.CategoryId) WHERE Id = @CategoryId) > 0)
,而是使用EXISTS (SELECT 1 from GetParentCategoriesByCategoryId(SC.CategoryId) WHERE Id = @CategoryId
。此外,如果可以的话,最好消除该函数调用,因为递归CTE不太快。 - SQLMasonSELECT S.* FROM Stock S LEFT JOIN Stock_Category SC ON SC.StockId = S.Id WHERE S.Published = 1 AND (@CategoryId IS NULL OR SC.CategoryId IN (SELECT CategoryId FROM #Cats)) OPTION (RECOMPILE)
的语句进行查询。 - Martin Smith