Лучше ли делать соединение equi в предложении from или where clause

При объединении двух простых таблиц в столбцах первичного ключа и размещении условия равенства дополнений это можно сделать в самом соединении или в предложении where.

Например, следующие равнозначны. Мой вопрос: есть ли какие-либо причины использовать один стиль над другим?

SELECT * 
FROM A
INNER JOIN B ON A.A_ID = B.A_ID
            AND A.DURATION = 3.00

... против:

SELECT * 
FROM A
INNER JOIN B ON A.A_ID = B.A_ID
WHERE A.DURATION = 3.00

Ответ 1

Это стиль. Как правило, вы хотите поместить условия, которые определяют "форму" результирующего набора в предложении FROM (т.е. те, которые контролируют, какие строки из каждой таблицы должны объединяться вместе для получения результата), тогда как те условия, которые фильтруют результат set должен быть в предложении WHERE. Для INNER JOINs эффекты равны, но когда задействуются ВНЕШНИЕ СОБЫТИЯ (ВЛЕВО, ВПРАВО), это становится намного яснее.


В вашем первом примере мне оставлено задание "что это связано с таблицей B?" когда я столкнулся с этим нечетным состоянием в JOIN. Если во втором случае я могу пропустить предложение FROM (и все JOIN), если меня это не интересует, и просто посмотрите условия, которые определяют, будут ли строки возвращаться в предложении WHERE.

Ответ 2

Вообще говоря, он не имеет смысловой разницы.

Есть один крайний случай, когда он может это сделать. Если в запрос добавляется конструктор (устаревший) GROUP BY ALL, как показано ниже.

DECLARE @A TABLE(A_ID INT, DURATION DECIMAL(3,2) )
INSERT INTO @A VALUES(1,2.00)

DECLARE @B TABLE(A_ID INT)
INSERT INTO @B VALUES(1)

/*Returns one row*/
SELECT *
FROM @A A
INNER JOIN @B B ON A.A_ID = B.A_ID
WHERE A.DURATION = 3.00
GROUP BY ALL A.A_ID, A.DURATION, B.A_ID

/*Returns zero rows*/    
SELECT *
FROM @A A
INNER JOIN @B B ON A.A_ID = B.A_ID  AND A.DURATION = 3.00
GROUP BY ALL A.A_ID, A.DURATION, B.A_ID

Ответ 3

Это тип JOIN, который имеет значение.
Нет никакой разницы, либо версия предоставленного запроса будет использовать один и тот же план выполнения, потому что вы имеете дело с INNER JOIN.

Если вы работаете с OUTER JOIN (IE: LEFT, RIGHT), между двумя версиями существует огромная разница, так как критерий WHERE применяется после создания JOIN. Если критерии указаны в предложении ON, критерии применяются до того, как будет создан JOIN, что может существенно повлиять на результирующие наборы.

Ответ 4

Для SQL Server 2000+ планы запросов для каждого из этих запросов будут indentical, и поэтому так будет производительность.

Вы можете проверить это, используя SSMS, чтобы отобразить фактический план выполнения для каждого запроса, нажав CTRL + M перед выполнением запроса. На панели результатов будет добавлена ​​дополнительная вкладка, которая показывает план выполнения. Вы увидите, что в этом случае оба плана одинаковы.

Ответ 5

Это вопрос стиля. Оптимизатор сделает все возможное.

Ответ 6

    --Samples for time of join wheather can we write condition at where or ON 
create table #emp(id int ,teamid int)
create table #team(tid int,name char(2))
insert into #emp values(1,1)
insert into #emp values(2,1)
insert into #emp values(3,2)
insert into #emp values(4,0)

insert into #team values(1,'A')
insert into #team values(2,'B')
insert into #team values(3,'C')

--select * from #emp
--select * from #team

--on inner join => there is no difference in Query Exc. Plan
--select * from #emp e join #team t on e.teamid=t.tid where e.teamid=2
--select * from #emp e join #team t on e.teamid=t.tid and e.teamid=2


/*on outetr join see the differnence If dealing with an OUTER JOIN (IE: LEFT, RIGHT), 
there is a huge difference between the two versions because the WHERE criteria is applied after the JOIN is made. 
If the criteria is specified in the ON clause, the criteria is applied before the JOIN is made which can made a considerable difference 
between the result sets.*/
select * from #emp e left join #team t on e.teamid=t.tid
select * from #emp e left join #team t on e.teamid=t.tid where e.teamid=2
select * from #emp e left join #team t on e.teamid=t.tid and  (e.teamid=2 or t.tid=1) and t.name='A'


drop table #emp
drop table #team