1

I'm confused by something. I'm using T-SQL and trying to optimize code that looks like this:

SELECT * FROM MyTable mt
LEFT JOIN
  (SELECT * FROM Table1 t1
   LEFT JOIN api.tableValuedFunc(@someArgs) tvf
   on tvf.Key = t1.Key) firstJoin
on mt.Key = firstJoin.key
LEFT JOIN
  (SELECT * FROM Table2 t2
   LEFT JOIN api.tableValuedFunc(@someArgs) tvf
   on tvf.Key = t2.Key) secondJoin
on mt.Key = secondJoin.key

by doing this:

declare @tvfResult TABLE ( ... some columns ... )
insert into @tvfResults SELECT * FROM api.tableValuedFunc(@someArgs);

SELECT * FROM MyTable mt
LEFT JOIN
  (SELECT * FROM Table1 t1
   LEFT JOIN @tvfResults tvf
   on tvf.Key = t1.Key) firstJoin
on mt.Key = firstJoin.key
LEFT JOIN
  (SELECT * FROM Table2 t2
   LEFT JOIN @tvfResults tvf
   on tvf.Key = t2.Key) secondJoin
on mt.Key = secondJoin.key

This doubles the time it takes to execute! Why is this? In the second example, I (naively) assume I'm executing the function half as often. Is there some kind of SQL wizardry happening behind the scenes that I'm ruining?

3
  • 1
    Looking around, this seems related to stackoverflow.com/questions/4109152/… But the prescription in this case is to use a temp table, which is what I'm doing. Commented Jun 2, 2016 at 22:59
  • OK, apparently that's not a temp table but a table variable, which is a ton slower. This all needs to live in a function, though, so I can't use temp tables. Is option #1 as fast as I'm going to get? Commented Jun 2, 2016 at 23:06
  • 1
    Please confirm whether or not you are actually using "SELECT * " in your measured queries, or are merely using it as shorthand in the question. Note that the mere use of "SELECT * " can be a sever performance hit due to the unavailability of any covering indices. Next, please attach an ACTUAL QUERY PLAN from SSMS for analysis - How can we possibly identify what is happening without either a query plan or the full DDL for all tables/views/etc involved? Commented Jun 3, 2016 at 0:58

2 Answers 2

1

Instead of creating a table variable, create a local temporary table may do better performance if it's outputting large number of rows.

create table #tvfResult  ( ... some columns ... )

insert into #tvfResults SELECT * FROM api.tableValuedFunc(@someArgs);

SELECT * FROM MyTable mt
LEFT JOIN
  (SELECT * FROM Table1 t1
   LEFT JOIN #tvfResults tvf
   on tvf.Key = t1.Key) firstJoin
on mt.Key = firstJoin.key
LEFT JOIN
  (SELECT * FROM Table2 t2
   LEFT JOIN #tvfResults tvf
   on tvf.Key = t2.Key) secondJoin
on mt.Key = secondJoin.key

Local temporary tables are visible only to their creators during the same connection to an instance of SQL Server as when the tables were first created or referenced. Local temporary tables are deleted after the user disconnects from the instance of SQL Server.

Drop the temporary table explicitly if you are re-running the query with the same session.

drop table #tvfResult
Sign up to request clarification or add additional context in comments.

5 Comments

I want to do that, but all of this needs to live inside of a function itself, so a temp table is off-limits, unfortunately.
you can create a local temporary table inside a function, isn't it?
I thought so, but SQL server throws an error: Cannot access temporary tables from within a function.
tvf inside of tvf - starting smell not good. Try rethinking your approach and main idea of the way you're attempting to implement the solution.
I inherited this code and am currently evaluating a re-factor.
0

Note that, unless you have omitted several critical factors from your question, your first query reduces to merely:

SELECT * FROM MyTable mt
LEFT JOIN Table1 t1 on mt.Key = t1.key
LEFT JOIN Table2 t2 on mt.Key = t2.key
LEFT JOIN api.tableValuedFunc(@someArgs) tvf1 on tvf1.Key = t1.key
LEFT JOIN api.tableValuedFunc(@someArgs) tvf2 on tvf2.Key = t2.key

Now, the analysis reduces to what your actual column selection is in the SELECT clause - please supply those details as it is impossible to analyze your query without actually knowing what the query is - in excruciating detail - because performance problems are invariably in the details.

1 Comment

I elided a fair amount due to the function in question being over 600 lines long. Here's the execution plan for it as-is: pastebin.com/7Y4axtKB And with my mis-optimization: pastebin.com/NZuZHkY1

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.