• Alan.B (3/1/2013)


    This is something I need to play around with more. I took what Jeff said to imply that, in the code below, the iTVF function (nsq_iTVF) would be faster than the iSVF (nsq_iSVF).

    CREATE FUNCTION dbo.nsq_iSVF (@int int)

    RETURNS bigint WITH SCHEMABINDING

    AS

    BEGIN

    RETURN @int/2

    END

    GO

    CREATE FUNCTION dbo.nsq_iTVF (@int int)

    RETURNS @rs TABLE (n bigint) WITH SCHEMABINDING

    AS

    BEGIN

    INSERT @rs SELECT @int/2;

    RETURN;

    END

    GO

    --Create some test data

    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;

    SET NOCOUNT ON;

    GO

    --Test the Functions (on my local PC)

    SET STATISTICS TIME ON

    SELECT x.n n1, s.n n2

    FROM #tmp x

    CROSS APPLY dbo.nsq_iTVF(x.n) s

    SET STATISTICS TIME OFF

    GO

    SET STATISTICS TIME ON

    SELECT n n1, dbo.nsq_iSVF(n) n2

    FROM #tmp x

    SET STATISTICS TIME OFF

    GO

    DROP TABLE #tmp

    GO

    However, the iSVF makes short work of the iTVF.

    SQL Server Execution Times:

    CPU time = 4977 ms, elapsed time = 5108 ms.

    SQL Server Execution Times:

    CPU time = 1497 ms, elapsed time = 1599 ms.

    Doing the same test on a two functions I wrote - each correctly calculate the hamming distance between two strings... Again, the SVF remains undefeated.

    Query:

    --iTVF

    CREATE FUNCTION dbo.hd_iTVF (@s1 varchar(8000), @s2 varchar(8000))

    RETURNS @hd TABLE(hd int)

    AS

    BEGIN

    WITH

    nums(n) AS (SELECT ROW_NUMBER() OVER (ORDER BY (SELECT 0)) FROM [master].dbo.spt_values Tally),

    matrix AS (SELECT SUBSTRING(@s1,n,1) s1, SUBSTRING(@s2,n,1) s2 FROM nums WHERE n<=LEN(@s1))

    INSERT @hd

    SELECT CASE WHEN LEN(@s1)<>LEN(@s2) THEN NULL ELSE COUNT(*) END

    FROM matrix

    WHERE s1<>s2;

    RETURN;

    END

    GO

    --iSVF

    CREATE FUNCTION dbo.hd_SVF (@s1 varchar(8000), @s2 varchar(8000))

    RETURNS int

    AS

    BEGIN

    DECLARE @hd int=0;

    WITH

    nums(n) AS (SELECT ROW_NUMBER() OVER (ORDER BY (SELECT 0)) FROM [master].dbo.spt_values Tally),

    matrix AS (SELECT SUBSTRING(@s1,n,1) s1, SUBSTRING(@s2,n,1) s2 FROM nums WHERE n<=LEN(@s1))

    SELECT @hd=CASE WHEN LEN(@s1)<>LEN(@s2) THEN NULL ELSE COUNT(*) END

    FROM matrix

    WHERE s1<>s2;

    RETURN @hd;

    END

    GO

    --Create some test data

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

    DROP TABLE #tmp;

    CREATE TABLE #tmp (s1 varchar(10), s2 varchar(10))

    INSERT #tmp

    SELECT TOP 100000 s1 = ABS(CHECKSUM(NEWID())), s2=ABS(CHECKSUM(NEWID()))

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

    SET NOCOUNT ON;

    GO

    --Test the Functions (on my local PC)

    SET STATISTICS TIME ON

    SELECT s1, s2, s.hd

    FROM #tmp x

    CROSS APPLY dbo.hd_iTVF(x.s1,x.s2) s

    SET STATISTICS TIME OFF

    GO

    SET STATISTICS TIME ON

    SELECT s1, s2, dbo.hd_SVF(s1,s2) AS hd

    FROM #tmp x

    SET STATISTICS TIME OFF

    GO

    DROP TABLE #tmp

    GO

    Results:

    SQL Server Execution Times:

    CPU time = 4977 ms, elapsed time = 5108 ms.

    SQL Server Execution Times:

    CPU time = 1497 ms, elapsed time = 1599 ms.

    Yes, I have begun reading Jeff's Spackle article about this (great article as usual) and am at the TEST, TEST, TEST part.

    Based on my testing here - this is a case where a SVF (inline or otherwise) is superior. Is this because I need to do a cross join to get my scalar value from the iTVF?

    Your itvf isn't, it is a multistatement tvf. Use this in your tests:

    CREATE FUNCTION dbo.nsq_iTVF (@int bigint)

    RETURNS TABLE WITH SCHEMABINDING

    AS

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