[sql] 내부 조인에 언제 교차 적용을 사용해야합니까?

CROSS APPLY 사용의 주요 목적은 무엇입니까 ?

cross apply파티셔닝하는 경우 대용량 데이터 세트를 선택할 때 더 효율적일 수있는 ( 인터넷의 게시물을 통해) 읽었습니다 . (페이징이 떠오른다)

또한 CROSS APPLYUDF가 올바른 테이블로 필요하지 않다는 것을 알고 있습니다.

대부분의 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

하지만 읽기가 어렵고 효율성이 떨어집니다.

최신 정보:

방금 확인했습니다.

masteron에 대한 20,000,000레코드 에 대한 테이블입니다 .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

인스턴트입니다.


답변

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

이것은 합법적입니다.

편집 :
또는 대안으로 더 짧은 구문 : (by 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+)에는 비슷한 효과에 사용할 수있는 측면 서브 쿼리 가 있습니다.


답변

두 개의 테이블이 있다고 가정하십시오.

마스터 테이블

x------x--------------------x
| Id   |        Name        |
x------x--------------------x
|  1   |          A         |
|  2   |          B         |
|  3   |          C         |
x------x--------------------x

세부 사항 테이블

x------x--------------------x-------x
| Id   |      PERIOD        |   QTY |
x------x--------------------x-------x
|  1   |   2014-01-13       |   10  |
|  1   |   2014-01-11       |   15  |
|  1   |   2014-01-12       |   20  |
|  2   |   2014-01-06       |   30  |
|  2   |   2014-01-08       |   40  |
x------x--------------------x-------x

우리는 교체 할 필요가 많은 상황이있다 INNER JOIN와 함께 CROSS APPLY.

1. TOP n결과에 따라 두 테이블을 조인

우리가 선택해야 할 경우 고려 IdName에서 Master각 마지막 두 날짜 Id에서 Details table.

SELECT M.ID,M.NAME,D.PERIOD,D.QTY
FROM MASTER M
INNER JOIN
(
    SELECT TOP 2 ID, PERIOD,QTY
    FROM DETAILS D
    ORDER BY CAST(PERIOD AS DATE)DESC
)D
ON M.ID=D.ID

위 쿼리는 다음과 같은 결과를 생성합니다.

x------x---------x--------------x-------x
|  Id  |   Name  |   PERIOD     |  QTY  |
x------x---------x--------------x-------x
|   1  |   A     | 2014-01-13   |  10   |
|   1  |   A     | 2014-01-12   |  20   |
x------x---------x--------------x-------x

마지막 두 날짜의 마지막 두 날짜에 대한 결과를 생성 Id한 다음의 외부 쿼리에서만 이러한 레코드를 조인했습니다 Id. 이것은 Ids1과 2를 모두 반환해야 하지만 1에는 마지막 두 날짜가 있기 때문에 1 만 반환했습니다. 이를 위해서는을 사용해야 CROSS APPLY합니다.

SELECT M.ID,M.NAME,D.PERIOD,D.QTY
FROM MASTER M
CROSS APPLY
(
    SELECT TOP 2 ID, PERIOD,QTY
    FROM DETAILS D
    WHERE M.ID=D.ID
    ORDER BY CAST(PERIOD AS DATE)DESC
)D

다음 결과를 형성합니다.

x------x---------x--------------x-------x
|  Id  |   Name  |   PERIOD     |  QTY  |
x------x---------x--------------x-------x
|   1  |   A     | 2014-01-13   |  10   |
|   1  |   A     | 2014-01-12   |  20   |
|   2  |   B     | 2014-01-08   |  40   |
|   2  |   B     | 2014-01-06   |  30   |
x------x---------x--------------x-------x

작동 방식은 다음과 같습니다. 내부 쿼리 CROSS APPLY는 외부 테이블을 참조 INNER JOIN할 수 있습니다.이 작업을 수행 할 수 없습니다 (컴파일 오류가 발생 함). 마지막 두 날짜를 찾을 때, 내부에서 수행되는 접합 CROSS APPLY, 즉 WHERE M.ID=D.ID.

2. INNER JOIN기능을 사용하여 기능이 필요한 경우 .

CROSS APPLYtable과 a INNER JOIN에서 결과를 얻어야 할 때를 대신하여 사용할 수 있습니다 .Masterfunction

SELECT M.ID,M.NAME,C.PERIOD,C.QTY
FROM MASTER M
CROSS APPLY dbo.FnGetQty(M.ID) C

그리고 여기 기능이 있습니다

CREATE FUNCTION FnGetQty
(
    @Id INT
)
RETURNS TABLE
AS
RETURN
(
    SELECT ID,PERIOD,QTY
    FROM DETAILS
    WHERE ID=@Id
)

다음 결과를 생성했습니다

x------x---------x--------------x-------x
|  Id  |   Name  |   PERIOD     |  QTY  |
x------x---------x--------------x-------x
|   1  |   A     | 2014-01-13   |  10   |
|   1  |   A     | 2014-01-11   |  15   |
|   1  |   A     | 2014-01-12   |  20   |
|   2  |   B     | 2014-01-06   |  30   |
|   2  |   B     | 2014-01-08   |  40   |
x------x---------x--------------x-------x

크로스 적용의 추가 이점

APPLY의 대체품으로 사용할 수 있습니다 UNPIVOT. 하나 CROSS APPLY또는 OUTER APPLY교환 할 수있는, 여기에 사용할 수 있습니다.

아래 표 ( MYTABLE) 가 있다고 가정하십시오 .

x------x-------------x--------------x
|  Id  |   FROMDATE  |   TODATE     |
x------x-------------x--------------x
|   1  |  2014-01-11 | 2014-01-13   |
|   1  |  2014-02-23 | 2014-02-27   |
|   2  |  2014-05-06 | 2014-05-30   |
|   3  |     NULL    |    NULL      |
x------x-------------x--------------x

검색어는 다음과 같습니다.

SELECT DISTINCT ID,DATES
FROM MYTABLE
CROSS APPLY(VALUES (FROMDATE),(TODATE))
COLUMNNAMES(DATES)

결과를 가져옵니다

  x------x-------------x
  | Id   |    DATES    |
  x------x-------------x
  |  1   |  2014-01-11 |
  |  1   |  2014-01-13 |
  |  1   |  2014-02-23 |
  |  1   |  2014-02-27 |
  |  2   |  2014-05-06 |
  |  2   |  2014-05-30 |
  |  3   |    NULL     |
  x------x-------------x


답변

CROSS APPLY는 복잡하고 중첩 된 쿼리에서 계산 된 필드로 작업 할 때 특정 간격을 메울 수 있으며 더 간단하고 읽기 쉽습니다.

간단한 예 : DoB가 있고 최종 사용자 애플리케이션에 사용하기 위해 Age, AgeGroup, AgeAtHiring, MinimumRetirementDate 등과 같은 다른 데이터 소스 (예 : 고용)에 의존하는 여러 연령 관련 필드를 제시하려고합니다. (예 : Excel 피벗 테이블).

옵션은 제한적이고 거의 우아하지 않습니다.

  • JOIN 하위 쿼리는 상위 쿼리의 데이터를 기반으로 데이터 집합에 새 값을 도입 할 수 없습니다 (자체로 서 있어야 함).

  • UDF는 깔끔하지만 병렬 작업을 방해하는 경향이 있으므로 느립니다. 그리고 별도의 엔티티가되는 것은 좋은 것 (코드가 적음)이거나 나쁜 것 (코드가있는 곳) 일 수 있습니다.

  • 접합 테이블. 때때로 그들은 작동 할 수 있지만 곧 당신은 많은 UNION과 서브 쿼리에 참여할 것입니다. 큰 혼란.

  • 계산에 기본 쿼리 중간에 얻은 데이터가 필요하지 않다고 가정하면 또 다른 단일 목적 뷰를 작성하십시오.

  • 중개 테이블. 예 … 일반적으로 작동하며 종종 색인화되고 빠를 수 있으므로 좋은 옵션이지만 UPDATE 문이 병렬이 아니고 수식을 재사용 (결과 재사용)하여 여러 필드를 업데이트하지 않아 성능이 저하 될 수 있습니다. 같은 진술. 때로는 한 번에 한 번만 수행하는 것을 선호하기도합니다.

  • 중첩 쿼리. 예, 언제든지 전체 쿼리에 괄호를 넣고 소스 데이터와 계산 된 필드를 모두 조작 할 수있는 하위 쿼리로 사용할 수 있습니다. 그러나 추악 해지기 전에는 그렇게 많이 할 수 있습니다. 아주 못생긴.

  • 반복 코드. 3 개의 long (CASE … ELSE … END) 문 중 가장 큰 값은 무엇입니까? 읽을 수 있습니다!

    • 고객에게 지독한 것을 스스로 계산하도록 지시하십시오.

내가 뭘 놓 쳤니? 아마, 자유롭게 의견을 말하십시오. 그러나 CROSS APPLY는 그러한 상황에서 신의 선물과 같습니다. 당신은 간단 CROSS APPLY (select tbl.value + 1 as someFormula) as crossTbl하고 자비를 추가합니다 ! 이제 새 필드는 소스 데이터에 항상 존재했던 것처럼 실제로 사용할 수 있습니다.

CROSS APPLY를 통해 도입 된 가치는 …

  • 믹스에 성능, 복잡성 또는 가독성 문제를 추가하지 않고 하나 또는 여러 개의 계산 된 필드를 만드는 데 사용
  • JOIN과 마찬가지로 몇 가지 후속 CROSS APPLY 문이 자신을 참조 할 수 있습니다. CROSS APPLY (select crossTbl.someFormula + 1 as someMoreFormula) as crossTbl2
  • 후속 조인 조건에서 CROSS APPLY에 의해 도입 된 값을 사용할 수 있습니다.
  • 보너스로 테이블 반환 함수 측면이 있습니다.

Dang, 그들이 할 수있는 일은 없습니다!


답변

교차 적용은 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


답변

이것은 이미 기술적으로 매우 잘 대답되었지만 그것이 어떻게 매우 유용한 지에 대한 구체적인 예를 보여 드리겠습니다.

Customer 테이블과 Order 테이블이 있다고 가정 해 봅시다. 고객에게 많은 주문이 있습니다.

고객에 대한 세부 정보와 고객이 주문한 최근 주문을 제공하는보기를 만들고 싶습니다. JOINS 만 있으면 자체 조인과 집계가 필요하지만 꽤 좋지는 않습니다. 그러나 Cross Apply를 사용하면 매우 쉽습니다.

SELECT *
FROM Customer
CROSS APPLY (
  SELECT TOP 1 *
  FROM Order
  WHERE Order.CustomerId = Customer.CustomerId
  ORDER BY OrderDate DESC
) T


답변

교차 적용을 사용하면 하위 쿼리의 열이 필요한 하위 쿼리를 대체 할 수 있습니다.

하위 쿼리

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