• Okay. Taking this just a little bit further, I have added one more test to the suite, I hard-coded the calculation being done by the functions. I have also added some code from my 5 year old blog post where I compared hard-coded functions, scalar functions, and itvf's.

    Have a look:

    --I changed the order of these functions to the order in which

    --they appear in the output.

    --===== Alan's orignal code.

    -- This actually is NOT an "iTVF". It's an "mTVF"

    -- which is as bad or worse than a scalar UDR>

    CREATE FUNCTION dbo.nsq_iTVF (@int int)

    RETURNS @rs TABLE (n bigint) WITH SCHEMABINDING

    AS

    BEGIN

    INSERT @rs SELECT @int/2;

    RETURN;

    END

    GO

    --===== Alan's orignal code

    -- This is a scalar UDF

    CREATE FUNCTION dbo.nsq_iSVF (@int int)

    RETURNS bigint WITH SCHEMABINDING

    AS

    BEGIN

    RETURN @int/2

    END

    GO

    --===== Lynn's true iTVF code being used

    -- as if a scalar UDF. (changed the name for testing)

    CREATE FUNCTION dbo.Lynn_iTVF (@int bigint)

    RETURNS TABLE WITH SCHEMABINDING

    AS

    return (SELECT cast(@int/2 as bigint) divby2);

    GO

    --===== Create some test data (Alan's original code)

    IF OBJECT_ID('tempdb..#tmp') IS NOT NULL

    DROP TABLE #tmp;

    CREATE TABLE #tmp (n bigint);

    INSERT #tmp

    SELECT TOP 100000 ABS(CHECKSUM(NEWID()))

    FROM sys.all_columns ac1 CROSS JOIN sys.all_columns ac2;

    GO

    RAISERROR('

    ======================================================================

    Now, do the exact same tests adding hard-coding of the calculation

    being done with the various functions with a simple DURATION calculation

    instead of using SET STATISTICS, plus calculations from sys.db_exec_requests.

    Also clearing proccache and systemcache.

    ======================================================================

    ',0,1) WITH NOWAIT

    ;

    GO

    RAISERROR('========== nsq_iTVF (mTVF) ===========================================',0,1) WITH NOWAIT

    ;

    --===== Create the timer and bit-bucket variables and start the timer.

    DECLARE @StartTime DATETIME,

    @Bitbucket BIGINT;

    Declare @cpu_ int,

    @lreads_ int,

    @eMsec_ int;

    declare @CpuMs int,

    @LogRds int,

    @Elapsed int;

    dbcc freeproccache with no_infomsgs;

    dbcc freesystemcache('ALL') with no_infomsgs;

    Select

    @StartTime = GETDATE(),

    @cpu_ = cpu_time

    , @lreads_ = logical_reads

    , @eMsec_ = total_elapsed_time

    From

    sys.dm_exec_requests

    Where

    session_id = @@spid;

    ---

    --===== Test the code

    SELECT @Bitbucket = x.n,

    @Bitbucket = s.n

    FROM #tmp x

    CROSS APPLY dbo.nsq_iTVF(x.n) s

    ;

    ---

    Select

    @CpuMs = cpu_time - @cpu_

    , @LogRds = logical_reads - @lreads_

    , @Elapsed = total_elapsed_time - @eMsec_

    From

    sys.dm_exec_requests

    Where

    session_id = @@spid;

    --===== Display the duration

    PRINT 'Duration (ms): ' + CAST(DATEDIFF(ms,@StartTime,GETDATE()) AS VARCHAR(10)) +

    ' CPU(ms): ' + cast(@CpuMs as varchar(10)) + ' Logical Reads: ' + cast(@LogRds as varchar(10)) + ' Elapsed(ms): ' + cast(@Elapsed as varchar(10))

    ;

    GO

    RAISERROR('========== nsq_iSVF (scalar) =========================================',0,1) WITH NOWAIT

    ;

    --===== Create the timer and bit-bucket variables and start the timer.

    DECLARE @StartTime DATETIME,

    @Bitbucket BIGINT;

    Declare @cpu_ int,

    @lreads_ int,

    @eMsec_ int;

    declare @CpuMs int,

    @LogRds int,

    @Elapsed int;

    dbcc freeproccache with no_infomsgs;

    dbcc freesystemcache('ALL') with no_infomsgs;

    Select

    @StartTime = GETDATE(),

    @cpu_ = cpu_time

    , @lreads_ = logical_reads

    , @eMsec_ = total_elapsed_time

    From

    sys.dm_exec_requests

    Where

    session_id = @@spid;

    ---

    --===== Test the code

    SELECT @Bitbucket = n,

    @Bitbucket = dbo.nsq_iSVF(n)

    FROM #tmp x

    ;

    --===== Test the code

    SELECT @Bitbucket = x.n,

    @Bitbucket = s.n

    FROM #tmp x

    CROSS APPLY dbo.nsq_iTVF(x.n) s

    ;

    ---

    Select

    @CpuMs = cpu_time - @cpu_

    , @LogRds = logical_reads - @lreads_

    , @Elapsed = total_elapsed_time - @eMsec_

    From

    sys.dm_exec_requests

    Where

    session_id = @@spid;

    --===== Display the duration

    PRINT 'Duration (ms): ' + CAST(DATEDIFF(ms,@StartTime,GETDATE()) AS VARCHAR(10)) +

    ' CPU(ms): ' + cast(@CpuMs as varchar(10)) + ' Logical Reads: ' + cast(@LogRds as varchar(10)) + ' Elapsed(ms): ' + cast(@Elapsed as varchar(10))

    ;

    GO

    RAISERROR('========== Lynn_iTVF (real iTVF) =====================================',0,1) WITH NOWAIT

    ;

    --===== Create the timer and bit-bucket variables and start the timer.

    DECLARE @StartTime DATETIME,

    @Bitbucket BIGINT;

    Declare @cpu_ int,

    @lreads_ int,

    @eMsec_ int;

    declare @CpuMs int,

    @LogRds int,

    @Elapsed int;

    dbcc freeproccache with no_infomsgs;

    dbcc freesystemcache('ALL') with no_infomsgs;

    Select

    @StartTime = GETDATE(),

    @cpu_ = cpu_time

    , @lreads_ = logical_reads

    , @eMsec_ = total_elapsed_time

    From

    sys.dm_exec_requests

    Where

    session_id = @@spid;

    ---

    --===== Test the code

    SELECT @Bitbucket = x.n,

    @Bitbucket = s.divby2

    FROM #tmp x

    CROSS APPLY dbo.Lynn_iTVF(x.n) s

    ;

    ---

    Select

    @CpuMs = cpu_time - @cpu_

    , @LogRds = logical_reads - @lreads_

    , @Elapsed = total_elapsed_time - @eMsec_

    From

    sys.dm_exec_requests

    Where

    session_id = @@spid;

    --===== Display the duration

    PRINT 'Duration (ms): ' + CAST(DATEDIFF(ms,@StartTime,GETDATE()) AS VARCHAR(10)) +

    ' CPU(ms): ' + cast(@CpuMs as varchar(10)) + ' Logical Reads: ' + cast(@LogRds as varchar(10)) + ' Elapsed(ms): ' + cast(@Elapsed as varchar(10))

    ;

    GO

    RAISERROR('========== Hard-coded computation =====================================',0,1) WITH NOWAIT

    ;

    --===== Create the timer and bit-bucket variables and start the timer.

    DECLARE @StartTime DATETIME,

    @Bitbucket BIGINT;

    Declare @cpu_ int,

    @lreads_ int,

    @eMsec_ int;

    declare @CpuMs int,

    @LogRds int,

    @Elapsed int;

    dbcc freeproccache with no_infomsgs;

    dbcc freesystemcache('ALL') with no_infomsgs;

    Select

    @StartTime = GETDATE(),

    @cpu_ = cpu_time

    , @lreads_ = logical_reads

    , @eMsec_ = total_elapsed_time

    From

    sys.dm_exec_requests

    Where

    session_id = @@spid;

    ---

    --===== Test the code

    SELECT @Bitbucket = x.n,

    @Bitbucket = x.n/2

    FROM #tmp x

    ;

    ---

    Select

    @CpuMs = cpu_time - @cpu_

    , @LogRds = logical_reads - @lreads_

    , @Elapsed = total_elapsed_time - @eMsec_

    From

    sys.dm_exec_requests

    Where

    session_id = @@spid;

    --===== Display the duration

    PRINT 'Duration (ms): ' + CAST(DATEDIFF(ms,@StartTime,GETDATE()) AS VARCHAR(10)) +

    ' CPU(ms): ' + cast(@CpuMs as varchar(10)) + ' Logical Reads: ' + cast(@LogRds as varchar(10)) + ' Elapsed(ms): ' + cast(@Elapsed as varchar(10))

    ;

    GO

    DROP FUNCTION dbo.nsq_iTVF;

    DROP FUNCTION dbo.nsq_iSVF;

    DROP FUNCTION dbo.Lynn_iTVF;

    GO

    Here are my results on my 8 year old single processor hyper-threaded system:

    (100000 row(s) affected)

    ======================================================================

    Now, do the exact same tests adding hard-coding of the calculation

    being done with the various functions with a simple DURATION calculation

    instead of using SET STATISTICS, plus calculations from sys.db_exec_requests.

    Also clearing proccache and systemcache.

    ======================================================================

    ========== nsq_iTVF (mTVF) ===========================================

    Duration (ms): 14710 CPU(ms): 13984 Logical Reads: 1000393 Elapsed(ms): 14710

    ========== nsq_iSVF (scalar) =========================================

    Duration (ms): 14356 CPU(ms): 13766 Logical Reads: 1000631 Elapsed(ms): 14354

    ========== Lynn_iTVF (real iTVF) =====================================

    Duration (ms): 63 CPU(ms): 62 Logical Reads: 289 Elapsed(ms): 65

    ========== Hard-coded computation =====================================

    Duration (ms): 63 CPU(ms): 63 Logical Reads: 253 Elapsed(ms): 64