【问题标题】:SQL recursive hierarchy very slowSQL递归层次结构非常慢
【发布时间】:2016-04-15 19:22:54
【问题描述】:

所以我刚刚得到一个任务来优化 SQL 查询,该查询构建产品、内部产品、制造操作、操作细节和项目(制造产品所需)的层次结构树。该查询返回 218k 行,工作正常,但构建树大约需要 15-18 秒。是否可以优化该查询,使其大约需要 2-3 秒?如果我添加 @ProductID 作为此过程的参数并执行

WHERE ProductID = @ProductID

从产品表中选择后,它工作得非常快,但树不完整,因为如果我为其构建树的产品是内部产品,它的父产品不会出现在树中。 将所有这些表加载到 C# 应用程序并在那里构建所有层次结构会更快吗?

我对所有想法持开放态度。以下是有问题的查询

  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)

结束

【问题讨论】:

  • 标记使用的 dbms。 (产品特定问题...)
  • 您正在执行大量与 UniqueID 相关的字符串操作,但您的查询实际上并不需要该特定列。您应该只选择列,然后在应用程序级别创建聚合 UniqueID;排除那些强制转换和字符串连接。

标签: c# sql sql-server recursion hierarchy


【解决方案1】:

看起来您正在有效地构建一组异构行,我通常会尽量远离这些行。如果需要,使用递归获取产品树,然后将操作、项目等作为单独的结果集拉入。像你一样混合行类型很可能会导致令人头疼的问题(不仅仅是性能问题)。

在不了解您的应用程序的全部功能的情况下,我不能说您应该从数据库中检索这些项目的最佳方式,但我肯定会从可能的问题开始。

【讨论】:

  • 这可能有用,谢谢。致力于创建产品树,将报告结果:)
猜你喜欢
  • 2017-02-04
  • 2015-11-23
  • 2013-02-09
  • 2013-11-22
  • 1970-01-01
  • 2019-03-22
  • 2013-11-07
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多