문제

사용의 주요 목적은 무엇입니까? 크로스 적용?

인터넷의 게시물을 통해 모호하게 읽었습니다. 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
도움이 되었습니까?

해결책

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 상태.

당신은 아마도 그것을 사용하는 것과 같은 일을 할 수 있습니다 CTES 및 창 함수 :

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

이것은 합법적입니다.

편집하다:또는 또는 짧은 구문 : (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+는 HAS가 있습니다 측면 파생 테이블 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 그런 다음이 레코드를 OUTER QUERY에서만 가입했습니다. Id, 그것은 잘못입니다. 이를 달성하려면 사용해야합니다 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 대체품으로 사용할 수 있습니다 INNER JOIN 우리가 결과를 얻어야 할 때 Master 테이블과 a 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

Cross Apply의 추가 이점

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가 있고 최종 사용자 애플리케이션에 사용하기 위해 연령, 연령 그룹, Ageathing, MinimumRetirementDate 등과 같은 다른 데이터 소스 (예 : 고용)에 의존하는 여러 연령 관련 분야를 제시하려고합니다. (예를 들어 Excel pivottables).

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

  • 가입 하위 Queries는 부모 쿼리의 데이터를 기반으로 데이터 세트에 새 값을 도입 할 수 없습니다 (자체적으로 서 있어야 함).

  • UDF는 깔끔하지만 병렬 작업을 방지하는 경향이 있기 때문에 느립니다. 그리고 별도의 엔티티가되는 것은 좋은 (코드가 적음) 또는 나쁜 (코드는 어디에 있습니까) 일 수 있습니다.

  • 정션 테이블. 때때로 그들은 일할 수 있지만 곧 당신은 수많은 노조와 하위 쿼리에 합류하고 있습니다. 큰 혼란.

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

  • 중개 테이블. 예 ... 일반적으로 작동하며 종종 색인화되고 빠르게 적용 할 수있는 좋은 옵션이지만 업데이트 명령문이 평행하지 않고 캐스케이드 공식 (재사용 결과)을 허용하지 않기 때문에 성능이 떨어질 수 있습니다. 같은 진술. 그리고 때로는 한 번의 패스로 일을 선호합니다.

  • 중첩 쿼리. 예, 언제라도 전체 쿼리에 괄호를 넣고 소스 데이터와 계산 된 필드를 조작 할 수있는 하위 쿼리로 사용할 수 있습니다. 그러나 당신은 못 생기기 전에 이것을 너무 많이 할 수 있습니다. 아주 못생긴.

  • 반복 코드. 3 길이의 가장 큰 값은 무엇입니까 (Case ... Else ... End) 진술은 무엇입니까? 읽을 수있을거야!

    • 고객에게 빌어 먹을 물건을 계산하도록 지시하십시오.

내가 뭐 놓친 거 없니? 아마도, 자유롭게 의견을 말하십시오. 하지만 Cross Apply는 그러한 상황에서 신의 선수와 같습니다. CROSS APPLY (select tbl.value + 1 as someFormula) as crossTbl 그리고 Voilà! 새로운 필드는 이제 소스 데이터에 항상 존재했던 것처럼 실질적으로 사용할 준비가되었습니다.

Cross Apply를 통해 도입 된 값은 ...

  • 믹스에 성능, 복잡성 또는 가독성 문제를 추가하지 않고 하나 또는 다중 계산 필드를 만드는 데 사용됩니다.
  • Join과 마찬가지로, 몇 가지 후속 교차 응용 설명서는 다음을 참조 할 수 있습니다. CROSS APPLY (select crossTbl.someFormula + 1 as someMoreFormula) as crossTbl2
  • 후속 조인 조건에서 크로스 적용으로 도입 된 값을 사용할 수 있습니다.
  • 보너스로 테이블 값 기능 측면이 있습니다.

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

Cross Apply는 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

이것은 이미 기술적으로 매우 잘 응답되었지만 매우 유용한 방법에 대한 구체적인 예를 알려 드리겠습니다.

두 개의 테이블, 고객 및 주문이 있다고 가정 해 봅시다. 고객은 주문이 많습니다.

고객에 대한 세부 정보와 가장 최근의 순서를 제공하는 견해를 만들고 싶습니다. 결합 된 경우, 이것은 예쁘지 않은자가 요인과 집계가 필요합니다. 그러나 Cross Apply를 사용하면 매우 쉽습니다.

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

Cross Apply는 하위 쿼리가 필요한 서브 쿼리를 대체하는 데 사용할 수 있습니다.

하위 쿼리

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

여기서는 Cross Apply를 사용하여 회사 테이블의 열을 선택할 수 없습니다.

select P.*,T.CompanyName
from Person p
cross apply (
    select *
    from Company C
    where p.companyid = c.companyId and c.CompanyName like '%yyy%'
) T

가독성이어야한다고 생각합니다.)

Cross Apply는 사람들이 왼쪽 테이블의 각 행에 적용될 UDF가 사용되고 있다고 말하는 사람들에게 다소 독특합니다.

물론, 다른 친구들이 위에 게시 한 가입보다 크로스 적용이 더 잘 사용되는 다른 제한 사항이 있습니다.

다음은 성능 차이와 조인에 대한 사용법으로 모든 것을 설명하는 기사입니다.

SQL Server Cross는 적용되고 OUTER Apply Appry Alwind

이 기사에서 제안한 바와 같이, 정상적인 조인 작업 (내부 및 크로스)에 대한 성능 차이는 없습니다.

enter image description here

사용 차이는 다음과 같은 쿼리를 수행해야 할 때 발생합니다.

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)

즉, 기능과 관련이 있어야합니다. 내부 조인을 사용하여 수행 할 수 없으므로 오류가 발생합니다. "다중 파트 식별자"d.departmentid "는 구속 될 수 없었다." 여기서 각 행을 읽을 때 값이 함수로 전달됩니다. 나에게 멋지다. :)

이것이 Cross Apply와 Inner Join을 사용하는 이유로 자격이 있는지 확실하지 않지만 Cross Apply를 사용하는 포럼 게시물 에서이 쿼리가 나에게 답변되었으므로 내부 조인을 사용하여 동등한 방법이 있는지 확실하지 않습니다.

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

적용 연산자의 본질은 FROM 절에서 연산자의 왼쪽과 오른쪽 사이의 상관 관계를 허용하는 것입니다.

결합과 달리 입력 간의 상관 관계는 허용되지 않습니다.

Apply Operator의 상관 관계에 대해 말하면, 우리가 넣을 수있는 오른쪽에서 다음을 의미합니다.

  • 파생 된 테이블 - 별칭과 상관 관계 서브 쿼리로서
  • 테이블 값 기능 - 매개 변수가 왼쪽을 참조 할 수있는 매개 변수가있는 개념적보기

둘 다 여러 열과 행을 반환 할 수 있습니다.

이것은 아마도 오래된 질문이지만, 여전히 논리의 재사용을 단순화하고 결과를위한 "체인"메커니즘을 제공하기 위해 크로스의 힘을 좋아합니다.

아래의 SQL 바이올린을 제공했으며, Cross Apply를 사용하는 방법에 대한 간단한 예를 보여줍니다. 여기에서 더 복잡한 계산을 외삽하기는 어렵지 않습니다.

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

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top