1047

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

cross applyパーティションを作成している場合に大きなデータセットを選択するときに、より効率的になる可能性があることを(漠然と、インターネット上の投稿を通じて)読んだことがあります。(ページングが頭に浮かぶ)

CROSS APPLYまた、右のテーブルとしてUDFを必要としないことも知っています。

ほとんどのINNER JOINクエリ(1対多の関係)では、使用するように書き直すことができます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
4

15 に答える 15

759

INNER JOIN も機能する場合に CROSS APPLY が違いを生むときの良い例を誰か教えてもらえますか?

詳細なパフォーマンス比較については、私のブログの記事を参照してください。

CROSS APPLYJOIN単純な条件を持たないものの方がうまく機能します。

これは から各レコード3の最後のレコードを選択します:t2t1

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

、しかし、これは読みにくく、おそらく効率的ではありません。

アップデート:

ちょうどチェックしました。

masteron20,000,000を持つ about レコードのテーブルです。PRIMARY KEYid

このクエリ:

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

インスタントです。

于 2009-07-16T17:52:56.203 に答える
214

cross applyを使用すると、 ではできないことを実行できる場合がありますinner join

例 (構文エラー):

select F.* from sys.objects O  
inner join dbo.myTableFun(O.name) F   
on F.schema_id= O.schema_id

これは構文エラーです。なぜなら、inner joinテーブル関数をと共に使用する場合、変数または定数のみをパラメーターとして取ることができるからです。(つまり、テーブル関数パラメーターは、別のテーブルの列に依存することはできません。)

でも:

select F.* from sys.objects O  
cross apply ( select * from dbo.myTableFun(O.name) ) F  
where F.schema_id= O.schema_id

これは合法です。

編集: または、代わりに、より短い構文:(ErikEによる)

select F.* from sys.objects O  
cross apply dbo.myTableFun(O.name) F
where F.schema_id= O.schema_id

編集:

注: Informix 12.10 xC2+ にはラテラル派生テーブルがあり、Postgresql (9.3+) にはラテラル サブクエリがあり、同様の効果を得るために使用できます。

于 2011-03-03T12:28:48.010 に答える
14

相互適用は、XML フィールドでもうまく機能します。他のフィールドと組み合わせてノード値を選択する場合。

たとえば、いくつかのxmlを含むテーブルがある場合

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

クエリの使用

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

結果を返します

xt_id root_attribute_value node_attribute_value lt_name
----------------------------------------------------------------------
1     test1            1                    Benefits
1     test1            4                    FINRPTCOMPANY
于 2013-02-01T18:52:17.637 に答える
10

クロス適用を使用して、サブクエリの列が必要なサブクエリを置き換えることができます

サブクエリ

select * from person p where
p.companyId in(select c.companyId from company c where c.companyname like '%yyy%')

ここでは、会社のテーブルの列を選択できないため、クロス適用を使用します

select P.*,T.CompanyName
from Person p
cross apply (
    select *
    from Company C
    where p.companyid = c.companyId and c.CompanyName like '%yyy%'
) T
于 2014-12-11T09:51:12.437 に答える
5

私はそれが読みやすさであるべきだと思います;)

CROSS APPLY は、左の表の各行に適用される UDF が使用されていることを読者に伝えるために、ややユニークです。

もちろん、他の友人が上に投稿した JOIN よりも CROSS APPLY を使用したほうがよいという制限は他にもあります。

于 2009-07-16T18:12:28.320 に答える
4

これは、パフォーマンスの違いと JOINS での使用法を含めて、すべてを説明する記事です。

JOINS に対する SQL Server CROSS APPLY および OUTER APPLY

この記事で提案されているように、通常の結合操作 (INNER と CROSS) では、それらの間にパフォーマンスの違いはありません。

ここに画像の説明を入力

次のようなクエリを実行する必要がある場合、使用方法の違いが生じます。

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)

つまり、機能と関連付ける必要がある場合です。これは、INNER JOIN を使用して実行することはできず、「マルチパート識別子 "D.DepartmentID" をバインドできませんでした」というエラーが発生します。ここでは、各行が読み取られるたびに値が関数に渡されます。私にはクールに聞こえます。:)

于 2016-03-21T04:44:34.437 に答える
3

これが Cross Apply と Inner Join を使用する理由として適切かどうかはわかりませんが、このクエリは Cross Apply を使用したフォーラム投稿で回答されているため、Inner Join を使用した同等の方法があるかどうかはわかりません。

Create PROCEDURE [dbo].[Message_FindHighestMatches]

-- Declare the Topical Neighborhood
@TopicalNeighborhood nchar(255)

はじめに

-- 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

終わり

于 2012-03-08T19:51:43.140 に答える
2

これはおそらく古い質問ですが、ロジックの再利用を簡素化し、結果の「連鎖」メカニズムを提供する CROSS APPLY の機能は今でも気に入っています。

以下に SQL Fiddle を用意しました。これは、CROSS APPLY を使用して、データ セットに対して複雑な論理操作を実行する方法の簡単な例を示しています。ここから、より複雑な計算を推定することは難しくありません。

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

于 2015-10-06T01:41:57.050 に答える
0

CROSS APPLYを使用して、別の (更新要求) テーブルからのJSONでテーブルを更新します。OPENJSON を使用して JSON の内容を読み取り、OPENJSON は「テーブル値関数」であるため、結合は機能しません。

例として、UPDATE コマンドの 1 つの単純化されたバージョンをここに置くつもりでしたが、単純化したとしても、例としてはかなり大きく、過度に複雑です。したがって、コマンドの一部だけを簡略化した「スケッチ」で十分です。

SELECT  
       r.UserRequestId,
       j.xxxx AS xxxx,
FROM  RequestTable as r WITH (NOLOCK)
   CROSS APPLY
      OPENJSON(r.JSON, '$.requesttype.recordtype')
      WITH(
             r.userrequestid nvarchar(50) '$.userrequestid',
             j.xxx nvarchar(20) '$.xxx
           )j
       WHERE r.Id > @MaxRequestId
          and ... etc. ....
于 2021-08-11T10:21:47.790 に答える