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
on에 대한 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
인스턴트입니다.
답변
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
결과에 따라 두 테이블을 조인
우리가 선택해야 할 경우 고려 Id
및 Name
에서 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
. 이것은 Ids
1과 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 APPLY
table과 a INNER JOIN
에서 결과를 얻어야 할 때를 대신하여 사용할 수 있습니다 .Master
function
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