简体   繁体   English

SQL递归层次结构非常慢

[英]SQL recursive hierarchy very slow

So I just got a task to optimize an SQL query that builds a hierarchy tree of products, inner products, manufactory operations, operation details, and items (needed to make the product). 因此,我刚完成一项优化SQL查询的任务,该SQL查询构建了产品,内部产品,制造操作,操作细节和项目(制造产品所需)的层次结构树。 The query returns 218k rows, works correctly but takes about 15-18 seconds to build the tree. 该查询返回218k行,可以正常工作,但是大约需要15-18秒来构建树。 Is it possible to optimize that query so it would take about 2-3 seconds? 是否可以优化该查询,因此大约需要2-3秒? If I add @ProductID as a parameter for this procedure and do 如果我将@ProductID添加为该过程的参数并执行

WHERE ProductID = @ProductID

after selecting from Product table, then it works very fast, but tree is not complete, because if the product that I build the tree for is an inner product, it's parent product does not show up in the tree. 从“产品”表中选择后,它的运行速度非常快,但是树却不完整,因为如果我为其构建树的产品是内部产品,则其父产品不会显示在树中。 Would it be faster to load all these tables to the C# application and do all hierarchy building there? 将所有这些表加载到C#应用程序并在那里进行所有层次结构构建会更快吗?

I'm open to all ideas. 我愿意接受所有想法。 Below is the query in question 下面是有问题的查询

  ALTER PROCEDURE [dbo].[ProductProduct_selectHierarchy_v2]
WITH EXECUTE AS CALLER
AS
BEGIN
WITH ProductProductHierarchy (
    ProductID
    ,ItemProductID
    ,LEVEL
    ,UniqueID
    ,ParentID
    ,RowType
    ,ProductDetailID
    ,ProductProductDetailBindID
    ,ManufactoryOperationID
    ,ItemID
    )
AS (
    -- Anchor member definition
    SELECT dbo.Product.ProductID AS ProductID
        ,Product.ProductID AS ItemProductID
        ,0 AS LEVEL
        ,Cast(cast(Product.ProductID AS NVARCHAR(40)) + '' AS NVARCHAR(50)) AS UniqueID
        ,cast('' AS NVARCHAR(50)) AS ParentID
        ,1 AS RowType
        ,NULL AS ProductDetailID
        ,NULL AS ProductProductDetailBindID
        ,NULL AS ManufactoryOperationID
        ,NULL AS ItemID
    FROM dbo.Product

    UNION ALL

    -- Recursive member definition
    SELECT e.ProductID
        ,e.ItemProductID
        ,LEVEL + 1
        ,Cast(Cast(d.UniqueID AS NVARCHAR(40)) + '_' + cast((e.ItemProductID) AS NVARCHAR(10)) AS NVARCHAR(50)) AS UniqueID
        ,Cast(d.UniqueID AS NVARCHAR(50)) AS ParentID
        ,1 AS RowType
        ,NULL AS ProductDetailID
        ,NULL AS ProductProductDetailBindID
        ,NULL AS ManufactoryOperationID
        ,NULL AS ItemID
    FROM dbo.ProductProduct AS e
    INNER JOIN ProductProductHierarchy AS d ON e.ProductID = d.ItemProductID

    UNION ALL

    SELECT NULL AS ProductID
        ,NULL
        ,LEVEL + 1
        ,Cast(Cast(d.UniqueID AS NVARCHAR(40)) + '_' + cast((e.ProductDetailID) AS NVARCHAR(10)) AS NVARCHAR(50)) AS UniqueID
        ,Cast(d.UniqueID AS NVARCHAR(50)) AS ParentID
        ,2 AS RowType
        ,e.ProductDetailID AS ProductDetailID
        ,e.ProductProductDetailBindID AS ProductProductDetailBindID
        ,NULL AS ManufactoryOperationID
        ,NULL AS ItemID
    FROM dbo.ProductProductDetailBind AS e
    INNER JOIN ProductProductHierarchy AS d ON e.ProductID = d.ItemProductID

    UNION ALL

    SELECT NULL AS ProductID
        ,NULL
        ,LEVEL + 1
        ,Cast(Cast(d.UniqueID AS NVARCHAR(40)) + '_' + cast((e.ManufactoryOperationID) AS NVARCHAR(10)) AS NVARCHAR(50)) AS UniqueID
        ,Cast(d.UniqueID AS NVARCHAR(50)) AS ParentID
        ,3 AS RowType
        ,NULL AS ProductDetailID
        ,NULL AS ProductProductDetailBindID
        ,e.ManufactoryOperationID AS ManufactoryOperationID
        ,NULL AS ItemID
    FROM dbo.ProductDetailOperation AS e
    INNER JOIN ProductProductHierarchy AS d ON e.ProductProductDetailBindID = d.ProductProductDetailBindID

    UNION ALL

    SELECT NULL AS ProductID
        ,NULL
        ,LEVEL + 1
        ,Cast(Cast(d.UniqueID AS NVARCHAR(40)) + '_' + cast((e.ItemID) AS NVARCHAR(10)) AS NVARCHAR(50)) AS UniqueID
        ,Cast(d.UniqueID AS NVARCHAR(50)) AS ParentID
        ,4 AS RowType
        ,NULL AS ProductDetailID
        ,NULL AS ProductProductDetailBindID
        ,NULL AS ManufactoryOperationID
        ,e.ItemID AS ItemID
    FROM dbo.ProductItem AS e
    INNER JOIN ProductProductHierarchy AS d ON e.ProductID = d.ItemProductID
    )
-- Statement that executes the CTE
SELECT CASE 
        WHEN RowType = 1
            THEN ProductName + '<' + ProductCode + '>'
        WHEN RowType = 2
            THEN ProductDetail.ProductDetailName
        WHEN RowType = 3
            THEN ManufactoryOperation.ManufactoryOperationName
        ELSE Item.ItemName
        END AS ProductName
    ,UniqueID
    ,ProductProductHierarchy.ParentID
    ,Product.ProductID
    ,RowType
FROM ProductProductHierarchy
LEFT OUTER JOIN Product ON Product.ProductID = ProductProductHierarchy.ItemProductID
    AND RowType = 1
LEFT OUTER JOIN ProductDetail ON ProductDetail.ProductDetailID = ProductProductHierarchy.ProductDetailID
    AND RowType = 2
LEFT OUTER JOIN ManufactoryOperation ON ManufactoryOperation.ManufactoryOperationID = ProductProductHierarchy.ManufactoryOperationID
    AND RowType = 3
LEFT OUTER JOIN Item ON Item.ItemID = ProductProductHierarchy.ItemID
    AND RowType = 4
OPTION (MAXRECURSION 0)

END 结束

It looks like you're effectively building a set of heterogeneous rows, which I would try to stay away from in general. 看来您正在有效地构建一组异构行,但我通常会尽量避免这样做。 Get your product tree using recursion if you need to, but then pull in the operations, items, etc. as separate result sets. 如果需要,可以使用递归获取产品树,然后将操作,项目等作为单独的结果集。 Mixing row types as you have is very likely to cause headaches (not just performance ones) down the road. 像这样混合行类型很可能会引起麻烦(而不仅仅是性能问题)。

Without knowing the full functionality of your application I can't say the best way that you should retrieve those items from the DB, but I would definitely start there as a possible issue. 在不了解应用程序的全部功能的情况下,我无法说出应该从数据库中检索这些项目的最佳方法,但是我肯定会从那里开始作为一个可能的问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM