Can this be converted to a set based query?

  • The image of a plan is useless... we always need the actual .sqlplan file.

  • Thanks Ninja --

    The plan was included in the previous post -- I was simply posting a pitcture to get Wayne's comfirmation that I was looking in the same area of the plan as he was...

    Tony

  • Wayne,

    Missed one: Yes I tried the index order both ways -- the invoicekey is currently first.

  • tfeuz (6/6/2011)


    Thanks Ninja --

    The plan was included in the previous post -- I was simply posting a pitcture to get Wayne's comfirmation that I was looking in the same area of the plan as he was...

    Tony

    Ya missed it... I'm more skimming on this thread more than anything else.

  • tfeuz (6/6/2011)


    Wayne...

    Here is index #1

    USE [TBR3]

    GO

    /****** Object: Index [_dta_index_InvoiceLineItem_43_800057936__K2_K28_K17_K21_K1_10] Script Date: 06/06/2011 11:24:37 ******/

    CREATE NONCLUSTERED INDEX [_dta_index_InvoiceLineItem_43_800057936__K2_K28_K17_K21_K1_10] ON [dbo].[InvoiceLineItem]

    (

    [InvoiceKey] ASC,

    [ProductRebateCategory] ASC,

    [GrossAmount] ASC,

    [NetAmount] ASC,

    [InvoiceLineKey] ASC

    )

    INCLUDE ( [UnitsShipped]) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]

    GO

    Here is index #2

    USE [TBR3]

    GO

    /****** Object: Index [PK_InvoiceLineItem] Script Date: 06/06/2011 11:25:11 ******/

    ALTER TABLE [dbo].[InvoiceLineItem] ADD CONSTRAINT [PK_InvoiceLineItem] PRIMARY KEY CLUSTERED

    (

    [InvoiceLineKey] ASC

    )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]

    GO

    I looked at plan (see attached image) -- I assume the problem area is what you are looking at?

    I was going to try and attempt to generate the "missing index" myself....

    I think it should be on invoicekey and include grossamount, netamount and unitsshipped.

    It appears that Index #1 has 2 of the 3 (it is missing units)....

    Am I on the right track?

    1. Yes... but your image is showing it as 4%; I'm showing it as 40%.

    2. What "missing index" were you going to generate?

    3. Actually, Index #1 has the UnitsShipped column as an included column already.

    tfeuz (6/6/2011)


    Wayne,

    Missed one: Yes I tried the index order both ways -- the invoicekey is currently first.

    Is this the way that the "slow" query plan is for?

    Can you build the index the other way, run it, and attach that query plan?

    Wayne
    Microsoft Certified Master: SQL Server 2008
    Author - SQL Server T-SQL Recipes


    If you can't explain to another person how the code that you're copying from the internet works, then DON'T USE IT on a production system! After all, you will be the one supporting it!
    Links:
    For better assistance in answering your questions
    Performance Problems
    Common date/time routines
    Understanding and Using APPLY Part 1 & Part 2

  • Wayne,

    I have attached the 2 query plans - one name invoicekeyfirst and one named invoicekeysecond....

    Ignore my other questions -- I was off down a wrong path...

    Tony

    Just so we are on the same page -- this is the current SP we are working with. The ones using string concatentation took at least 2-3 times longer to execute:

    -- fastest so far

    CREATE PROCEDURE spCalculateRuleInvoiceUnits @RuleUnitType numeric(9,2),@TermsRuleType numeric(9,2),@RuleId decimal(18,0)

    AS

    DECLARE @CalcDateType INT;

    SELECT @CalcDateType = CalcDateType

    FROM dbo.RB_Rule

    WHERE RB_RuleId = @RuleId;

    ;

    WITH cteMain AS

    (

    SELECT

    c.InvoiceKey,

    b.InvoiceDate,

    b.ShipToKey,

    b.ShipToDiscountDueDate,

    b.ShipToNetDueDate,

    b.TermsDiscountDueDate,

    b.TermsNetDueDate,

    c.RulePeriodId

    FROM dbo.RB_InvoicesToProcess c

    JOIN dbo.Invoice b

    ON c.InvoiceKey = b.InvoiceKey

    WHERE c.RB_RuleId = @RuleId

    UNION

    SELECT

    c.InvoiceKey,

    b.InvoiceDate,

    b.ShipToKey,

    b.ShipToDiscountDueDate,

    b.ShipToNetDueDate,

    b.TermsDiscountDueDate,

    b.TermsNetDueDate,

    c.RulePeriodId

    FROM dbo.RB_InvoicesToProcess_Moved c

    JOIN dbo.Invoice b

    ON c.InvoiceKey = b.InvoiceKey

    WHERE c.RB_RuleId = @RuleId

    ), cteMain2 AS

    (

    SELECT cteMain.*,

    fn.*,

    InvoiceDate2 = CASE (@CalcDateType)

    WHEN 1 THEN cteMain.ShipToDiscountDueDate

    WHEN 2 THEN cteMain.ShipToNetDueDate

    WHEN 3 THEN cteMain.TermsDiscountDueDate

    WHEN 4 THEN cteMain.TermsNetDueDate

    ELSE cteMain.InvoiceDate

    END,

    IsAssociated = CASE cteMain.RulePeriodId

    WHEN -1 THEN 0

    WHEN -2 THEN 0

    WHEN -3 THEN -3

    ELSE 1

    END

    FROM cteMain

    CROSS APPLY dbo.fnCalculateRuleInvoiceUnits_Single(@RuleUnitType, @TermsRuleType, @RuleId, cteMain.InvoiceKey) fn

    )

    INSERT INTO dbo.[RB_RuleInvoice]

    ([RB_RuleId],

    [RB_RulePeriodId],

    [InvoiceKey],

    [IsAssociated],

    [ForcastData],

    [RebateUnits],

    [GrossAmount],

    [NetAmount],

    [Units],

    [DealerId],

    [RebateAmount],

    [RebateAmountPaid],

    [RebateAmountActual],

    [ReallocationAmount],

    [ReallocationAmountPaid],

    [ReallocationPaidFlag],

    [PostPeriodAdjustAmount],

    [TotalInvoiceNotPaid],

    [TotalReallocation],

    [PercentPayable])

    SELECT @RuleId,

    CASE WHEN t.RulePeriodId IS NULL OR t.RulePeriodId IN (-1,-3) THEN ISNULL(caAll.RB_RulePeriodId, caNext.RB_RulePeriodId)

    ELSE t.RulePeriodId

    END,

    t.InvoiceKey,

    t.IsAssociated,

    0,

    t.RebateUnits,

    t.TotalGross,

    t.TotalNet,

    t.TotalUnits,

    t.ShipToKey,

    0,

    0,

    0,

    0,

    0,

    0,

    0,

    0,

    0,

    0

    FROM cteMain2 t

    CROSS APPLY (SELECT RB_RulePeriodId

    FROM dbo.RB_RulePeriod

    WHERE RB_RuleId = @RuleId

    AND PeriodStarting <= t.InvoiceDate2

    AND PeriodEnding >= t.InvoiceDate2

    AND Reconciled = 0 ) caAll

    CROSS APPLY (SELECT TOP (1)

    RB_RulePeriodId

    FROM dbo.RB_RulePeriod

    WHERE RB_RuleId = @RuleId

    AND PeriodStarting >= t.InvoiceDate2

    AND Reconciled = 0

    ORDER BY RB_RulePeriodId ASC

    ) caNext;

  • tfeuz (6/6/2011)


    Wayne,

    Just so we are on the same page -- this is the current SP we are working with. The ones using string concatentation took at least 2-3 times longer to execute:

    Tony,

    I really think that this is the wrong track to take - tackling that next area could be the thing that makes this shine. Sometimes, you end up taking a step back to make that big leap forward, which is where I think we're at. As it is, the approach you're rejecting is reducing the Invoice table activity branch to < 1%, where the code you want to use has it at 74%. At 1%, it is clearly showing the next areas of improvement.

    But, if that's what you want, then you need to do the 6 procedure approach as I detailed in this post.

    Wayne
    Microsoft Certified Master: SQL Server 2008
    Author - SQL Server T-SQL Recipes


    If you can't explain to another person how the code that you're copying from the internet works, then DON'T USE IT on a production system! After all, you will be the one supporting it!
    Links:
    For better assistance in answering your questions
    Performance Problems
    Common date/time routines
    Understanding and Using APPLY Part 1 & Part 2

  • Tony,

    Can you add SET STATISTICS IO,TIME ON; to the test that you're running (not to the procedures), and send the results?

    Please do it for "slow" and "InvoiceKeyFirst" methods.

    Wayne
    Microsoft Certified Master: SQL Server 2008
    Author - SQL Server T-SQL Recipes


    If you can't explain to another person how the code that you're copying from the internet works, then DON'T USE IT on a production system! After all, you will be the one supporting it!
    Links:
    For better assistance in answering your questions
    Performance Problems
    Common date/time routines
    Understanding and Using APPLY Part 1 & Part 2

  • Wayne,

    I am certainly not going to change taking your advice at this point 😉

    That also explains why my plan was show operations on the invoice table of over 20%

    But I am glad I did clarify where we are at....

    Here is the stored procedure...

    CREATE PROCEDURE spCalculateRuleInvoiceUnits @RuleUnitType numeric(9,2),@TermsRuleType numeric(9,2),@RuleId decimal(18,0)

    AS

    DECLARE @Col2Use sysname,

    @SQLCmd NVARCHAR(MAX);

    SELECT @Col2Use = CASE (CalcDateType)

    WHEN 1 THEN 'ShipToDiscountDueDate'

    WHEN 2 THEN 'ShipToNetDueDate'

    WHEN 3 THEN 'TermsDiscountDueDate'

    WHEN 4 THEN 'TermsNetDueDate'

    ELSE 'InvoiceDate'

    END

    FROM dbo.RB_Rule

    WHERE RB_RuleId = @RuleId;

    SET @SQLCmd =

    ';

    WITH cteMain AS

    (

    SELECT c.InvoiceKey,

    b.ShipToKey,

    c.RulePeriodId,

    b.' + @Col2Use + '

    FROM dbo.RB_InvoicesToProcess c

    JOIN dbo.Invoice b

    ON c.InvoiceKey = b.InvoiceKey

    WHERE c.RB_RuleId = @RuleId

    UNION

    SELECT c.InvoiceKey,

    b.ShipToKey,

    c.RulePeriodId,

    b.' + @Col2Use + '

    FROM dbo.RB_InvoicesToProcess_Moved c

    JOIN dbo.Invoice b

    ON c.InvoiceKey = b.InvoiceKey

    WHERE c.RB_RuleId = @RuleId

    ), cteMain2 AS

    (

    SELECT cteMain.*,

    fn.*,

    IsAssociated = CASE cteMain.RulePeriodId

    WHEN -1 THEN 0

    WHEN -2 THEN 0

    WHEN -3 THEN -3

    ELSE 1

    END

    FROM cteMain

    CROSS APPLY dbo.fnCalculateRuleInvoiceUnits_Single(@RuleUnitType, @TermsRuleType, @RuleId, cteMain.InvoiceKey) fn

    )

    INSERT INTO dbo.[RB_RuleInvoice]

    ([RB_RuleId],

    [RB_RulePeriodId],

    [InvoiceKey],

    [IsAssociated],

    [ForcastData],

    [RebateUnits],

    [GrossAmount],

    [NetAmount],

    [Units],

    [DealerId],

    [RebateAmount],

    [RebateAmountPaid],

    [RebateAmountActual],

    [ReallocationAmount],

    [ReallocationAmountPaid],

    [ReallocationPaidFlag],

    [PostPeriodAdjustAmount],

    [TotalInvoiceNotPaid],

    [TotalReallocation],

    [PercentPayable])

    SELECT @RuleId,

    CASE WHEN t.RulePeriodId IS NULL OR t.RulePeriodId IN (-1,-3) THEN ISNULL(caAll.RB_RulePeriodId, caNext.RB_RulePeriodId)

    ELSE t.RulePeriodId

    END,

    t.InvoiceKey,

    t.IsAssociated,

    0,

    t.RebateUnits,

    t.TotalGross,

    t.TotalNet,

    t.TotalUnits,

    t.ShipToKey,

    0,

    0,

    0,

    0,

    0,

    0,

    0,

    0,

    0,

    0

    FROM cteMain2 t

    CROSS APPLY (SELECT RB_RulePeriodId

    FROM dbo.RB_RulePeriod

    WHERE RB_RuleId = @RuleId

    AND PeriodStarting <= t.' + @Col2Use + '

    AND PeriodEnding >= t.' + @Col2Use + '

    AND Reconciled = 0 ) caAll

    CROSS APPLY (SELECT TOP (1)

    RB_RulePeriodId

    FROM dbo.RB_RulePeriod

    WHERE RB_RuleId = @RuleId

    AND PeriodStarting >= t.' + @Col2Use + '

    AND Reconciled = 0

    ORDER BY RB_RulePeriodId ASC

    ) caNext;

    ';

    EXECUTE sp_executesql @SQLCmd, N'@RuleUnitType numeric(9,2),@TermsRuleType numeric(9,2),@RuleId decimal(18,0)', @RuleUnitType, @TermsRuleType, @RuleId;

    I have attached the 2 query plans using the above procedure and changing the indexes as you requested....

    TOny

  • Wayne,

    Just saw your last post ---

    Here are the attached plans and the sql output...

    InvoiceKeyFirst:

    SQL Server parse and compile time:

    CPU time = 0 ms, elapsed time = 0 ms.

    SQL Server parse and compile time:

    CPU time = 0 ms, elapsed time = 0 ms.

    Table 'RB_Rule'. Scan count 1, logical reads 1, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

    (1 row(s) affected)

    SQL Server Execution Times:

    CPU time = 0 ms, elapsed time = 6 ms.

    SQL Server Execution Times:

    CPU time = 0 ms, elapsed time = 0 ms.

    SQL Server parse and compile time:

    CPU time = 0 ms, elapsed time = 0 ms.

    Table 'RB_RuleInvoice'. Scan count 0, logical reads 81317, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

    Table 'Worktable'. Scan count 317733, logical reads 2172231, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

    Table 'RB_RulePeriod'. Scan count 6, logical reads 6, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

    Table 'InvoiceTotal'. Scan count 79432, logical reads 239122, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

    Table 'InvoiceTotalTax'. Scan count 79432, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

    Table 'RB_RuleCategory'. Scan count 238296, logical reads 476592, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

    Table 'Invoice'. Scan count 5, logical reads 61999, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

    Table 'InvoiceLineItem'. Scan count 79432, logical reads 247626, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

    Table 'InvoiceTotalAdditionalCosts'. Scan count 79432, logical reads 238296, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

    Table 'Worktable'. Scan count 0, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

    Table 'RB_InvoicesToProcess_Moved'. Scan count 1, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

    Table 'RB_InvoicesToProcess'. Scan count 1, logical reads 408, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

    (79432 row(s) affected)

    (1 row(s) affected)

    SQL Server Execution Times:

    CPU time = 20109 ms, elapsed time = 20457 ms.

    SQL Server Execution Times:

    CPU time = 20109 ms, elapsed time = 20457 ms.

    SQL Server Execution Times:

    CPU time = 20109 ms, elapsed time = 20464 ms.

    SQL Server parse and compile time:

    CPU time = 0 ms, elapsed time = 0 ms.

    SQL Server Execution Times:

    CPU time = 0 ms, elapsed time = 0 ms.

    InvoiceKeySecond:

    SQL Server parse and compile time:

    CPU time = 0 ms, elapsed time = 0 ms.

    SQL Server Execution Times:

    CPU time = 0 ms, elapsed time = 0 ms.

    SQL Server parse and compile time:

    CPU time = 0 ms, elapsed time = 0 ms.

    SQL Server Execution Times:

    CPU time = 0 ms, elapsed time = 0 ms.

    SQL Server parse and compile time:

    CPU time = 0 ms, elapsed time = 0 ms.

    SQL Server parse and compile time:

    CPU time = 0 ms, elapsed time = 0 ms.

    Table 'RB_Rule'. Scan count 1, logical reads 1, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

    (1 row(s) affected)

    SQL Server Execution Times:

    CPU time = 0 ms, elapsed time = 0 ms.

    SQL Server Execution Times:

    CPU time = 0 ms, elapsed time = 0 ms.

    SQL Server parse and compile time:

    CPU time = 0 ms, elapsed time = 0 ms.

    Table 'RB_InvoicesToProcess'. Scan count 3, logical reads 1620, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

    Table 'Invoice'. Scan count 7, logical reads 63648, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

    Table 'Worktable'. Scan count 317733, logical reads 2172231, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

    Table 'RB_InvoicesToProcess_Moved'. Scan count 1, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

    Table 'Worktable'. Scan count 0, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

    Table 'InvoiceTotal'. Scan count 79432, logical reads 239122, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

    Table 'InvoiceTotalTax'. Scan count 79432, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

    Table 'RB_RuleCategory'. Scan count 238296, logical reads 476592, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

    Table 'InvoiceLineItem'. Scan count 79432, logical reads 247626, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

    Table 'InvoiceTotalAdditionalCosts'. Scan count 79432, logical reads 238296, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

    Table 'RB_RulePeriod'. Scan count 6, logical reads 6, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

    Table 'RB_RuleInvoice'. Scan count 0, logical reads 81317, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

    (79432 row(s) affected)

    (1 row(s) affected)

    SQL Server Execution Times:

    CPU time = 21890 ms, elapsed time = 20470 ms.

    SQL Server Execution Times:

    CPU time = 22093 ms, elapsed time = 20676 ms.

    SQL Server Execution Times:

    CPU time = 22093 ms, elapsed time = 20678 ms.

    SQL Server parse and compile time:

    CPU time = 0 ms, elapsed time = 0 ms.

    SQL Server Execution Times:

    CPU time = 0 ms, elapsed time = 0 ms.

  • Here is the slower one (although they all seem to be running about same now)

    CREATE PROCEDURE spCalculateRuleInvoiceUnits @RuleUnitType numeric(9,2),@TermsRuleType numeric(9,2),@RuleId decimal(18,0)

    AS

    DECLARE @Col2Use sysname,

    @SQLCmd VARCHAR(MAX);

    SELECT @Col2Use = CASE (CalcDateType)

    WHEN 1 THEN 'ShipToDiscountDueDate'

    WHEN 2 THEN 'ShipToNetDueDate'

    WHEN 3 THEN 'TermsDiscountDueDate'

    WHEN 4 THEN 'TermsNetDueDate'

    ELSE 'InvoiceDate'

    END

    FROM dbo.RB_Rule

    WHERE RB_RuleId = @RuleId;

    SET @SQLCmd =

    ';

    WITH cteMain AS

    (

    SELECT c.InvoiceKey,

    b.ShipToKey,

    c.RulePeriodId,

    b.' + @Col2Use + '

    FROM dbo.RB_InvoicesToProcess c

    JOIN dbo.Invoice b

    ON c.InvoiceKey = b.InvoiceKey

    WHERE c.RB_RuleId = ' + CAST(@RuleId as VARCHAR(MAX)) + '

    UNION

    SELECT c.InvoiceKey,

    b.ShipToKey,

    c.RulePeriodId,

    b.' + @Col2Use + '

    FROM dbo.RB_InvoicesToProcess_Moved c

    JOIN dbo.Invoice b

    ON c.InvoiceKey = b.InvoiceKey

    WHERE c.RB_RuleId = ' + CAST(@RuleId as VARCHAR(MAX)) + '

    ), cteMain2 AS

    (

    SELECT cteMain.*,

    fn.*,

    IsAssociated = CASE cteMain.RulePeriodId

    WHEN -1 THEN 0

    WHEN -2 THEN 0

    WHEN -3 THEN -3

    ELSE 1

    END

    FROM cteMain

    CROSS APPLY dbo.fnCalculateRuleInvoiceUnits_Single(' + CAST(@RuleUnitType as VARCHAR(MAX)) + ',' + CAST(@TermsRuleType as VARCHAR(MAX)) + ',' + CAST(@RuleId as VARCHAR(MAX)) + ', cteMain.InvoiceKey) fn

    )

    INSERT INTO dbo.[RB_RuleInvoice]

    ([RB_RuleId],

    [RB_RulePeriodId],

    [InvoiceKey],

    [IsAssociated],

    [ForcastData],

    [RebateUnits],

    [GrossAmount],

    [NetAmount],

    [Units],

    [DealerId],

    [RebateAmount],

    [RebateAmountPaid],

    [RebateAmountActual],

    [ReallocationAmount],

    [ReallocationAmountPaid],

    [ReallocationPaidFlag],

    [PostPeriodAdjustAmount],

    [TotalInvoiceNotPaid],

    [TotalReallocation],

    [PercentPayable])

    SELECT ' + CAST(@RuleId as VARCHAR(MAX)) + ',

    CASE WHEN t.RulePeriodId IS NULL OR t.RulePeriodId IN (-1,-3) THEN ISNULL(caAll.RB_RulePeriodId, caNext.RB_RulePeriodId)

    ELSE t.RulePeriodId

    END,

    t.InvoiceKey,

    t.IsAssociated,

    0,

    t.RebateUnits,

    t.TotalGross,

    t.TotalNet,

    t.TotalUnits,

    t.ShipToKey,

    0,

    0,

    0,

    0,

    0,

    0,

    0,

    0,

    0,

    0

    FROM cteMain2 t

    CROSS APPLY (SELECT RB_RulePeriodId

    FROM dbo.RB_RulePeriod

    WHERE RB_RuleId = ' + CAST(@RuleId as VARCHAR(MAX)) + '

    AND PeriodStarting <= t.' + @Col2Use + '

    AND PeriodEnding >= t.' + @Col2Use + '

    AND Reconciled = 0 ) caAll

    CROSS APPLY (SELECT TOP (1)

    RB_RulePeriodId

    FROM dbo.RB_RulePeriod

    WHERE RB_RuleId = ' + CAST(@RuleId as VARCHAR(MAX)) + '

    AND PeriodStarting >= t.' + @Col2Use + '

    AND Reconciled = 0

    ORDER BY RB_RulePeriodId ASC

    ) caNext;

    ';

    --print @SQLCmd

    EXECUTE (@SQLCmd);

    With the invoicekey first:

    SQL Server parse and compile time:

    CPU time = 0 ms, elapsed time = 0 ms.

    SQL Server Execution Times:

    CPU time = 0 ms, elapsed time = 0 ms.

    SQL Server parse and compile time:

    CPU time = 0 ms, elapsed time = 0 ms.

    SQL Server Execution Times:

    CPU time = 0 ms, elapsed time = 0 ms.

    SQL Server parse and compile time:

    CPU time = 0 ms, elapsed time = 0 ms.

    SQL Server parse and compile time:

    CPU time = 0 ms, elapsed time = 0 ms.

    Table 'RB_Rule'. Scan count 1, logical reads 1, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

    (1 row(s) affected)

    SQL Server Execution Times:

    CPU time = 0 ms, elapsed time = 0 ms.

    SQL Server Execution Times:

    CPU time = 0 ms, elapsed time = 0 ms.

    SQL Server parse and compile time:

    CPU time = 0 ms, elapsed time = 0 ms.

    Table 'RB_RuleInvoice'. Scan count 0, logical reads 81317, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

    Table 'Worktable'. Scan count 317733, logical reads 2172231, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

    Table 'RB_RulePeriod'. Scan count 6, logical reads 6, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

    Table 'InvoiceTotal'. Scan count 79432, logical reads 239122, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

    Table 'InvoiceTotalTax'. Scan count 79432, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

    Table 'RB_RuleCategory'. Scan count 238296, logical reads 476592, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

    Table 'Invoice'. Scan count 5, logical reads 61999, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

    Table 'InvoiceLineItem'. Scan count 79432, logical reads 247626, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

    Table 'InvoiceTotalAdditionalCosts'. Scan count 79432, logical reads 238296, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

    Table 'Worktable'. Scan count 0, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

    Table 'RB_InvoicesToProcess_Moved'. Scan count 1, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

    Table 'RB_InvoicesToProcess'. Scan count 1, logical reads 408, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

    (79432 row(s) affected)

    (1 row(s) affected)

    SQL Server Execution Times:

    CPU time = 18875 ms, elapsed time = 19381 ms.

    SQL Server Execution Times:

    CPU time = 19062 ms, elapsed time = 19577 ms.

    SQL Server Execution Times:

    CPU time = 19062 ms, elapsed time = 19579 ms.

    SQL Server parse and compile time:

    CPU time = 0 ms, elapsed time = 0 ms.

    SQL Server Execution Times:

    CPU time = 0 ms, elapsed time = 0 ms.

    With the invoicekey second

    SQL Server parse and compile time:

    CPU time = 0 ms, elapsed time = 0 ms.

    SQL Server Execution Times:

    CPU time = 0 ms, elapsed time = 0 ms.

    SQL Server parse and compile time:

    CPU time = 0 ms, elapsed time = 0 ms.

    SQL Server Execution Times:

    CPU time = 0 ms, elapsed time = 0 ms.

    SQL Server parse and compile time:

    CPU time = 0 ms, elapsed time = 0 ms.

    SQL Server parse and compile time:

    CPU time = 0 ms, elapsed time = 2 ms.

    Table 'RB_Rule'. Scan count 1, logical reads 1, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

    (1 row(s) affected)

    SQL Server Execution Times:

    CPU time = 0 ms, elapsed time = 0 ms.

    SQL Server Execution Times:

    CPU time = 0 ms, elapsed time = 0 ms.

    SQL Server parse and compile time:

    CPU time = 0 ms, elapsed time = 0 ms.

    Table 'RB_InvoicesToProcess'. Scan count 3, logical reads 1620, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

    Table 'Invoice'. Scan count 7, logical reads 63648, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

    Table 'Worktable'. Scan count 317733, logical reads 2172231, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

    Table 'RB_InvoicesToProcess_Moved'. Scan count 1, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

    Table 'Worktable'. Scan count 0, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

    Table 'InvoiceTotal'. Scan count 79432, logical reads 239122, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

    Table 'InvoiceTotalTax'. Scan count 79432, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

    Table 'RB_RuleCategory'. Scan count 238296, logical reads 476592, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

    Table 'InvoiceLineItem'. Scan count 79432, logical reads 247626, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

    Table 'InvoiceTotalAdditionalCosts'. Scan count 79432, logical reads 238296, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

    Table 'RB_RulePeriod'. Scan count 6, logical reads 6, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

    Table 'RB_RuleInvoice'. Scan count 0, logical reads 81317, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

    (79432 row(s) affected)

    (1 row(s) affected)

    SQL Server Execution Times:

    CPU time = 21860 ms, elapsed time = 20493 ms.

    SQL Server Execution Times:

    CPU time = 22063 ms, elapsed time = 20700 ms.

    SQL Server Execution Times:

    CPU time = 22063 ms, elapsed time = 20705 ms.

    SQL Server parse and compile time:

    CPU time = 0 ms, elapsed time = 0 ms.

    SQL Server Execution Times:

    CPU time = 0 ms, elapsed time = 0 ms.

  • I just spent a few minutes looking at one of your later plans. It is my belief that you have no hope of significant improvements based on your current approach to this solution. You cannot win with that many nested-loops-on-many-rows and spools (SEVEN of those!). You have painted yourself into a performance dead end with those CTEs and CROSS APPLYs. And I sure hope the function you have listed is an inline TVF or it gets worse (although that is actually a good thing because you can refactor that out for a potential perf gain). Oh, and you may well have a SORT/DISTINCT going on for no reason due to the user of UNION instead of UNION ALL (assuming there cannot be dupes between the two invoices to process tables.

    You could try forcing some non-loop (hash most likely?) joins but that may not be allowed with the query forms you currently have. Look to InvoiceLineItem first for this.

    Most likely you will need to break down into intermediate results to get any reasonable performance. The out-of-the-box part of my brain says to evaluate a cursor-based solution too, but since it isn't a running total I will ignore that recommendation. 🙂

    P.S. Stop worrying about percentages between refactors. It is useless to say table A is now 3% of total when it used to be 68%. You either improved the query as a whole by some metric that is important to you (duration, CPU, IO, etc) or you didn't.

    Best,
    Kevin G. Boles
    SQL Server Consultant
    SQL MVP 2007-2012
    TheSQLGuru on googles mail service

  • tfeuz (6/6/2011)


    Wayne,

    I am certainly not going to change taking your advice at this point 😉

    That also explains why my plan was show operations on the invoice table of over 20%

    But I am glad I did clarify where we are at....

    Here is the stored procedure...

    CREATE PROCEDURE spCalculateRuleInvoiceUnits @RuleUnitType numeric(9,2),@TermsRuleType numeric(9,2),@RuleId decimal(18,0)

    AS

    DECLARE @Col2Use sysname,

    @SQLCmd NVARCHAR(MAX);

    SELECT @Col2Use = CASE (CalcDateType)

    WHEN 1 THEN 'ShipToDiscountDueDate'

    WHEN 2 THEN 'ShipToNetDueDate'

    WHEN 3 THEN 'TermsDiscountDueDate'

    WHEN 4 THEN 'TermsNetDueDate'

    ELSE 'InvoiceDate'

    END

    FROM dbo.RB_Rule

    WHERE RB_RuleId = @RuleId;

    SET @SQLCmd =

    ';

    WITH cteMain AS

    (

    SELECT c.InvoiceKey,

    b.ShipToKey,

    c.RulePeriodId,

    b.' + @Col2Use + '

    FROM dbo.RB_InvoicesToProcess c

    JOIN dbo.Invoice b

    ON c.InvoiceKey = b.InvoiceKey

    WHERE c.RB_RuleId = @RuleId

    UNION

    SELECT c.InvoiceKey,

    b.ShipToKey,

    c.RulePeriodId,

    b.' + @Col2Use + '

    FROM dbo.RB_InvoicesToProcess_Moved c

    JOIN dbo.Invoice b

    ON c.InvoiceKey = b.InvoiceKey

    WHERE c.RB_RuleId = @RuleId

    ), cteMain2 AS

    (

    SELECT cteMain.*,

    fn.*,

    IsAssociated = CASE cteMain.RulePeriodId

    WHEN -1 THEN 0

    WHEN -2 THEN 0

    WHEN -3 THEN -3

    ELSE 1

    END

    FROM cteMain

    CROSS APPLY dbo.fnCalculateRuleInvoiceUnits_Single(@RuleUnitType, @TermsRuleType, @RuleId, cteMain.InvoiceKey) fn

    )

    INSERT INTO dbo.[RB_RuleInvoice]

    ([RB_RuleId],

    [RB_RulePeriodId],

    [InvoiceKey],

    [IsAssociated],

    [ForcastData],

    [RebateUnits],

    [GrossAmount],

    [NetAmount],

    [Units],

    [DealerId],

    [RebateAmount],

    [RebateAmountPaid],

    [RebateAmountActual],

    [ReallocationAmount],

    [ReallocationAmountPaid],

    [ReallocationPaidFlag],

    [PostPeriodAdjustAmount],

    [TotalInvoiceNotPaid],

    [TotalReallocation],

    [PercentPayable])

    SELECT @RuleId,

    CASE WHEN t.RulePeriodId IS NULL OR t.RulePeriodId IN (-1,-3) THEN ISNULL(caAll.RB_RulePeriodId, caNext.RB_RulePeriodId)

    ELSE t.RulePeriodId

    END,

    t.InvoiceKey,

    t.IsAssociated,

    0,

    t.RebateUnits,

    t.TotalGross,

    t.TotalNet,

    t.TotalUnits,

    t.ShipToKey,

    0,

    0,

    0,

    0,

    0,

    0,

    0,

    0,

    0,

    0

    FROM cteMain2 t

    CROSS APPLY (SELECT RB_RulePeriodId

    FROM dbo.RB_RulePeriod

    WHERE RB_RuleId = @RuleId

    AND PeriodStarting <= t.' + @Col2Use + '

    AND PeriodEnding >= t.' + @Col2Use + '

    AND Reconciled = 0 ) caAll

    CROSS APPLY (SELECT TOP (1)

    RB_RulePeriodId

    FROM dbo.RB_RulePeriod

    WHERE RB_RuleId = @RuleId

    AND PeriodStarting >= t.' + @Col2Use + '

    AND Reconciled = 0

    ORDER BY RB_RulePeriodId ASC

    ) caNext;

    ';

    EXECUTE sp_executesql @SQLCmd, N'@RuleUnitType numeric(9,2),@TermsRuleType numeric(9,2),@RuleId decimal(18,0)', @RuleUnitType, @TermsRuleType, @RuleId;

    I have attached the 2 query plans using the above procedure and changing the indexes as you requested....

    TOny

    Tony,

    1. The InvoiceKey definitely needs to be the first column in those 5 indexes. So, let's only use that from here on.

    2. Lets add another index to the Invoice table: InvoiceKey, SupplierKey INCLUDE(TermsDiscountAmount) (Yikes... that's 6 indexes being added to this table - but this should take care of 3 index scans and 1 table (CI) sc)

    Make sure you're using this parametrized dynamic sql procedure, and please include the statistics

    Wayne
    Microsoft Certified Master: SQL Server 2008
    Author - SQL Server T-SQL Recipes


    If you can't explain to another person how the code that you're copying from the internet works, then DON'T USE IT on a production system! After all, you will be the one supporting it!
    Links:
    For better assistance in answering your questions
    Performance Problems
    Common date/time routines
    Understanding and Using APPLY Part 1 & Part 2

  • As requested....

    Stats

    SQL Server parse and compile time:

    CPU time = 0 ms, elapsed time = 0 ms.

    SQL Server parse and compile time:

    CPU time = 0 ms, elapsed time = 0 ms.

    Table 'RB_Rule'. Scan count 1, logical reads 1, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

    (1 row(s) affected)

    SQL Server Execution Times:

    CPU time = 0 ms, elapsed time = 0 ms.

    SQL Server Execution Times:

    CPU time = 0 ms, elapsed time = 0 ms.

    SQL Server parse and compile time:

    CPU time = 0 ms, elapsed time = 0 ms.

    Table 'RB_RuleInvoice'. Scan count 0, logical reads 81318, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

    Table 'Worktable'. Scan count 79437, logical reads 543084, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

    Table 'RB_RulePeriod'. Scan count 6, logical reads 6, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

    Table 'InvoiceTotal'. Scan count 79432, logical reads 239122, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

    Table 'InvoiceTotalTax'. Scan count 79432, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

    Table 'Invoice'. Scan count 2, logical reads 715740, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

    Table 'RB_RuleCategory'. Scan count 238296, logical reads 476592, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

    Table 'InvoiceLineItem'. Scan count 79432, logical reads 247626, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

    Table 'InvoiceTotalAdditionalCosts'. Scan count 79432, logical reads 238296, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

    Table 'Worktable'. Scan count 0, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

    Table 'RB_InvoicesToProcess_Moved'. Scan count 1, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

    Table 'RB_InvoicesToProcess'. Scan count 1, logical reads 409, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

    (79432 row(s) affected)

    (1 row(s) affected)

    SQL Server Execution Times:

    CPU time = 16047 ms, elapsed time = 16751 ms.

    SQL Server Execution Times:

    CPU time = 16047 ms, elapsed time = 16751 ms.

    SQL Server Execution Times:

    CPU time = 16047 ms, elapsed time = 16753 ms.

    SQL Server parse and compile time:

    CPU time = 0 ms, elapsed time = 0 ms.

    SQL Server Execution Times:

    CPU time = 0 ms, elapsed time = 0 ms.

    Procedure -- just so we are on the same page

    CREATE PROCEDURE spCalculateRuleInvoiceUnits @RuleUnitType numeric(9,2),@TermsRuleType numeric(9,2),@RuleId decimal(18,0)

    AS

    DECLARE @Col2Use sysname,

    @SQLCmd VARCHAR(MAX);

    SELECT @Col2Use = CASE (CalcDateType)

    WHEN 1 THEN 'ShipToDiscountDueDate'

    WHEN 2 THEN 'ShipToNetDueDate'

    WHEN 3 THEN 'TermsDiscountDueDate'

    WHEN 4 THEN 'TermsNetDueDate'

    ELSE 'InvoiceDate'

    END

    FROM dbo.RB_Rule

    WHERE RB_RuleId = @RuleId;

    SET @SQLCmd =

    ';

    WITH cteMain AS

    (

    SELECT c.InvoiceKey,

    b.ShipToKey,

    c.RulePeriodId,

    b.' + @Col2Use + '

    FROM dbo.RB_InvoicesToProcess c

    JOIN dbo.Invoice b

    ON c.InvoiceKey = b.InvoiceKey

    WHERE c.RB_RuleId = ' + CAST(@RuleId as VARCHAR(MAX)) + '

    UNION

    SELECT c.InvoiceKey,

    b.ShipToKey,

    c.RulePeriodId,

    b.' + @Col2Use + '

    FROM dbo.RB_InvoicesToProcess_Moved c

    JOIN dbo.Invoice b

    ON c.InvoiceKey = b.InvoiceKey

    WHERE c.RB_RuleId = ' + CAST(@RuleId as VARCHAR(MAX)) + '

    ), cteMain2 AS

    (

    SELECT cteMain.*,

    fn.*,

    IsAssociated = CASE cteMain.RulePeriodId

    WHEN -1 THEN 0

    WHEN -2 THEN 0

    WHEN -3 THEN -3

    ELSE 1

    END

    FROM cteMain

    CROSS APPLY dbo.fnCalculateRuleInvoiceUnits_Single(' + CAST(@RuleUnitType as VARCHAR(MAX)) + ',' + CAST(@TermsRuleType as VARCHAR(MAX)) + ',' + CAST(@RuleId as VARCHAR(MAX)) + ', cteMain.InvoiceKey) fn

    )

    INSERT INTO dbo.[RB_RuleInvoice]

    ([RB_RuleId],

    [RB_RulePeriodId],

    [InvoiceKey],

    [IsAssociated],

    [ForcastData],

    [RebateUnits],

    [GrossAmount],

    [NetAmount],

    [Units],

    [DealerId],

    [RebateAmount],

    [RebateAmountPaid],

    [RebateAmountActual],

    [ReallocationAmount],

    [ReallocationAmountPaid],

    [ReallocationPaidFlag],

    [PostPeriodAdjustAmount],

    [TotalInvoiceNotPaid],

    [TotalReallocation],

    [PercentPayable])

    SELECT ' + CAST(@RuleId as VARCHAR(MAX)) + ',

    CASE WHEN t.RulePeriodId IS NULL OR t.RulePeriodId IN (-1,-3) THEN ISNULL(caAll.RB_RulePeriodId, caNext.RB_RulePeriodId)

    ELSE t.RulePeriodId

    END,

    t.InvoiceKey,

    t.IsAssociated,

    0,

    t.RebateUnits,

    CASE WHEN t.TotalGross is null then 0 else t.TotalGross end ,

    CASE WHEN t.TotalNet is null then 0 else t.TotalNet end,

    CASE WHEN t.TotalUnits is null then 0 else t.TotalUnits end,

    t.ShipToKey,

    0,

    0,

    0,

    0,

    0,

    0,

    0,

    0,

    0,

    0

    FROM cteMain2 t

    CROSS APPLY (SELECT RB_RulePeriodId

    FROM dbo.RB_RulePeriod

    WHERE RB_RuleId = ' + CAST(@RuleId as VARCHAR(MAX)) + '

    AND PeriodStarting <= t.' + @Col2Use + '

    AND PeriodEnding >= t.' + @Col2Use + '

    AND Reconciled = 0 ) caAll

    CROSS APPLY (SELECT TOP (1)

    RB_RulePeriodId

    FROM dbo.RB_RulePeriod

    WHERE RB_RuleId = ' + CAST(@RuleId as VARCHAR(MAX)) + '

    AND PeriodStarting >= t.' + @Col2Use + '

    AND Reconciled = 0

    ORDER BY RB_RulePeriodId ASC

    ) caNext;

    ';

    EXECUTE (@SQLCmd);

    SQL plan attached...

  • FYI: Wrong procedure. Need the one that has the parametrized string, calling sp_executesql at the end.

    Wayne
    Microsoft Certified Master: SQL Server 2008
    Author - SQL Server T-SQL Recipes


    If you can't explain to another person how the code that you're copying from the internet works, then DON'T USE IT on a production system! After all, you will be the one supporting it!
    Links:
    For better assistance in answering your questions
    Performance Problems
    Common date/time routines
    Understanding and Using APPLY Part 1 & Part 2

Viewing 15 posts - 76 through 90 (of 117 total)

You must be logged in to reply to this topic. Login to reply