• phosplait (6/16/2015)


    So it seems this is definitely an issue of parameter sniffing.

    While option(recompile) did nothing, option(optimize for unknown) brought the dynamic query down to 3 seconds. Still slower, but I can live with this.

    Is there some more correct way to fix this, or would simply leaving that as part of the query be the best solution?

    The first posting of the History function looks like this:

    CREATE FUNCTION [dbo].[history] (

    @First DATE,

    @DatedStart DATE = '6/1/2014',

    @DatedEnd DATE = NULL,

    @Number FLOAT,

    @Year INT,

    @Sub INT = 5000000

    )

    ...

    SELECT DATEADD(day, num - 1, @Sub) AS thedate,

    which of course throws an error. I might be wrong, but this suggests that you're in the middle of designing the process, rather than query tuning a process which has been identified as a bottleneck. If this is the case you might want to reconsider the design and configure the inner iTVF as a bogstandard query and reconfigure the outer iTVF as a new function returning a bunch of dates. I'm confident you'd have a far less messy structure to work with. Rejigging your inner iTVF results in something like this:

    SELECT

    [Year] = YEAR(o.Date),

    o.Object,

    Amt = SUM(x.ModifiedSize)

    FROM [Object] o

    INNER JOIN transactions t

    ON t.object = o.object

    CROSS APPLY (

    SELECT ModifiedSize = CASE t.TypeIndicator

    WHEN 'P' THEN isnull(Amt, @Substitution) * - 1

    WHEN 'S' THEN isnull(Amt, @Substitution)

    ELSE 0 END

    ) x

    WHERE o.DatedDate >= @EarliestDated

    AND (@LatestDated IS NULL OR o.DatedDate <= @LatestDated)

    AND (@Number IS NULL OR o.Number = @Number)

    AND (@Year IS NULL OR YEAR(o.Date) = @Year)

    AND o.FinalSize IS NOT NULL

    AND t.TypeIndicator != 'D'

    AND (@OnDate IS NULL OR t.TransDate <= @OnDate)

    GROUP BY

    YEAR(o.Date),

    o.Object

    which is simple, easy to adapt, and easy to mark as a problem catch-all query to which the usual caveats and cures apply. The point to remember is this: if you run the process with a single date and then with the widest date range which makes sense with your data, the two execution plans are unlikely to be the same.

    “Write the query the simplest way. If through testing it becomes clear that the performance is inadequate, consider alternative query forms.” - Gail Shaw

    For fast, accurate and documented assistance in answering your questions, please read this article.
    Understanding and using APPLY, (I) and (II) Paul White
    Hidden RBAR: Triangular Joins / The "Numbers" or "Tally" Table: What it is and how it replaces a loop Jeff Moden