• Hi David,

    I'm surprised to see so little comments yet. But who knows, maybe I'm not the only one with a reading backlog.

    In the beginning of your article, you write that RAP rewards developers for creating their foreign keys by generating lookup routines. But in the rest of the article, you only describe routines generated upon primary keys and unique constraints. So technicallly, the developer can still get away with not defining the foreign key, as long as the PK and UQ constraints are defined.

    More important is that the performance of your generated code on larger tables will be miserable. This is because you use multi-statement table-valued functions to retrieve rows. These are bad news for the optimizer - it has no other option but to execute them first, store the results, then combine these (unindexed) result sets for thte final result. Ouch!

    You should convert to inline table-valued functions. These, like views, are treated as macros - the reference to the function is first replaced by its definition, and only then will the optimizer be invoked to work out an execution plan. You'll see a major performance gain!

    As an example:

    create function UFTBadmUser##PK

    (

    -- declare the 'As Of' parameter

    @AsOf datetime,

    -- declare other parameters

    @userid bigint

    )

    returns table

    as

    return (select UserId,

    LoginName,

    Notes,

    AuditDate,

    AuditUserId,

    AuditStatus

    from TBadmUser

    where UserId = @userid

    and @AsOf is null

    union all

    select UserId,

    LoginName,

    Notes,

    AuditDate,

    AuditUserId,

    AuditStatus

    from TBadmUser#

    where UserId = @userid

    and AuditStatus <> 'D'

    and A.AuditDate = (select max(AuditDate) from TBadmUser#

    where UserId = A.UserId

    and AuditDate <= @AsOf)

    and @AsOf is not null

    );

    Another possible performance optimization is to create seperate function for querying live and archive data. That reduces complexity in the functions (making it easier for the optimizer to come up with an efficient plan). In my experience, it is quite uncommon to use the same queries on both live and archived data. (And since you generate the code, you could also go the whole way and simply generate functions for only live, for only archive, and for the combination, with a note to the developer to only use the latter when neeed, because the other perform better).


    Hugo Kornelis, SQL Server/Data Platform MVP (2006-2016)
    Visit my SQL Server blog: https://sqlserverfast.com/blog/
    SQL Server Execution Plan Reference: https://sqlserverfast.com/epr/