Can subqueries produce different execution plans than CTE's?
-
07-02-2021 - |
سؤال
I was talking with the bossman, and he prefers subqueries over CTE's. Personally, I loathe subqueries. He mentioned that subqueries can be faster, but I am not convinced. I ran this short test:
with classes as
(select top 10 Classkey from dimclass
group by classkey
order by count(1) desc),
policies as (
select CarrierKey, policykey, periodeffectivedate from dimpolicy),
exposure as (
select policykey, classkey from DimExposure)
select * from policies p
inner join exposure x on p.PolicyKey = x.PolicyKey
inner join classes c on x.ClassKey = c.Classkey
has an excution plan of:
https://www.brentozar.com/pastetheplan/?id=SJYJUZNHS
select p.CarrierKey, p.PolicyKey, p.periodeffectivedate from dimpolicy p
inner join (select policykey, classkey from DimExposure) x on p.PolicyKey = x.PolicyKey
inner join (select top 10 Classkey from dimclass
group by classkey
order by count(1) desc) c on x.ClassKey = c.Classkey
has the same execution plan:
https://www.brentozar.com/pastetheplan/?id=rJs_LbVSr
Question: Is this always the case? In the weird and wonderful world of SQL Server, the answer always seems to be it depends.
المحلول
As is, I'd argue that the question isn't answerable. It's impossible to prove a negative and you won't find a guarantee in the product documentation. If you'd like an example of a technical difference between the two approaches, watch a few minutes of Paul White's Query Optimizer Deep Dive session. It is not clear how someone could translate that into a performance best practice.
I suggest approaching the issue as a matter of coding style instead of trying to find a performance best practice. Switching out a CTE for a derived table or a derived table for a CTE is not a meaningful way to rewrite a query.
نصائح أخرى
In general, it depends. One case where a CTE is nicer than a derived table is when you need to reference it several times in the query. A silly example:
SELECT x,y
FROM (
SELECT x,y FROM T WHERE p
) AS A
WHERE x = (SELECT MAX(x) FROM T WHERE p)
vs
WITH CTE (x,y) as (
SELECT x,y FROM T WHERE p
)
SELECT x,y FROM CTE WHERE x = (SELECT MAX(x) FROM CTE)
Different database engines treat multiple references to a CTE in different ways. In SQL Server, the CTE will generally be fully evaluated for each reference.