Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

CROSS APPLY with table valued function restriction performance

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 ...
  • Inner select on table LOT_OF_ROWS_TABLE is returning many rows.
  • Joining tables LOT_OF_ROWS_TABLE and ANOTHER_TABLE returns only one or few rows.
  • Table valued function is very time consuming and when calling for a lot of rows the select lasts very long time.

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.

like image 433
Pavel Hodek Avatar asked Apr 26 '13 11:04

Pavel Hodek


People also ask

How do you use cross apply with table valued functions?

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.

Is Cross apply faster than 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.

Is Cross apply efficient?

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.

Can we use CTE in table valued function?

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.


2 Answers

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
like image 100
Sankara Avatar answered Sep 28 '22 00:09

Sankara


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.

like image 23
Kenneth Fisher Avatar answered Sep 27 '22 23:09

Kenneth Fisher