1. ホーム
  2. sql

[解決済み] INNER JOINよりもCROSS APPLYを使用すべきなのはどのような場合ですか?

2022-03-19 01:40:13

質問

を使用する主な目的は何ですか? CROSS APPLY ?

私は、(インターネット上の書き込みで漠然とですが)次のようなことを読みました。 cross apply は、大規模なデータセットで選択する場合、パーティショニングを行うとより効率的です。(ページングが思い浮かびます)

また、私は CROSS APPLY は、右テーブルとしてUDFを必要としない。

ほとんどの INNER JOIN クエリ (一対多のリレーション) の場合、これらを書き換えて CROSS APPLY しかし、常に同等の実行プランが得られます。

を使用した場合の良い例をどなたか教えてください。 CROSS APPLY を使用する場合、その違いは INNER JOIN ということですか?


編集する

以下は、実行計画が全く同じである些細な例です。 (両者が異なる場合、そして cross apply の方が速い/効率が良い)

create table Company (
    companyId int identity(1,1)
,   companyName varchar(100)
,   zipcode varchar(10) 
,   constraint PK_Company primary key (companyId)
)
GO

create table Person (
    personId int identity(1,1)
,   personName varchar(100)
,   companyId int
,   constraint FK_Person_CompanyId foreign key (companyId) references dbo.Company(companyId)
,   constraint PK_Person primary key (personId)
)
GO

insert Company
select 'ABC Company', '19808' union
select 'XYZ Company', '08534' union
select '123 Company', '10016'


insert Person
select 'Alan', 1 union
select 'Bobby', 1 union
select 'Chris', 1 union
select 'Xavier', 2 union
select 'Yoshi', 2 union
select 'Zambrano', 2 union
select 'Player 1', 3 union
select 'Player 2', 3 union
select 'Player 3', 3 


/* using CROSS APPLY */
select *
from Person p
cross apply (
    select *
    from Company c
    where p.companyid = c.companyId
) Czip

/* the equivalent query using INNER JOIN */
select *
from Person p
inner join Company c on p.companyid = c.companyId

解決方法は?

<ブロッククオート

INNER JOINでもうまくいくようなケースで、CROSS APPLYが違いをもたらす良い例をどなたか教えていただけませんでしょうか?

詳しい性能比較は私のブログの記事をご覧ください。

CROSS APPLY は、単純なものを持たないものほどよく機能します。 JOIN という条件があります。

こちらは、選択された 3 からの最後のレコード t2 の各レコードに対して 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

で簡単に定式化することはできません。 INNER JOIN という条件があります。

を使って、そのようなことができるかもしれません。 CTE とウィンドウ関数があります。

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

しかし、これでは可読性が低く、おそらく効率も悪いでしょう。

更新してください。

今確認しました。

master は、約表 20,000,000 のレコードに PRIMARY KEY オン id .

このクエリ

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

はほとんど実行されます。 30 秒、一方こちらは

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

はインスタントです。