Which SQL would run faster?

  • GilaMonster (1/16/2009)


    Jeff Moden (1/16/2009)


    I'm trying to be as nice as pie... I don't understand why people post code and ask which will be faster... that's pretty lazy...

    Cause it's easier than setting up a test environment?

    That would be true, huh? 😉 I just forgot that sometimes people don't have access to the large amounts of production data and they don't know how to build, say, a million rows of test data quickly.

    Then, if you don't understand why, post the results, the code, and ask why. 😉

    I wonder how many of the people who think that one or the other will be faster can explain why they say that. 😉

    BWAA-HAA!!! I'm thinking that answer would be "more than you think, fewer than should, and a whole lot less than either took the time".

    --Jeff Moden


    RBAR is pronounced "ree-bar" and is a "Modenism" for Row-By-Agonizing-Row.
    First step towards the paradigm shift of writing Set Based code:
    ________Stop thinking about what you want to do to a ROW... think, instead, of what you want to do to a COLUMN.

    Change is inevitable... Change for the better is not.


    Helpful Links:
    How to post code problems
    How to Post Performance Problems
    Create a Tally Function (fnTally)

  • ok now that things are returning to normal do we think ISNULL performing better than COALESCE for checking a single operand is no co-incidence?

  • leonp (1/16/2009)


    ok now that things are returning to normal do we think ISNULL performing better than COALESCE for checking a single operand is no co-incidence?

    I don't believe they intentionally did that, if that's what you mean. I think it's just a matter of computational requirements. If you wrote split code in T-SQL, I'm absolutely posititve that the code you wrote to spit two known (ie. guaranteed to be there) parameters would be much shorter and faster than something that was required to split up to "n" parameters.

    --Jeff Moden


    RBAR is pronounced "ree-bar" and is a "Modenism" for Row-By-Agonizing-Row.
    First step towards the paradigm shift of writing Set Based code:
    ________Stop thinking about what you want to do to a ROW... think, instead, of what you want to do to a COLUMN.

    Change is inevitable... Change for the better is not.


    Helpful Links:
    How to post code problems
    How to Post Performance Problems
    Create a Tally Function (fnTally)

  • leonp (1/16/2009)


    ok now that things are returning to normal do we think ISNULL performing better than COALESCE for checking a single operand is no co-incidence?

    It would be interesting to see what happens with a CASE as well. I may do that test.

  • Jeff Moden (1/16/2009)


    leonp (1/16/2009)


    ok now that things are returning to normal do we think ISNULL performing better than COALESCE for checking a single operand is no co-incidence?

    I don't believe they intentionally did that, if that's what you mean. I think it's just a matter of computational requirements. If you wrote split code in T-SQL, I'm absolutely posititve that the code you wrote to spit two known (ie. guaranteed to be there) parameters would be much shorter and faster than something that was required to split up to "n" parameters.

    Actually in most 3GL & OO languages, you can write the longer one so that it is almost exactly the same speed as the shorter one (maybe 1% difference).

    I suspect that the real cause of the performance difference between ISNULL and COALESCE has to do with their type-coercion differences. Even just having to check for it can be a computational PITA in many architectures.

    [font="Times New Roman"]-- RBarryYoung[/font], [font="Times New Roman"] (302)375-0451[/font] blog: MovingSQL.com, Twitter: @RBarryYoung[font="Arial Black"]
    Proactive Performance Solutions, Inc.
    [/font]
    [font="Verdana"] "Performance is our middle name."[/font]

  • Okay, I loaded up the following tables with 1,000,000 rows using RedGate SQLDataGenerator (I needed to play with it since I have it).

    CREATE TABLE [dbo].[test_a]

    (

    [id] [int] IDENTITY(1, 1) NOT NULL,

    [id_2] [int] NOT NULL,

    [char_1] [char](5) NULL,

    PRIMARY KEY CLUSTERED ([id] ASC)

    WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF,

    IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON,

    ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]

    )

    ON [PRIMARY]

    GO

    CREATE NONCLUSTERED INDEX [IX_test_a_id_2] ON [dbo].[test_a] ([id_2] ASC)

    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

    CREATE TABLE [dbo].[test_b]

    (

    [id] [int] IDENTITY(1, 1)

    NOT NULL,

    [id_2] [int] NOT NULL,

    [char_1] [char](5) NULL,

    PRIMARY KEY CLUSTERED ([id] ASC)

    WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF,

    IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON,

    ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]

    )

    ON [PRIMARY]

    GO

    CREATE NONCLUSTERED INDEX [IX_test_b_id_2] ON [dbo].[test_b] ([id_2] ASC)

    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

    CREATE FUNCTION dbo.fnCoalesce

    (

    @char_1 NVARCHAR(25)

    )

    RETURNS NVARCHAR(25)

    --WITH ENCRYPTION|SCHEMABINDING, ...

    AS

    BEGIN

    DECLARE @retval NVARCHAR(25)

    SET @retval = CASE when @char_1 = '' THEN '9' ELSE ISNULL(@char_1, '*') end

    RETURN @retval

    END

    Then I ran these queries:

    SET STATISTICS IO ON;

    SELECT

    TA.id,

    TA.id_2,

    MIN(ISNULL(ISNULL(Nulllif(TB.char_1, ''), '9') '*')) AS char_1

    FROM

    dbo.test_a AS TA JOIN

    dbo.test_b AS TB

    ON TA.id = TB.id AND

    TA.id_2 = TB.id_2

    WHERE

    TA.id <= 100000

    GROUP BY

    TA.id,

    TA.id_2 ;

    SELECT

    TA.id,

    TA.id_2,

    MIN(CASE WHEN TB.char_1 = '' THEN '9'

    ELSE COALESCE(TB.char_1, '*')

    END) AS char_1

    FROM

    dbo.test_a AS TA JOIN

    dbo.test_b AS TB

    ON TA.id = TB.id AND

    TA.id_2 = TB.id_2

    WHERE

    TA.id <= 100000

    GROUP BY

    TA.id,

    TA.id_2 ;

    SELECT

    TA.id,

    TA.id_2,

    MIN(tb.char_1)

    FROM

    dbo.test_a AS TA JOIN

    (

    SELECT

    id,

    id_2,

    CASE WHEN char_1 = '' THEN '9'

    ELSE COALESCE(char_1, '*')

    END AS char_1

    FROM

    dbo.test_b

    ) AS tb

    ON TA.id = tb.id AND

    TA.id_2 = tb.id_2

    WHERE

    TA.id <= 100000

    GROUP BY

    TA.id,

    TA.id_2 ;

    SELECT

    TA.id,

    TA.id_2,

    MIN(CASE WHEN TB.char_1 = '' THEN '9'

    ELSE IsNull(TB.char_1, '*')

    END) AS char_1

    FROM

    dbo.test_a AS TA JOIN

    dbo.test_b AS TB

    ON TA.id = TB.id AND

    TA.id_2 = TB.id_2

    WHERE

    TA.id <= 100000

    GROUP BY

    TA.id,

    TA.id_2;

    SELECT

    TA.id,

    TA.id_2,

    MIN(CASE WHEN TB.char_1 = '' THEN '9'

    ELSE CASE WHEN TB.Char_1 IS NULL THEN '*' End

    END) AS char_1

    FROM

    dbo.test_a AS TA JOIN

    dbo.test_b AS TB

    ON TA.id = TB.id AND

    TA.id_2 = TB.id_2

    WHERE

    TA.id <= 100000

    GROUP BY

    TA.id,

    TA.id_2 ;

    SELECT

    TA.id,

    TA.id_2,

    MIN(tb.char_1)

    FROM

    dbo.test_a AS TA JOIN

    (

    SELECT

    id,

    id_2,

    dbo.fnCoalesce(char_1) AS char_1

    FROM

    dbo.test_b

    ) AS tb

    ON TA.id = tb.id AND

    TA.id_2 = tb.id_2

    WHERE

    TA.id <= 100000

    GROUP BY

    TA.id,

    TA.id_2 ;

    SET STATISTICS IO Off

    Here are the stats IO results

    (100000 row(s) affected)

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

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

    (1 row(s) affected)

    (100000 row(s) affected)

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

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

    (1 row(s) affected)

    (100000 row(s) affected)

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

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

    (1 row(s) affected)

    (100000 row(s) affected)

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

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

    (1 row(s) affected)

    (100000 row(s) affected)

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

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

    (1 row(s) affected)

    Attached are the execution plans in one file. Only the last one with the UDF has a different execution plan.

  • I must have something whacky going on with my machine... it gives me an XML error when I try to open the excecution plan.

    I have no doubt that the IO on all of these will be similar. What would be interesting to see is what all that code turns out to be for CPU usage and duration. Only one you won't be able to measure with SET STATISTICS TIME ON will be the UDF one...

    --Jeff Moden


    RBAR is pronounced "ree-bar" and is a "Modenism" for Row-By-Agonizing-Row.
    First step towards the paradigm shift of writing Set Based code:
    ________Stop thinking about what you want to do to a ROW... think, instead, of what you want to do to a COLUMN.

    Change is inevitable... Change for the better is not.


    Helpful Links:
    How to post code problems
    How to Post Performance Problems
    Create a Tally Function (fnTally)

  • Probably having an issue with execution plan because I am running 2008 on my laptop now.

    Here's the Statistics Time On Stats:

    --IsNull(IsNull(Nullif()))

    SQL Server Execution Times:

    CPU time = 109 ms, elapsed time = 1085 ms.

    --Case When Then Else Coalesce()

    SQL Server Execution Times:

    CPU time = 78 ms, elapsed time = 1323 ms.

    --Derived table with Case When Then Else Coalesce()

    SQL Server Execution Times:

    CPU time = 188 ms, elapsed time = 1102 ms.

    --Case When Then Else IsNull()

    SQL Server Execution Times:

    CPU time = 124 ms, elapsed time = 1154 ms.

    --Case When Then Else Case When Then Else

    SQL Server Execution Times:

    CPU time = 203 ms, elapsed time = 954 ms.

    --Derived table with UDF

    SQL Server Execution Times:

    CPU time = 7192 ms, elapsed time = 10530 ms.

  • Thanks Jack... appreciate your time.

    --Jeff Moden


    RBAR is pronounced "ree-bar" and is a "Modenism" for Row-By-Agonizing-Row.
    First step towards the paradigm shift of writing Set Based code:
    ________Stop thinking about what you want to do to a ROW... think, instead, of what you want to do to a COLUMN.

    Change is inevitable... Change for the better is not.


    Helpful Links:
    How to post code problems
    How to Post Performance Problems
    Create a Tally Function (fnTally)

  • I tried the queries and it looks to me Query 2 is better compared to Query 1.

    But again There is very slight differernce between Query 1 and 2. this is allmost negligible 🙂

    Thanks -- Vj

    http://dotnetvj.blogspot.com

Viewing 10 posts - 16 through 24 (of 24 total)

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