When should I use cross apply over inner join?

前端 未结 14 1054
忘了有多久
忘了有多久 2020-11-22 06:51

What is the main purpose of using CROSS APPLY?

I have read (vaguely, through posts on the Internet) that cross apply can be more efficient when selectin

相关标签:
14条回答
  • 2020-11-22 07:15

    Cross apply works well with an XML field as well. If you wish to select node values in combination with other fields.

    For example, if you have a table containing some xml

    <root>
        <subnode1>
           <some_node value="1" />
           <some_node value="2" />
           <some_node value="3" />
           <some_node value="4" />
        </subnode1>
    </root>
    

    Using the query

    SELECT
           id as [xt_id]
          ,xmlfield.value('(/root/@attribute)[1]', 'varchar(50)') root_attribute_value
      ,node_attribute_value = [some_node].value('@value', 'int')
      ,lt.lt_name   
    FROM dbo.table_with_xml xt
    CROSS APPLY xmlfield.nodes('/root/subnode1/some_node') as g ([some_node])
    LEFT OUTER JOIN dbo.lookup_table lt
    ON [some_node].value('@value', 'int') = lt.lt_id
    

    Will return a result

    xt_id root_attribute_value node_attribute_value lt_name
    ----------------------------------------------------------------------
    1     test1            1                    Benefits
    1     test1            4                    FINRPTCOMPANY
    
    0 讨论(0)
  • 2020-11-22 07:16

    Here is an article that explains it all, with their performance difference and usage over JOINS.

    SQL Server CROSS APPLY and OUTER APPLY over JOINS

    As suggested in this article, there is no performance difference between them for normal join operations (INNER AND CROSS).

    The usage difference arrives when you have to do a query like this:

    CREATE FUNCTION dbo.fn_GetAllEmployeeOfADepartment(@DeptID AS INT)  
    RETURNS TABLE 
    AS 
    RETURN 
       ( 
       SELECT * FROM Employee E 
       WHERE E.DepartmentID = @DeptID 
       ) 
    GO 
    SELECT * FROM Department D 
    CROSS APPLY dbo.fn_GetAllEmployeeOfADepartment(D.DepartmentID)
    

    That is, when you have to relate with function. This cannot be done using INNER JOIN, which would give you the error "The multi-part identifier "D.DepartmentID" could not be bound." Here the value is passed to the function as each row is read. Sounds cool to me. :)

    0 讨论(0)
  • 2020-11-22 07:16

    This is perhaps an old question, but I still love the power of CROSS APPLY to simplify the re-use of logic and to provide a "chaining" mechanism for results.

    I've provided a SQL Fiddle below which shows a simple example of how you can use CROSS APPLY to perform complex logical operations on your data set without things getting at all messy. It's not hard to extrapolate from here more complex calculations.

    http://sqlfiddle.com/#!3/23862/2

    0 讨论(0)
  • 2020-11-22 07:17

    The essence of the APPLY operator is to allow correlation between left and right side of the operator in the FROM clause.

    In contrast to JOIN, the correlation between inputs is not allowed.

    Speaking about correlation in APPLY operator, I mean on the right hand side we can put:

    • a derived table - as a correlated subquery with an alias
    • a table valued function - a conceptual view with parameters, where the parameter can refer to the left side

    Both can return multiple columns and rows.

    0 讨论(0)
  • 2020-11-22 07:18

    Can anyone give me a good example of when CROSS APPLY makes a difference in those cases where INNER JOIN will work as well?

    See the article in my blog for detailed performance comparison:

    • INNER JOIN vs. CROSS APPLY

    CROSS APPLY works better on things that have no simple JOIN condition.

    This one selects 3 last records from t2 for each record from t1:

    SELECT  t1.*, t2o.*
    FROM    t1
    CROSS APPLY
            (
            SELECT  TOP 3 *
            FROM    t2
            WHERE   t2.t1_id = t1.id
            ORDER BY
                    t2.rank DESC
            ) t2o
    

    It cannot be easily formulated with an INNER JOIN condition.

    You could probably do something like that using CTE's and window function:

    WITH    t2o AS
            (
            SELECT  t2.*, ROW_NUMBER() OVER (PARTITION BY t1_id ORDER BY rank) AS rn
            FROM    t2
            )
    SELECT  t1.*, t2o.*
    FROM    t1
    INNER JOIN
            t2o
    ON      t2o.t1_id = t1.id
            AND t2o.rn <= 3
    

    , but this is less readable and probably less efficient.

    Update:

    Just checked.

    master is a table of about 20,000,000 records with a PRIMARY KEY on id.

    This query:

    WITH    q AS
            (
            SELECT  *, ROW_NUMBER() OVER (ORDER BY id) AS rn
            FROM    master
            ),
            t AS 
            (
            SELECT  1 AS id
            UNION ALL
            SELECT  2
            )
    SELECT  *
    FROM    t
    JOIN    q
    ON      q.rn <= t.id
    

    runs for almost 30 seconds, while this one:

    WITH    t AS 
            (
            SELECT  1 AS id
            UNION ALL
            SELECT  2
            )
    SELECT  *
    FROM    t
    CROSS APPLY
            (
            SELECT  TOP (t.id) m.*
            FROM    master m
            ORDER BY
                    id
            ) q
    

    is instant.

    0 讨论(0)
  • 2020-11-22 07:19

    Well I am not sure if this qualifies as a reason to use Cross Apply versus Inner Join, but this query was answered for me in a Forum Post using Cross Apply, so I am not sure if there is an equalivent method using Inner Join:

    Create PROCEDURE [dbo].[Message_FindHighestMatches]
    
    -- Declare the Topical Neighborhood
    @TopicalNeighborhood nchar(255)
    

    AS BEGIN

    -- SET NOCOUNT ON added to prevent extra result sets from
    -- interfering with SELECT statements.
    SET NOCOUNT ON
    
    Create table  #temp
    (
        MessageID         int,
        Subjects          nchar(255),
        SubjectsCount    int
    )
    
    Insert into #temp Select MessageID, Subjects, SubjectsCount From Message
    
    Select Top 20 MessageID, Subjects, SubjectsCount,
        (t.cnt * 100)/t3.inputvalues as MatchPercentage
    
    From #temp 
    
    cross apply (select count(*) as cnt from dbo.Split(Subjects,',') as t1
                 join dbo.Split(@TopicalNeighborhood,',') as t2
                 on t1.value = t2.value) as t
    cross apply (select count(*) as inputValues from dbo.Split(@TopicalNeighborhood,',')) as t3
    
    Order By MatchPercentage desc
    
    drop table #temp
    

    END

    0 讨论(0)
提交回复
热议问题