改进存储过程中的完整sql查询

时间:2017-12-26 21:45:42

标签: sql-server tsql stored-procedures sql-function

我有一个存储过程,用于在WPF中填充像网格一样的仪表板。我随着时间的推移改进了查询,说实话,性能可能更好。我现在已经知道了,我不知道有什么改进查询的好方法,我可以通过执行时间获得性能。

非常感谢任何帮助。下面是存储过程:

    ALTER PROCEDURE [dbo].[spGetDashboardMainNew]
    AS
         BEGIN
             SET NOCOUNT ON;
             SELECT JC.job_number AS SalesOrder,
                    dbo.cust.Company AS Customer,
                    JC.Plan_ship_date AS PlannedShipDate,
                    JC.latest_ship_date AS LatestShipDate,
                    JC.planned_fab_complete AS PlanFabComplete,
                    JC.fldPromisedDate AS CommittedShipDate,
                    JC.Materials_of_Construction AS MatofCons,
                    JC.Fab_rating AS FabRating,
                    JC.ass_rating AS [Assembly Rating],
                    JC.shipped AS OpenShipped,
                    JC.electrical_status,
                    JC.dp_credit_status,
                    JC.fldCustRequestDate,
                    JC.commercial_terms,
                    JC.Approved_by,
                    fldLiquidatedDamages,
                    fldLiquidatedDamagesDesc,
                    CASE
                        WHEN hot_list = '0'
                             OR hot_list = 'No'
                        THEN 'No'
                        ELSE 'Yes'
                    END AS HotList,
                    CASE
                        WHEN JC.latest_ship_date IS NOT NULL
                             AND JC.fldPromisedDate IS NULL
                        THEN JC.latest_ship_date
                        ELSE JC.fldPromisedDate
                    END AS CommitDate,
                    CASE
                        WHEN dp_credit_status = 1
                             AND commercial_terms = 'Complete'
                        THEN 1
                        ELSE 0
                    END AS TermsMet,
                    CASE
                        WHEN JC.fldPromisedDate IS NULL
                        THEN 1
                        ELSE 0
                    END AS SortByDate,
                    dbo.tblShippingInfo.fldShipmentRequestID,
                    CASE
                        WHEN JC.fleInspectionType <> 'None'
                        THEN JC.fleInspectionType
                        ELSE NULL
                    END AS InspectionType,
                    JC.fldInspectionNotes,
                 JC.DueDateExtraTime,
                    CASE
                        WHEN JC.fleInspectionType <> 'None'
                             AND JC.fleInspectionType IS NOT NULL
                        THEN 1
                        ELSE 0
                    END AS InspectionDesc,
                    advanced_buying,
                    SortedOrder,
                    SalesOrderStatusGroup,
                    SalesOrderStatus,
                    SpecialOpList,
                    OperationDueBy,
                    test,
                    wpStatus,
                    SpecialOpsCount,
                    InChangeOrder,
                    RequiresSpecialPaint
             FROM dbo.cust
                  INNER JOIN dbo.Job_Control JC ON dbo.cust.CUST# = JC.Cust#
                  LEFT OUTER JOIN dbo.tblShippingInfo ON JC.job_number = dbo.tblShippingInfo.fldJobNumberID
                  OUTER APPLY
             (
                 SELECT dbo.udfGetManStatusFullSortOrder(JC.job_number) AS SortedOrder
             ) acolumn
                  OUTER APPLY
             (
                 SELECT ISNULL(dbo.udfGetManStatusBySOGroupNo(JC.job_number, 1), dbo.udfGetManStatusNew(JC.job_number)) AS SalesOrderStatusGroup
             ) bcolumn
                  OUTER APPLY
             (
                 SELECT ISNULL(dbo.udfGetManStatusBySOGroupNo(JC.job_number, 1), dbo.udfGetManStatusNew(JC.job_number)) AS SalesOrderStatus
             ) ccolumn
                  OUTER APPLY
             (
                 SELECT dbo.udfGetSpecialOperations(JC.job_number) AS SpecialOpList
             ) dcolumn
                  OUTER APPLY
             (
                 SELECT CASE
                            WHEN dbo.udfGetManStatusNew(JC.job_number) LIKE '%Approval%' OR dbo.udfGetManStatusNew(JC.job_number) LIKE '%Re-Approval%'
                            THEN JC.Approval_Due
                            ELSE dbo.udfGetDueByPerOperation(JC.job_number, 1)
                        END AS OperationDueBy
             ) ecolumn
                  OUTER APPLY
             (
                 SELECT dbo.udfGetGroupCount(JC.job_number) AS test
             ) fcolumn
                  OUTER APPLY
             (
                 SELECT dbo.udfGetOpenWorkPackagesByDesigner(JC.job_number) AS wpStatus
             ) gcolumn
                  OUTER APPLY
             (
                 SELECT dbo.udfGetSpecialOpsCount(JC.job_number) AS SpecialOpsCount
             ) hcolumn
                  OUTER APPLY
             (
                 SELECT dbo.udfIsActiveChangeOrder(JC.job_number) AS InChangeOrder
             ) icolumn
                  OUTER APPLY
             (
                 SELECT dbo.udfRequiresSpecialColor(JC.job_number) AS RequiresSpecialPaint
             ) jcolumn
             WHERE(JC.shipped = 'Open')
                  OR (JC.shipped = 'Hold');
         END;

以下是名为的外部应用函数:

        ALTER FUNCTION [dbo].[udfGetManStatusFullSortOrder] 
    (
        @SalesOrderNumber int
    )
    RETURNS INT
    AS
    BEGIN
        DECLARE @shipped nvarchar(50);
        DECLARE @eng_complete datetime;
        DECLARE @Drawing_Info nvarchar(50);
        DECLARE @Release_to_engineering datetime;
        DECLARE @Dwg_Sent datetime;
        DECLARE @Approval_done datetime;
        DECLARE @Detail bit;
        DECLARE @Release_to_shop datetime;
        DECLARE @OperationCount int;
        DECLARE @SortOrder INT;
        DECLARE @p as INT = 1;
        DECLARE @NonOpSortOrder INT;

        SET @NonOpSortOrder = dbo.udfIsOnHoldSort(@SalesOrderNumber)

        IF @NonOpSortOrder > 0 
            RETURN @nonopsortorder

            SELECT @SortOrder = (SELECT TOP(@p) dbo.ShopRouting.DashboardSortOrder
                FROM    dbo.Product INNER JOIN
                      dbo.ProductMfgGrouping ON dbo.Product.Record_no = dbo.ProductMfgGrouping.Record_no INNER JOIN
                      dbo.MfgGrouping ON dbo.ProductMfgGrouping.MfgGroupingID = dbo.MfgGrouping.MfgGroupingID INNER JOIN
                      dbo.GroupOperations ON dbo.MfgGrouping.MfgGroupingID = dbo.GroupOperations.MfgGroupingID INNER JOIN
                      dbo.ShopRouting ON dbo.GroupOperations.ShopRoutingID = dbo.ShopRouting.ShopRoutingID
                WHERE  (dbo.Product.Job_number = @SalesOrderNumber) AND (dbo.MfgGrouping.GroupingNumber = 1) AND (dbo.GroupOperations.Completed IS NULL)
                GROUP BY dbo.ShopRouting.Description, dbo.GroupOperations.NewSortOrder, dbo.ShopRouting.DashboardSortOrder
                ORDER BY dbo.GroupOperations.NewSortOrder);

        IF @SortOrder IS NOT NULL
                RETURN @SortOrder

        SELECT
            @shipped = shipped,
            @eng_complete = eng_complete,
            @Drawing_Info = Drawing_Info,
            @Release_to_engineering = Release_to_engineering,
            @Dwg_Sent = Dwg_Sent,
            @Approval_done = Approval_done,
            @Detail = Detail,
            @Release_to_shop = Release_to_shop

        FROM
            job_control

        WHERE
            job_number = @SalesOrderNumber

        BEGIN
            SET @OperationCount = flex2ksql.dbo.udfGetGroupOperationsCount(@SalesOrderNumber);
        END

        IF (@shipped = 'Hold')
            RETURN 33

        IF (@eng_complete IS NULL)
            BEGIN
                 IF (@Release_to_engineering IS NULL)

                    RETURN 32

                IF (@Drawing_Info = 'Approval' AND
                    @Release_to_engineering IS NOT NULL AND
                    @Dwg_Sent IS NOT NULL AND
                    @Approval_done IS NULL)

                    RETURN 28

                IF (@Drawing_Info = 'Re-Approval' AND
                    @Release_to_engineering IS NOT NULL AND
                    @Dwg_Sent IS NOT NULL AND
                    @Approval_done IS NULL)

                    RETURN 29

                IF (@Drawing_Info = 'Approval' AND
                    @Release_to_engineering IS NOT NULL AND
                    @Dwg_Sent IS NOT NULL AND
                    @Detail = 1 AND
                    @Approval_done IS NOT NULL)

                    If (@OperationCount) = 0 OR (@OperationCount IS NULL)
                        RETURN 27
                    ELSE
                        RETURN 26

                IF (@Drawing_Info = 'Approval' AND 
                    @Release_to_engineering IS NOT NULL)

                    RETURN 30

                IF (@Drawing_Info = 'Re-Approval' AND
                    @Release_to_engineering IS NOT NULL AND
                    @Dwg_Sent IS NULL AND
                    @Approval_done IS NULL)

                    RETURN 31

                IF (@Drawing_Info = 'Certified' AND
                    @Release_to_engineering IS NOT NULL AND
                    @Detail = 1)

                    If (@OperationCount) = 0 OR (@OperationCount IS NULL)
                        RETURN 27
                    ELSE
                        RETURN 26

                IF (@Drawing_Info = 'No Drawing Required' AND
                    @Release_to_engineering IS NOT NULL)

                    If (@OperationCount) = 0 OR (@OperationCount IS NULL)
                        RETURN 27
                    ELSE
                        RETURN 26

                IF (@Drawing_Info = 'Certified')

                    If (@OperationCount) = 0 OR (@OperationCount IS NULL)
                        RETURN 27
                    ELSE
                        RETURN 26

                IF (@Drawing_Info = 'Sales Drawing' AND
                    @Release_to_engineering IS NOT NULL AND
                    @Release_to_shop IS NOT NULL)

                    If (@OperationCount) = 0 OR (@OperationCount IS NULL)
                        RETURN 27
                    ELSE
                        RETURN 26
                ELSE
                    RETURN 27

            END
        ELSE
            BEGIN
                RETURN 27
            END
        RETURN 99



        ALTER FUNCTION [dbo].[udfGetManStatusBySOGroupNo] 
    (
        @SalesOrder int, @GroupNo int
    )
    RETURNS varchar(100)
    AS
    BEGIN

        DECLARE @ManStatus varchar(100);
        DECLARE @p as INT = 1;
        DECLARE @NonOpSortOrder INT;

        SET @NonOpSortOrder = dbo.udfIsOnHoldSort(@SalesOrder)

        IF @NonOpSortOrder > 0 
            RETURN 'Hold'
        ELSE

                SELECT @ManStatus = (SELECT TOP(@p) dbo.ShopRouting.Description
                FROM dbo.Product INNER JOIN
                      dbo.ProductMfgGrouping ON dbo.Product.Record_no = dbo.ProductMfgGrouping.Record_no INNER JOIN
                      dbo.MfgGrouping ON dbo.ProductMfgGrouping.MfgGroupingID = dbo.MfgGrouping.MfgGroupingID INNER JOIN
                      dbo.GroupOperations ON dbo.MfgGrouping.MfgGroupingID = dbo.GroupOperations.MfgGroupingID INNER JOIN
                      dbo.ShopRouting ON dbo.GroupOperations.ShopRoutingID = dbo.ShopRouting.ShopRoutingID
                WHERE  (dbo.Product.Job_number = @SalesOrder) AND (dbo.MfgGrouping.GroupingNumber = @GroupNo) AND (dbo.GroupOperations.Completed is null)
                GROUP BY dbo.ShopRouting.Description, dbo.Product.Model_NO, dbo.GroupOperations.NewSortOrder
                ORDER BY dbo.GroupOperations.NewSortOrder);

                RETURN @ManStatus


        ALTER FUNCTION [dbo].[udfGetManStatusNew] 
    (
        @SalesOrderNumber int
    )
    RETURNS nvarchar(50)
    AS
    BEGIN
        DECLARE @shipped nvarchar(50);
        DECLARE @eng_complete datetime;
        DECLARE @Drawing_Info nvarchar(50);
        DECLARE @Release_to_engineering datetime;
        DECLARE @Dwg_Sent datetime;
        DECLARE @Approval_done datetime;
        DECLARE @Detail bit;
        DECLARE @Release_to_shop datetime;
        DECLARE @OperationCount int;

        SELECT
            @shipped = shipped,
            @eng_complete = eng_complete,
            @Drawing_Info = Drawing_Info,
            @Release_to_engineering = Release_to_engineering,
            @Dwg_Sent = Dwg_Sent,
            @Approval_done = Approval_done,
            @Detail = Detail,
            @Release_to_shop = Release_to_shop

        FROM
            job_control

        WHERE
            job_number = @SalesOrderNumber

        BEGIN
            SET @OperationCount = flex2ksql.dbo.udfGetGroupOperationsCount(@SalesOrderNumber);
        END

        IF (@shipped = 'Hold')
            RETURN 'Hold'

        IF (@eng_complete IS NULL)
            BEGIN
              IF (@Release_to_engineering IS NULL)

                    RETURN 'Not Released'

                IF (@Drawing_Info = 'Approval' AND
                    @Release_to_engineering IS NOT NULL AND
                    @Dwg_Sent IS NOT NULL AND
                    @Approval_done IS NULL)

                    RETURN 'Approval Out'

                IF (@Drawing_Info = 'Re-Approval' AND
                    @Release_to_engineering IS NOT NULL AND
                    @Dwg_Sent IS NOT NULL AND
                    @Approval_done IS NULL)

                    RETURN 'Re-Approval Out'

                IF (@Drawing_Info = 'Approval' AND
                    @Release_to_engineering IS NOT NULL AND
                    @Dwg_Sent IS NOT NULL AND
                    @Detail = 1 AND
                    @Approval_done IS NOT NULL)

                    If (@OperationCount) = 0 OR (@OperationCount IS NULL)
                        RETURN 'Routing'
                    ELSE
                        RETURN 'Detail'

                IF (@Drawing_Info = 'Approval' AND 
                    @Release_to_engineering IS NOT NULL)

                    RETURN 'Approval To Be Done'

                IF (@Drawing_Info = 'Re-Approval' AND
                    @Release_to_engineering IS NOT NULL AND
                    @Dwg_Sent IS NULL AND
                    @Approval_done IS NULL)

                    RETURN 'Re-Approval To Be Done'
                IF (@Drawing_Info = 'Certified' AND
                    @Release_to_engineering IS NOT NULL AND
                    @Detail = 1)

                    If (@OperationCount) = 0 OR (@OperationCount IS NULL)
                        RETURN 'Routing'
                    ELSE
                        RETURN 'Detail'

                IF (@Drawing_Info = 'No Drawing Required' AND
                    @Release_to_engineering IS NOT NULL)

                    If (@OperationCount) = 0 OR (@OperationCount IS NULL)
                        RETURN 'Routing'
                    ELSE
                        RETURN 'Detail'

                IF (@Drawing_Info = 'Certified')

                    If (@OperationCount) = 0 OR (@OperationCount IS NULL)
                        RETURN 'Routing'
                    ELSE
                        RETURN 'Detail'

                IF (@Drawing_Info = 'Sales Drawing' AND
                    @Release_to_engineering IS NOT NULL AND
                    @Release_to_shop IS NOT NULL)

                    If (@OperationCount) = 0 OR (@OperationCount IS NULL)
                        RETURN 'Routing'
                    ELSE
                        RETURN 'Detail'
                ELSE
                    RETURN 'Routing'

            END
        ELSE
            BEGIN
                RETURN 'Routing'
            END
        RETURN NULL


ALTER FUNCTION [dbo].[udfGetSpecialOperations] 
(
@SalesOrder int
)
RETURNS nvarchar(MAX)
AS
BEGIN   
DECLARE @returnVal nvarchar(MAX)

SELECT @returnVal = Stuff((SELECT N', ' + dbo.ShopRouting.Description FROM dbo.Product INNER JOIN
        dbo.ProductMfgGrouping ON dbo.Product.Record_no = dbo.ProductMfgGrouping.Record_no INNER JOIN
        dbo.MfgGrouping ON dbo.ProductMfgGrouping.MfgGroupingID = dbo.MfgGrouping.MfgGroupingID INNER JOIN
        dbo.GroupOperations ON dbo.MfgGrouping.MfgGroupingID = dbo.GroupOperations.MfgGroupingID INNER JOIN
        dbo.ShopRouting ON dbo.GroupOperations.ShopRoutingID = dbo.ShopRouting.ShopRoutingID                         
    WHERE (dbo.ShopRouting.Standard = 0) AND (dbo.Product.Job_number = @SalesOrder)
    GROUP BY dbo.ShopRouting.Description, dbo.ShopRouting.DashboardSortOrder
    ORDER BY dbo.ShopRouting.DashboardSortOrder DESC 
    FOR XML PATH(''),TYPE).value('text()[1]','nvarchar(max)'),1,2,N'')

RETURN @returnVal


        ALTER FUNCTION [dbo].[udfGetDueByPerOperation] 
    (
        @SalesOrder int, @GroupNo int
    )
    RETURNS varchar(100)
    AS
    BEGIN
        DECLARE @ManStatus varchar(100);
        DECLARE @p as INT = 1;

        SELECT @ManStatus = (SELECT TOP(@p) dbo.GroupOperations.StartBy
    FROM     dbo.Product INNER JOIN
                      dbo.ProductMfgGrouping ON dbo.Product.Record_no = dbo.ProductMfgGrouping.Record_no INNER JOIN
                      dbo.MfgGrouping ON dbo.ProductMfgGrouping.MfgGroupingID = dbo.MfgGrouping.MfgGroupingID INNER JOIN
                      dbo.GroupOperations ON dbo.MfgGrouping.MfgGroupingID = dbo.GroupOperations.MfgGroupingID INNER JOIN
                      dbo.ShopRouting ON dbo.GroupOperations.ShopRoutingID = dbo.ShopRouting.ShopRoutingID
    WHERE  (dbo.Product.Job_number = @SalesOrder) AND (dbo.MfgGrouping.GroupingNumber = @GroupNo) AND (dbo.GroupOperations.Completed IS NULL) AND (dbo.GroupOperations.Active = 0)
    GROUP BY dbo.ShopRouting.[Description], dbo.Product.Model_NO, dbo.GroupOperations.NewSortOrder, dbo.GroupOperations.StartBy
    ORDER BY dbo.GroupOperations.NewSortOrder);

        RETURN @ManStatus


        ALTER FUNCTION [dbo].[udfGetGroupCount] 
    (
        @SalesOrder int
    )
    RETURNS varchar(MAX)
    AS
    BEGIN
        DECLARE @result varchar(MAX)
        DECLARE @result2 varchar(MAX)

    SET @result = ''

    SELECT @result = @result + Description + ': ' + Cast(StatusCount as varchar(5)) + ', ' FROM vwLineItemGroupStatusCounts WHERE Job_number = @SalesOrder
    ORDER BY vwLineItemGroupStatusCounts.NewSortOrder

    SELECT @result2 = substring(@result, 0, len(@result)) --trim extra "," at end

        -- Return the result of the function
        RETURN @result2


        ALTER FUNCTION [dbo].[udfGetOpenWorkPackagesByDesigner] 
    (
        @SalesOrder int
    )
    RETURNS varchar(MAX)
    AS
    BEGIN
        DECLARE @result varchar(MAX)
        DECLARE @result2 varchar(MAX)

    SET @result = ''

    --SELECT @result = @result + Fldusername + ': ' + Cast(StatusCount as varchar(5)) + ', ' FROM vwOpenWorkPackagesByDesigner WHERE Job_number = @SalesOrder
    SELECT @result = @result + eng_difficulty_category + ' ' FROM vwOpenWorkPackagesEngRating WHERE job_number = @SalesOrder
    SELECT @result = @result + Fldusername + ' ' + Cast(coalesce(fldPriority,'none') as varchar(5)) + ' ' + cast(PercentComplete as varchar(10)) + '% ' + fldTaskCategoryAbbr + '; ' FROM vwOpenWorkPackagesByDesigner WHERE fldSalesOrder = @SalesOrder

    SELECT @result2 = substring(@result, 0, len(@result)) --trim extra "," at end

        -- Return the result of the function
        RETURN @result2


        ALTER FUNCTION [dbo].[udfGetSpecialOpsCount] 
    (
        @SalesOrder int
    )
    RETURNS int
    AS
    BEGIN

        DECLARE @returnVal int;

        SELECT @returnVal = COUNT(dbo.GroupOperations.GroupOperationID)
    FROM     dbo.Product INNER JOIN
                      dbo.ProductMfgGrouping ON dbo.Product.Record_no = dbo.ProductMfgGrouping.Record_no INNER JOIN
                      dbo.MfgGrouping ON dbo.ProductMfgGrouping.MfgGroupingID = dbo.MfgGrouping.MfgGroupingID INNER JOIN
                      dbo.GroupOperations ON dbo.MfgGrouping.MfgGroupingID = dbo.GroupOperations.MfgGroupingID INNER JOIN
                      dbo.ShopRouting ON dbo.GroupOperations.ShopRoutingID = dbo.ShopRouting.ShopRoutingID
    WHERE  (dbo.ShopRouting.Standard = 0) AND (dbo.Product.Job_number = @SalesOrder) AND (dbo.ShopRouting.ShopRoutingID NOT IN (15,16))

        If (@returnVal) = 0 OR (@returnVal IS NULL)
            SET @returnVal = 0;
        Return @returnVal;


        ALTER FUNCTION [dbo].[udfIsActiveChangeOrder] (@SalesOrder numeric(18, 0))

    RETURNS Bit

    AS

    BEGIN

        DECLARE @isCO Bit
        DECLARE @SOFound as numeric(18)

        SET @SOFound = 0

            BEGIN
            SELECT
                @SOFound = fldSalesOrder        
            FROM
                [flex2kSQL].[dbo].[vwChangeOrdersAllActive]
            WHERE
                fldSalesOrder = @SalesOrder
            END


            if @SOFound =0
                SET @isCO=0
            else
                SET @isCO=1


        RETURN @isCO


        ALTER FUNCTION [dbo].[udfRequiresSpecialColor] 
    (
        @SalesOrder INT
    )
    RETURNS INT
    AS
    BEGIN
        DECLARE @ReturnVal int;

        IF EXISTS (SELECT 1
            FROM dbo.MfgGrouping INNER JOIN
                dbo.ProductMfgGrouping ON dbo.MfgGrouping.MfgGroupingID = dbo.ProductMfgGrouping.MfgGroupingID INNER JOIN
                dbo.Product ON dbo.ProductMfgGrouping.Record_no = dbo.Product.Record_no INNER JOIN
                dbo.GroupOperations ON dbo.MfgGrouping.MfgGroupingID = dbo.GroupOperations.MfgGroupingID
            WHERE (dbo.Product.Job_number = @SalesOrder) AND (dbo.GroupOperations.ShopRoutingID IN (23, 24, 25)))
        BEGIN
            SET @ReturnVal = 1
        END
        ELSE
        BEGIN
            SET @ReturnVal = 0
        END

        Return @ReturnVal;

以下是执行存储过程的一行示例数据(每行除去测试顺序):

  

SalesOrder客户PlannedShipDate LatestShipDate PlanFabComplete CommittedShipDate MatofCons FabRating大会评分OpenShipped electrical_status dp_credit_status fldCustRequestDate commercial_terms Approved_by fldLiquidatedDamages fldLiquidatedDamagesDesc好友名单CommitDate TermsMet SortByDate fldShipmentRequestID InspectionType fldInspectionNotes DueDateExtraTime InspectionDesc advanced_buying SortedOrder SalesOrderStatusGroup SalesOrderStatus SpecialOpList OperationDueBy测试wpStatus SpecialOpsCount InChangeOrder RequiresSpecialPaint   76506测试客户6/16/2020 12/31/2020 NULL 11/28/2016 SS CC在测试中打开0 9/29/2016 NULL Premount / Prewire 0 NULL是11/28/2016 0 0 NULL NULL NULL 7 0完成26详细信息NULL 6/2/2020详细信息:6 NULL 0 0 0

enter image description here 最后,下面是一个屏幕截图,显示了如何在主窗体上显示和组织数据。

enter image description here

- 编辑 - 更改调用内联表函数的函数后的最新查询执行计划。 Latest Query Execution Plan

1 个答案:

答案 0 :(得分:1)

查询优化更像是一种艺术形式而非科学。

最突出的是,您所使用的许多功能都是以命令式的方式编写的。作为一个起点,我将研究是否可以将针对函数调用的OUTER APPLY重写为对视图的LEFT JOIN(如果函数对于此报告是唯一的,则是内联编写的,或者是针对预定义的视图)。

例如,函数udfRequiresSpecialColor可以重写为:

SELECT
    dbo.Product.Job_number

FROM 
    dbo.MfgGrouping 

INNER JOIN
    dbo.ProductMfgGrouping 
    ON dbo.MfgGrouping.MfgGroupingID = dbo.ProductMfgGrouping.MfgGroupingID 

INNER JOIN
    dbo.Product 
    ON dbo.ProductMfgGrouping.Record_no = dbo.Product.Record_no 

INNER JOIN 
    dbo.GroupOperations 
    ON dbo.MfgGrouping.MfgGroupingID = dbo.GroupOperations.MfgGroupingID
    AND (dbo.GroupOperations.ShopRoutingID IN (23, 24, 25))

这将返回一个包含所有 Job_number的表,这些表需要特殊颜色,可以加入。

然后,在主查询中,替换以下OUTER APPLY:

SELECT
    ...
    RequiresSpecialPaint
    ...
OUTER APPLY
(
    SELECT dbo.udfRequiresSpecialColor(JC.job_number) AS RequiresSpecialPaint
) AS jcolumn

...并在主查询中替换为LEFT JOIN:

SELECT
    ...
    IIF(jobs_requiring_special_paint.job_number IS NOT NULL, 1, 0) AS RequiresSpecialPaint
    ...

LEFT JOIN
    (
        [here you can either a call to the new udfRequiresSpecialColor defined as a database view or an inlinable function, or simply include the code above as a subquery]
    ) AS jobs_requiring_special_paint
    ON (JC.job_number = jobs_requiring_special_paint.job_number)

通过左键连接到此表,将有一个job_number用于那些具有特殊绘制的作业,并且那些作业的NULL值将不会被转换为0/1标记。选择语句,而不是成为子函数的一部分。

您可以看到一般情况,您可以看到查询的整个部分处理获取特殊颜料数据,现在以纯粹基于集合的方式处理。

删除命令式代码使查询优化器能够以更高效的方式分析和重新组织查询,同时保留您定义的逻辑。

您最终还可以发现,当前各种单独的OUTER APPLY查询可以压缩为相关表关系的单个公共定义(或更少的通用定义),并在ON子句中应用必要的过滤。 / p>

例如,udfGetDueByPerOperation似乎与udfRequiresSpecialColor(那些表为MfgGrouping, ProductMfgGrouping, Product, GroupOperations)和相同的基本关系(相同键上的INNER JOIN)在同一个表中,但是最后加ShopRouting

因此可以定义公共代码(作为数据库视图或内联函数,或作为公用表表达式/ WITH子句),以及在针对公用表的最终JOIN子句中实现的过滤。这可能会使代码更短,更容易理解和维护,并且它可能有助于查询引擎优化其计划。如果需要,我可以更多地讨论如何应用这种方法。

我注意到有一些函数,例如udfGetManStatusNew,它们具有相对复杂的决策逻辑,这可能很难简化为基于表达式的计算,同时保持清晰度和正确性。

尽管如此,即使作为部分解决方案而没有从函数中完全消除命令性代码,如果以给定表在所有job_numbers中,为了所有相关作业的详细信息,点击job_control表,使用OUTER APPLY命中每个作业的udfGetGroupOperationsCount函数(或使用上述技术减少OUTER APPLY)到LEFT JOIN)并将@OperationCount作为附加列捕获(而不是分配给标量变量)。然后,一旦&#39;成分&#39;函数已经以这种方式收集到一个表中,然后遍历命令式代码,以获得每个作业状态的必要计算。)

我不想预先判断您将从这种一般方法中获得的结果,因为查询引擎可能无法预测,但我怀疑它是否应该提高性能,如果可以改进的话。

如果您可以了解查询的哪些部分对其不良性能的贡献最大,也可能会有所帮助 - 假设它不是一直很慢。

如果您需要更多指导,请随时提出。如果你对此感到高兴,请告诉我。

修改 更多信息,基于以下评论。

我刚刚意识到我误解了您发布的查询计划 - 因为功能是必不可少的,它不会显示它们的查询计划,也不包括它们的成本。如果您将它们重写为无法使用的函数,请发布另一个查询计划,该计划将开始显示查询计划以及函数本身的全部成本(当前它们作为低成本常量扫描出现在查询计划中,没有进一步的计划信息)。

命令式/多语句函数和无法使用的函数之间的区别如下(注意为了避免混淆,我在SQL Server中有一个DUAL表,以镜像默认情况下内置的Oracle功能):

CREATE FUNCTION [dbo].[fxn_imperative] 
(   
     @dummy     VARCHAR(1)
)
RETURNS INT
AS
BEGIN
    DECLARE @ReturnVal int;

    IF EXISTS (SELECT 1 FROM DUAL WHERE DUMMY = @dummy)
        BEGIN
            SET @ReturnVal = 1
        END
    ELSE
        BEGIN
            SET @ReturnVal = 0
        END

    Return @ReturnVal;
END
-- called like so: SELECT dbo.fxn_imperative('X') AS dummy_exists;


CREATE FUNCTION [dbo].[fxn_inline] 
(   
     @dummy     VARCHAR(1)
)
RETURNS TABLE 
AS
RETURN 
(
    SELECT ISNULL( (SELECT 1 FROM DUAL WHERE DUMMY = @dummy), 0) AS dummy_exists
)
-- called like so: SELECT * FROM fxn_inline('X');

这些函数在功能上或多或少相同 - 但只有内联函数才会出现在调用函数的查询的查询计划中。

关于LEFT JOIN方法,在这种情况下,您不要将内部查询定义为函数 - 将其定义为视图(或简单地将其作为子查询内联编写)并连接到它上(使用job_number)作为连接条件,作为已传递给原始函数的参数的替换。我已经大致展示了如何在上面应用这种方法作为原始帖子的一部分。

如果我想了解现有查询的处理方式(就调用OUTER APPLYed的函数而言),我将如下定义函数(我假设特殊绘制的基础查询只返回每个作业/销售订单的单行:

CREATE FUNCTION [dbo].[udfRequiresSpecialColor2] 
(   
     @SalesOrder INT
)
RETURNS TABLE 
AS
RETURN 
(

    WITH special_paint_subquery AS
    (
        SELECT
            dbo.Product.Job_number

        FROM 
            dbo.MfgGrouping 

        INNER JOIN
            dbo.ProductMfgGrouping 
            ON dbo.MfgGrouping.MfgGroupingID = dbo.ProductMfgGrouping.MfgGroupingID 

        INNER JOIN
            dbo.Product 
            ON dbo.ProductMfgGrouping.Record_no = dbo.Product.Record_no 

        INNER JOIN 
            dbo.GroupOperations 
            ON dbo.MfgGrouping.MfgGroupingID = dbo.GroupOperations.MfgGroupingID
            AND (dbo.GroupOperations.ShopRoutingID IN (23, 24, 25))

    )

    SELECT ISNULL( (SELECT 1 FROM special_paint_subquery WHERE dbo.Product.Job_number = @SalesOrder), 0) AS requires_special_paint
)

如果以这种方式编写函数,如果您获得主查询的计划,则会显示该函数的计划。

调用函数的方式与当前调用udfRequiresSpecialColor的方式相同 - 通过交叉应用作为参数传递的job_number。

一旦以这种方式定义了函数,实际上将函数调用转换为左连接变得微不足道(WITH special_paint_subquery ...部分进入视图定义,WHERE dbo.Product.Job_number = @SalesOrder进入连接条件主查询和主查询的SELECT语句被修改为将NULL匹配转换为零,如我最初所示。)