17 responses

  1. begin.ho
    May 12, 2022

    Great Tips ;) will you publish all articles on this website to the book?

    Reply

  2. Itzik Ben-Gan
    May 12, 2022

    Thanks begin.ho!

    As for your question, books and articles tend to have different focus, breadth and depth.

    Reply

  3. begin.ho
    May 12, 2022

    i have printed all your articles ;)
    as they are really amazing and teach me a lot
    thank you again, Itzik. you are a great sql mentor

    Reply

  4. Itzik Ben-Gan
    May 12, 2022

    Thanks begin.ho!

    Reply

  5. begin.ho
    May 15, 2022

    i am wodering, as we know, the all "select" calculate at the same time (the order of select elements should not be a matter). why you change the order can make the peformance better?

    Reply

  6. Mark Freeman
    May 16, 2022

    Thanks for this great article. Definitely actionable information here!

    >"Before I start with the tips, let’s first look at a simple example with a window function designed to benefit from a supp class="border indent shadow orting index."

    I think you have an HTML issue with this line.

    Reply

  7. Itzik Ben-Gan
    May 17, 2022

    begin.ho, the set-based treatment of the expressions in the SELECT list is relevant at the conceptual level. You get the same meaning/result irrespective of order. This article's focus is about optimization aspects, not logical meaning.

    Reply

  8. Itzik Ben-Gan
    May 17, 2022

    Mark, thanks for spotting this! Should be fixed now.

    Reply

  9. mmcdonald
    May 17, 2022

    I always enjoy reading and learning from your posts. Thank you.

    There is a typo in the initial creation of dbo.MyView.

    SUM(orderid) OVER(PARTITION BY custid ORDER BY ordered ROWS UNBOUNDED PRECEDING) AS sum2
    FROM dbo.Orders;

    should by

    SUM(orderid) OVER(PARTITION BY custid ORDER BY orderid ROWS UNBOUNDED PRECEDING) AS sum2
    FROM dbo.Orders;

    Cheers

    Reply

    • Aaron Bertrand
      May 17, 2022

      Fixed, nice catch, thanks!

      Reply

  10. mmcdonald
    May 17, 2022

    No way to correct the post…"Should by" should be — "Should be"

    Love typos :)

    LOL

    Reply

  11. Kamil Kosno
    June 14, 2022

    Hi Itzik,
    Thanks for the tips. It's interesting how you notice those dependencies, do you remember a case you worked on when it happened somewhat randomly and then you dissected it, or did you specifically target this particular issue and refined to get to the end conclusion?

    Reply

  12. Itzik Ben-Gan
    June 14, 2022

    Hi Kamil,

    Some years ago I targeted this specific area when I was researching optimization of window functions.
    Recently when working on solutions for the demand versus supply challenge I noticed my first solution had too many sorts, and was able to reduce those by applying these techniques. Then the idea to write an article on the topic was born since I figured that these techniques can be valuable to others.

    Reply

  13. Szabó István
    February 8, 2023

    A specific SQL problem:
    Is there a way generating many thousand lottery tickets ( for examples five distinct number on each ticket between 1 and 90 ) without using WHILE ?
    My simple solution (using WHILE) for 20 thousands lottery tickets:
    declare @ticket int = 1;
    while @ticket <= 20000
    begin
    select top 5 n as lottery_number from dbo.GetNums(1,90) order by CHECKSUM(newid());
    set @ticket += 1;
    end
    go
    This above solution is very slow.

    My second solution is fast, but a very complicated one with several steps, because there can be not unique numbers on certain tickets:

    drop table if exists #tmp;
    with step1 as
    (
    select abs(CHECKSUM(newid())) % 90 +1 as v from dbo.GetNums(1,150000)
    )
    select v, ntile(150000/5) over (order by (select null)) as ticket into #tmp from step1;
    go
    — index creation for accelerating next step
    create index tmp_index on #tmp(ticket,v);
    go
    — in #tmp table there can be tickets, on which the five numbers ( between 1 .. 90) are not unique
    — selecting 20 000 tickets with only unique numbers:
    with step3 as
    (
    select v, ticket, DENSE_RANK() over (partition by ticket order by v) as densNo from #tmp
    )
    select top (20000*5) ticket, v
    from step3 where ticket in ( select ticket from step3 group by ticket having max(densNo)=5 )
    order by ticket, v
    go

    So is there a fast and also simple solution for this problem ?
    Thank Itzik.
    I like your SQL books and articles.
    I collected all your books, and read them with pleasure.
    István Szabó from Budapest, Hungary

    Reply

  14. Szabó István
    February 8, 2023

    Same problem, but with small corrections in solutions, and giving execution times in my home computer (i3 1125, SQL server Express 2019)
    ——————
    — 1. solution
    drop table if exists szi.lotto;
    create table szi.lotto(ticket int, v tinyint);
    go
    declare @n int = 100000
    declare @ticket int = 1
    while @ticket <= @n
    begin
    insert into szi.lotto(ticket, v)
    select top 5 @ticket, n as lottery_number from dbo.GetNums(1,90) order by CHECKSUM(newid())
    set @ticket += 1
    end
    go
    — 17 seconds

    ——————
    — 2. solution
    drop table if exists szi.lotto;
    create table szi.lotto(ticket int, v tinyint);
    go
    declare @n int = 100000
    drop table if exists #tmp;
    — Generating 40% more random numbers , instead of 5*@n, there will be 7 * @n
    with step1 as
    (
    select abs(CHECKSUM(newid())) % 90 +1 as v from dbo.GetNums(1, @n*7)
    )
    select v, ntile(@n*7 /5) over (order by (select null)) as ticket into #tmp from step1;
    — index creation for accelerating next step
    create index tmp_index on #tmp(ticket,v);
    — in #tmp table there can be tickets, on which the five numbers ( between 1 .. 90) are not unique
    — selecting 20 000 tickets with only unique numbers:
    with step3 as
    (
    select v, ticket, DENSE_RANK() over (partition by ticket order by v) as densNo from #tmp
    )
    insert into szi.lotto(ticket, v)
    select top (@n*5) ticket, v
    from step3 where ticket in ( select ticket from step3 group by ticket having max(densNo)=5 )
    order by ticket, v
    go
    — 2 seconds, about eight times faster …

    Reply

  15. Itzik Ben-Gan
    February 9, 2023

    Hi Szabó,

    You can do this with CROSS APPLY, but there's a bit of trickiness to this. You need a correlated element from the left table involved in the lateral derived table so that it won't transform to a CROSS JOIN. Here's an example where I involve such an element in the random ordering expression:

    SELECT T.n AS ticket, A.v
    FROM dbo.GetNums(1, 100000) AS T
      CROSS APPLY
        (SELECT TOP (5) L.n AS v FROM dbo.GetNums(1, 90) AS L ORDER BY ABS(CHECKSUM(NEWID())) - T.n) AS A;
    
    

    Finishes in 2 seconds on my machine.

    Cheers,
    Itzik

    Reply

  16. Szabó István
    February 9, 2023

    Thank a lot, Itzik.
    I also tried with CROSS APPLY, OUTER APPLY , but without success …
    Occured the same tickets one after the other.

    You are one of the best in T-SQL !
    and your explanations are excellent.

    Reply

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Back to top