공통 테이블 표현식 (CTE)의 이점은 무엇입니까?


21

에서 MSDN :

파생 테이블과 달리 CTE는 자체 참조가 가능하며 동일한 쿼리에서 여러 번 참조 될 수 있습니다.

저는 CTE를 많이 사용하고 있지만 CTE의 이점에 대해 깊이 생각해 본 적이 없습니다.

동일한 쿼리에서 CTE를 여러 번 참조하는 경우 :

  • 성능상의 이점이 있습니까?
  • 자체 조인을 수행하는 경우 SQL Server가 대상 테이블을 두 번 스캔합니까?

2
프로파일 러는 두 번 스캔하는지 알려줍니다. IMHO, CTE는 재귀에 훌륭합니다.
Dan Andrews

3
쿼리 최적화 프로그램이 실행 중일 때는 확실한 답변이 없습니다. 일부 쿼리는 성능상의 이점을 볼 수 있지만 일부 쿼리는 그렇지 않습니다. 때로는 CTE 대신 임시 테이블을 사용하는 것이 더 빠르며 때로는 그렇지 않습니다.

답변:


25

일반적으로 CTE는 결코 성능을 향상시키지 않습니다 .

CTE는 본질적으로 일회용입니다. 저장된 추가 통계 나 인덱스는 없습니다. 하위 쿼리의 속기 기능을합니다.

내 의견으로는 그것들은 쉽게 남용 될 수 있습니다 (제 직장의 코드에서 많은 양의 남용을 보았습니다). 좋은 대답이 여기 있지만 , 두 번 이상 무언가를 참조하거나 수십만 행이 넘는 경우 #temp대신 테이블에 넣고 색인을 만드십시오.


3
동의하다. 재귀 CTE를 제외하고는 가독성을 지원합니다
gbn

CTE가 계산하는 데 비용이 많이 들고 (큰 테이블에서 집계) 몇 개의 행만 반환하므로 (메모리에 보관할 수 있음) 그 결과가 두 번 이상 사용되면 어떻게됩니까? 성능을 향상시켜야합니까? (적어도 그것은 임시 테이블이 거의 사용되지 않는 PostgreSQL과 Oracle에 대한 나의 경험입니다)
a_horse_with_no_name

2
@a_horse_with_no_name-하위 쿼리로 만드는 것과 같습니다. 단일 쿼리에서 결과가 두 번 이상 사용되면 재사용되고 다시 계산되지 않습니다. 둘 이상의 쿼리에서 사용되는 경우 CTE첫 번째 쿼리 후에 결과가 삭제되므로 a 를 사용하는 것이 좋습니다.
JNK

@JNK : 감사합니다. 여기에서 SQL Server가 다르게 동작하는 것 같습니다.
a_horse_with_no_name

어떤 사람들은 특정 상황에서 CTE가 더 읽기
쉽다고 생각합니다.

14

CTE가 매우 유용한 재귀 외에 한 곳은 복잡한보고 쿼리를 만들 때입니다. 일련의 CTE를 사용하여 필요한 데이터 청크를 얻은 다음 최종 선택에 결합합니다. 파생 테이블이 많거나 20 조인으로 동일한 작업을 수행하는 것보다 유지 관리가 더 쉽다는 것을 알았으며 일대 다 관계로 인해 여러 레코드의 영향없이 올바른 데이터를 반환한다는 것을 확신 할 수 있습니다 다른 조인. 간단한 예를 들어 보겠습니다.

;WITH Conferences (Conference_id)
AS 
(select  m.Conference_id
FROM mydb.dbo.Conference m 
WHERE client_id = 10
    and Conference_id in 
            (select Conference_id from mydb.dbo.Expense 
            where amount <>0
            and amount is not null)
     )
--select * from Conferences
,MealEaters(NumberMealEaters, Conference_id, AttendeeType)
AS
(Select count(*) as NumberMealEaters, m.Conference_id,  AttendeeType 
from mydb.dbo.attendance ma 
join Conferences m on m.Conference_id = ma.Conference_id
where (ma.meals_consumed>0 or meals_consumed is null)and attended = 1
group by m.Conference_id)
--select * from MealEaters

,Expenses (Conference_id,expense_date, expenseDescription,  RecordIdentifier,amount)
AS
(select Conference_id,max(expense_date) as Expense_date, expenseDescription,  RecordIdentifier,sum(amount) as amount
    FROM
        (SELECT Conference_id,expense_date,  amount, RecordIdentifier
        FROM mydb.dbo.Expense
        WHERE  amount <> 0 
            and Conference_id IN 
            (SELECT  Conference_id
            FROM mydb.dbo.Conferences ) 
        group by Conference_id, RecordIdentifier) a
)
--select * from Expenses
Select m.Conference_id,me.NumberMealEaters, me.AttendeeType, e.expense_date,         e.RecordIdentifier,amount
from Conferences m
join mealeaters me on m.Conference_id = me.Conference_id
join expenses e on e.Conference_id = m.Conference_id

따라서 원하는 다른 정보를 분리하여 주석 처리 된 선택을 사용하여 각 부분의 주석을 해제하고 해당 범위까지만 실행하여 비용을 변경해야하는 경우 각 부분을 개별적으로 확인할 수 있습니다. 계산 (이 예에서)이 하나의 대규모 쿼리로 함께 혼합 된 경우보다 찾기가 더 쉽습니다. 물론 내가 사용하는 실제보고 쿼리는 일반적으로 예제보다 훨씬 더 복잡합니다.


1
검색어보고 만 하시겠습니까? 매일 작업하는 시스템에는 복잡한 트랜잭션 쿼리가 있습니다. 이상하게도 우리의보고 쿼리는 종종 간단한 쿼리 중 일부입니다. (물론 간단한 joinless CRUD 쿼리를 제외하고).
케빈 카스 카트

그 일반적으로 대부분 여기에 복잡하기 때문에 나는 예로서 그 사용
HLGEM

+1 때로는 더 논리적 (인간이 읽을 수있는) 쿼리가 잠재적으로 더 나은 성능을 발휘하는 쿼리보다 선호됩니다.
11

예. CTE가 일반적으로 동일한 결과 계획을 생성한다는 점을 감안할 때 각 구성 요소를 필요한 순서대로 시각적으로 배치 할 수있을 때 끔찍하게 중첩 된 다중 하위 쿼리 괴물을 만들 이유가 없습니다. XML 파일을 가져오고 다양한 곡예를 수행하여 데이터를 올바른 형식으로 가져옵니다. CTE 없이는 쓰기 / 읽기가 불가능합니다. (내 오래된 코드 중 일부는 아마도 끔찍한 하위 쿼리를 가지고있을 것입니다!)
underscore_d

0

항상 그렇듯이 성능이 크게 향상되는 경우가 있습니다. 선택에 CTE를 사용한 다음 INSERT INTO에서 CTE를 사용하는 INSERT INTO SELECT 문으로 볼 수 있습니다. RCSI가 데이터베이스에 설정되어 있어야 할 수도 있지만, 거의 선택하지 않은 경우에는 상당히 도움이 될 수 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.