User13839404
User13839404

Reputation: 1813

What is the alternative for outer apply?

Recently I have added outer apply in my a query. Since then this query takes forever. One reason i know that the table it is associated with is the biggest table in the database now.

select   
    a.*,
    b.*,
    BTab.*,
    BTTab.*
from 
    tableA a 
    join tableB b ON a.ID = b.UID
    join *****
    left join *******
    ....
    ....
    ....
    outer apply 
        (SELECT TOP 1 * 
        FROM 
            biggestTable bt 
        WHERE 
            bt.id = a.id 
            and a.id <> 100 
        ORDER BY a.datetime desc) BTab
    Outer apply
        (SELECT TOP 1 * 
        FROM 
            biggestTable btt
        WHERE 
            btt.id = a.id 
            AND btt.DateTime <> '1948-01-01 00:00:00.000'
            and btt.value = 0 
        order by btt.datetime desc) BTTab
where 
    ..................
    .................
    ....................
    .................

Is there any better solution than using outer apply?

Upvotes: 5

Views: 11361

Answers (2)

paparazzo
paparazzo

Reputation: 45096

+1 for Conrad as his answer might be all you need and I reused some of his syntax.

Problem with Apply and CTE is they are evaluated for each row in the a, b join.

I would create two temporary tables. To represent the max rows and put a PK on them. The benefit is these two expensive quires are done once and the join is to a PK. Big benefit joining to a PK. I eat the overhead of #temp to get a single evaluation and PK a lot.

   Create table #Btab (int ID PK, ...)
   insert into #Btab
   WITH BTAB as 
   (       SELECT * ,
               row_nubmer() over (partition by b.id) rn 
           FROM 
               biggestTable
           where ID <> 100 
   ) 
   Select * from BTAB
   Where RN = 1 
   order by ID

   Create table #Bttab (int ID PK, ...)
   insert into #Bttab
   WITH BTTAB as 
   (       SELECT * ,
               row_nubmer() over (partition by id order by datetime desc) rn 
           FROM 
               biggestTable
           where DateTime <> '1948-01-01 00:00:00.000' and value = 0
   ) 
   Select * from BTAB
   Where RN = 1 
   order by ID

   select   
       a.*,
       b.*,
       #Btab.*,
       #Bttab.*
   from 
       tableA a 
       join tableB b ON a.ID = b.UID
       join *****
       left join *******
       ....
       ....
       ....
       left outer outer join #Btab 
           on #Btab.ID = a.ID
       left outer outer join #Bttab 
           on #Bttab.ID = a.ID
   where 
       ..................
       .................

P.S. I am exploring TVP over #TEMP for this. A TVP supports a PK and has less overhead than #tmp. But I have not compared them head to head in this type of application.

Tested TVP over #TEMP and got a 1/2 second improvement (about the time it take to create and delete a temporary table).

Upvotes: 5

Conrad Frix
Conrad Frix

Reputation: 52645

Here's an alternative, can't say whether its better or not. You may simply need better indexes on your big table

WITH BTAB as 
(       SELECT TOP 1 
            * ,
            row_nubmer() over (partition by b.id) rn 

        FROM 
            biggestTable bt 
) ,
BTTab as (SELECT TOP 1 
              * ,
              row_nubmer() over (partition by btt.id order by btt.datetime desc) rn 
        FROM 
            biggestTable btt
        WHERE 
            AND btt.DateTime <> '1948-01-01 00:00:00.000'
            and btt.value = 0 
)

select   
    a.*,
    b.*,
    BTab.*,
    BTTab.*
from 
    tableA a 
    join tableB b ON a.ID = b.UID
    join *****
    left join BTab on ON a.ID = BTab.ID 
           and BTAB.rn = 1
    left join BTTabon ON a.ID = BTTab.ID 
           and BTTab.rn = 1

Upvotes: 7

Related Questions