2013-07-25 2 views
0

Я пытаюсь добиться условно присоединиться, как этоУсловный присоединиться

declare @JoinWithT2 bit = 1; 

select T1.* from T1 
inner join T2 on (@JoinWithT2 = 0 or T1.Id=T2.Id) 

Это прекрасно работает, когда я прохожу @JoinWithT2 значение 1 дает мне результат, используя объединение двух таблиц, и когда я прохожу @JoinWithT2 значение 0 он возвращает все результаты от T1, игнорируя соединение.

Это все работает хорошо, но я обеспокоен производительности, так как выше, также может быть достигнуто как этот

if @JoinWithT2=0 
begin 
    select T1.* from T1 
end 
else 
begin 
    select T1.* from T1 
    inner join T2 on (T1.Id=T2.Id) 
end 

Что является лучшим способом для достижения условного соединения, первый один или второй?

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

+1

Это не игнорирует e присоединиться. Он всегда присоединяется к таблице. Если JoinWithT2 = 1, то он выполняет правильное соединение (по идентификатору), а если оно равно 0, вы присоединяетесь ко всем записям, эффективно превращая свое соединение в кросс-соединение. Это то, что вы хотите? – GolezTrol

+4

Обратите внимание, что где '@ JoinWithT2' равно 0, первый запрос ** не ** эквивалентен' select T1. * От T1' - вместо этого он становится неявным декартовым соединением - см. Http://sqlfiddle.com/# ! 3/3f574/3 –

+0

Да. На самом деле я хочу проигнорировать объединение, если значение '@ JoinWithT2' равно 0 –

ответ

2

Я запутался. Далее следует сделать либо декартово произведение или внутреннее соединение, в зависимости от значения JoinWithT2:

declare @JoinWithT2 bit = 1; 

select T1.* 
from T1 inner join 
    T2 
    on (@JoinWithT2 = 0 or T1.Id=T2.Id); 

Когда @JoinWithT2 является 0 то пункт on всегда верно. Это делает join эквивалентом cross join.

Следующая условна логика для выполнения объединения или принимая первую таблицу:

declare @JoinWithT2 bit = 1; 

select T1.* 
from T1 left outer join 
    T2 
    on (@JoinWithT2 = 1 and T1.Id=T2.Id) 
where @JoinWithT2 = 0 or T2.Id is not null; 

С точки зрения производительности, отдельное заявление в if, как правило, будет работать лучше. Для оптимизации SQL-сервера существует больше информации. Однако, если у вас есть индекс на T2(id), разница в производительности может быть не существенной по сравнению с другими частями запроса, например, возвратом результатов обратно пользователю.

1

Это случай, когда лучшим вариантом, вероятно, будет динамический SQL althouth, или условия не так плохи в новой версии SQL-сервера, как более старые. Оператор if хорош, но становится сложным в обслуживании после добавления двух или трех других таблиц, которые могут или не могут быть объединены в зависимости от конкретных условий. Условие или, вероятно, будет медленным с течением времени, и в запрос добавляется больше вещей. Создание запроса типа поиска с помощью только того, что вам нужно для этого конкретного набора параметров, часто является лучшим выбором.

Вы можете прочитать:

http://www.sommarskog.se/dyn-search-2008.html

или (если Youa повторно с помощью SQL Server 2005 или более ранних версий) http://www.sommarskog.se/dyn-search-2005.html

1

Почему вам нужно присоединиться, если вы ничего не выбрали от Т2?То же самое может быть достигнуто что-то вроде:

select T1.* 
from T1 
where @JoinWithT2 = 0 or T1.Id in (select T2.Id from T2); 
1

Статическое решение:

CREATE VIEW Person.vBusinessEntityAddressWithInfo 
AS 
SELECT bea.AddressID,bea.AddressTypeID,bea.BusinessEntityID,bea.ModifiedDate, 
     a.PostalCode AS AddressPostalCode,a.City AS AddressPostalCity 
FROM Person.BusinessEntityAddress bea 
JOIN Person.[Address] a ON bea.AddressID=a.AddressID; 
GO 
-- Test #1: columns from only one table Person.BusinessEntityAddress 
SELECT v.AddressID,v.BusinessEntityID 
FROM Person.vBusinessEntityAddressWithInfo v 
GO 
-- Test #2: columns from both tables 
SELECT v.AddressID,v.BusinessEntityID,v.AddressPostalCode 
FROM Person.vBusinessEntityAddressWithInfo v 
GO 

И если я смотрю на казни планов, то я мог видеть, что для Test #1 SQL-сервер использует только Person.BusinessEntityAddress таблицу (см FK elimination; Смотри также этот answer) и Test #2 SQL сервер использует обе таблицы: enter image description here

Другой "статические" (более или менее) решение:

DECLARE @Type BIT; 
SET  @Type=0; 

SELECT bea.*,NULL AS AddressPostalCode,NULL AS AddressPostalCity 
FROM Person.BusinessEntityAddress bea 
WHERE @Type=0 
UNION ALL 
SELECT bea.*,a.PostalCode AS AddressPostalCode,a.City AS AddressPostalCity 
FROM Person.BusinessEntityAddress bea 
JOIN Person.[Address] a ON bea.AddressID=a.AddressID 
WHERE @Type=1; 

Если я выполнить этот запрос с @Type=0 и SET STATISTICS IO ON то SQL Server будет считывать данные из BusinessEntityAddress:

Table 'Worktable'. Scan count 0, logical reads 0 
Table 'Worktable'. Scan count 0, logical reads 0 
Table 'BusinessEntityAddress'. Scan count 1, logical reads 112 

и когда я выполняю то же самое запрос с @Type=1, то SQL Server будет считывать данные из обеих таблиц:

Table 'Worktable'. Scan count 0, logical reads 0 
Table 'Address'. Scan count 1, logical reads 216 
Table 'BusinessEntityAddress'. Scan count 1, logical reads 112 
Table 'Worktable'. Scan count 0, logical reads 0 
Смежные вопросы