I have problem with CROSS APPLY
with parametrised table valued function.
Here is simplified pseudo code example:
SELECT *
FROM (
SELECT lor.*
FROM LOT_OF_ROWS_TABLE lor
WHERE ...
) AS lor
CROSS APPLY dbo.HeavyTableValuedFunction(lor.ID) AS htvf
INNER JOIN ANOTHER_TABLE AS at ON lor.ID = at.ID
WHERE ...
LOT_OF_ROWS_TABLE
is returning many rows.LOT_OF_ROWS_TABLE
and ANOTHER_TABLE
returns only one or few rows. My problem:
The function is called for all rows returned from LOT_OF_ROWS_TABLE
regardless of the fact that the data will be limited when just join ANOTHER_TABLE
.
The select has to be in the shown format - it is generated and in fact it is much more dificult.
When I try to rewrite it, it can be very fast, but it cannot be rewritten like this:
SELECT *
FROM (
SELECT lor.*
FROM LOT_OF_ROWS_TABLE lor
WHERE ...
) AS lor
INNER JOIN ANOTHER_TABLE AS at ON lor.ID = at.ID
CROSS APPLY dbo.HeavyTableValuedFunction(at.ID) AS htvf
WHERE ...
I'd like to know:
Is there any setting or hint or something that forces select to call function only for finally restricted rows?
Thank you.
EDIT:
The table valued function is very complex: http://pastebin.com/w6azRvxR. The select we are talking about is "user configured" and generated: http://pastebin.com/bFbanY2n.
CROSS APPLY returns only rows from the outer table that produce a result set from the table-valued function. It other words, result of CROSS APPLY doesn't contain any row of left side table expression for which no result is obtained from right side table expression. CROSS APPLY work as a row by row INNER JOIN.
While most queries which employ CROSS APPLY can be rewritten using an INNER JOIN , CROSS APPLY can yield better execution plan and better performance, since it can limit the set being joined yet before the join occurs.
Conclusion. As demonstrated, CROSS APPLY is a very useful operator when referencing a Table Function or filtering on a subset of data. The key benefit is the ability to use one defined set with another separately created set. Unlike Joins, you can define a dynamic subset of data to match with the outer query.
In addition, it is also perfectly valid to use Common Table Expression (CTE) in ITVF. ); Note that ITVF cannot have BEGIN and END block encapsulating the RETURN statement. You will get error “Incorrect syntax near BEGIN” when use BEGIN and END statement as follow.
you can divide this query into 2 parts use either table variable or temp table
SELECT lor.*,at.* into #tempresult
FROM (
SELECT lor.*
FROM LOT_OF_ROWS_TABLE lor
WHERE ...
) lor
INNER JOIN ANOTHER_TABLE AS at ON lor.ID = at.ID
WHERE ...
now do the time consuming part which is table valued function right
SELECT * FROM #tempresult
CROSS APPLY dbo.HeavyTableValuedFunction(#tempresult.ID) AS htvf
I believe this is what you are looking for.
Plan Forcing Scenario: Create a Plan Guide to Force a Plan Obtained from a Rewritten Query
Basically it describes re-writing the query to get a generated plan using the correct order of joins. Then saving off that plan and forcing your existing query (that does not get changed) to use the plan you saved off.
The BOL link I put in even gives a specific example of re-writing the query putting the joins in a different order and using a FORCE ORDER
hint. Then using sp_create_plan_guild
to take the plan from the re-written query and use it on the original query.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With