сначала фильтровать или присоединиться?

Я изначально просто написал запрос, чтобы узнать годовой общий номер заказа на одного клиента, превышающий 1. В 1.query я отфильтровал результирующий набор и присоединил его к другому результирующему набору, который узнал имя клиента. Любопытно, что, по-моему, фильтр сначала обеспечивал бы лучшую производительность, поскольку для этого требовалось меньше результатов. Поэтому я написал второй запрос для объединения сначала, а затем фильтр, который выглядит более аккуратно, чем первый запрос. Результат такой же, как я ожидаю, потому что все время в результате ниже. Но я не уверен, какое время самое главное? Или этот случай просто совпаден? Как думать о производительности?

use [AdventureWorks2012] set statistics time on; --1.filter first,join second select tempC.*,tempP.FirstName,tempP.LastName from (select Year(OrderDate) As OrderYear,CustomerID,count(CustomerID) As CustomerOrderAmt from Sales.SalesOrderHeader group by Year(OrderDate),CustomerID having count(CustomerID) >1 ) as tempC join( select p.FirstName,p.LastName,c.CustomerID from Person.Person as p join Sales.Customer as c on c.PersonID=p.BusinessEntityID ) as tempP on tempC.CustomerID=tempP.CustomerID order by tempC.OrderYear,tempC.CustomerID GO --2.join first,filter second select Year(so.OrderDate) As Orderdate,so.CustomerID,count(so.CustomerID) As CustomerOrderAmt,p.FirstName,p.LastName from Sales.SalesOrderHeader as so join Sales.Customer as C on so.CustomerID=c.CustomerID join Person.Person as p on c.PersonID=p.BusinessEntityID group by Year(so.OrderDate),so.CustomerID,p.FirstName,p.LastName having count(so.CustomerID)>1 go 

Solutions Collecting From Web of "сначала фильтровать или присоединиться?"

Оптимизатор запросов может выбирать действия в любом порядке, которые приводят к одному и тому же логическому результату, поэтому даже если вы попытаетесь сначала фильтровать и затем присоединиться к нему, если вы не принудительно его используете с помощью таблицы или таблицы temp, оптимизатор может присоединиться к фильтру.

Если вы действительно считаете, что оптимизатор делает что-то глупое, вы можете попробовать такие вещи, как таблица var или temp, но то, что кажется глупым, на самом деле не может быть по причинам, которые становятся довольно продвинутыми.

Тем не менее, иногда то, как вы пишете запрос, будет влиять на то, что делает оптимизатор, поэтому вы должны в основном смотреть на планы выполнения. Если они одинаковы, используйте самый ясный код. Если они не тестируют и не тестируют снова, и идут с тем, что кажется лучшим.

Я считаю хорошей практикой использовать подзапросы, позволяющие уменьшить общее количество операций присоединения и количество столбцов в блоке GROUP BY. Поэтому я сразу скажу вам, что первый запрос определенно более эффективен.

Запросы:

 SELECT t.OrderYear , t.CustomerID , t.CustomerOrderAmt , p.FirstName , p.LastName FROM ( SELECT OrderYear = YEAR(OrderDate) , CustomerID , CustomerOrderAmt = COUNT(CustomerID) FROM Sales.SalesOrderHeader GROUP BY YEAR(OrderDate) , CustomerID HAVING COUNT(CustomerID) > 1 ) t JOIN ( SELECT p.FirstName , p.LastName , c.CustomerID FROM Person.Person p JOIN Sales.Customer c ON c.PersonID = p.BusinessEntityID ) p ON t.CustomerID = p.CustomerID ORDER BY t.OrderYear , t.CustomerID 

против

 SELECT Orderdate = YEAR(so.OrderDate) , so.CustomerID , CustomerOrderAmt = COUNT(so.CustomerID) , FirstName = MAX(p.FirstName) , LastName = MAX(p.LastName) FROM Sales.SalesOrderHeader so JOIN Sales.Customer c ON so.CustomerID = c.CustomerID JOIN Person.Person p ON c.PersonID = p.BusinessEntityID GROUP BY YEAR(so.OrderDate) , so.CustomerID HAVING COUNT(so.CustomerID) > 1 

Стоимость запроса:

Стоимость запроса

Время исполнения:

 -- first query SQL Server Execution Times: CPU time = 94 ms, elapsed time = 395 ms. -- second query SQL Server Execution Times: CPU time = 140 ms, elapsed time = 480 ms.