Преобразовать Where в подзапросе во внутреннее соединение

#sql #sql-server

#sql #sql-сервер

Вопрос:

Можно ли преобразовать приведенный ниже запрос в использование внутреннего соединения вместо подзапроса where В?

 select i.*, it.*
from ItemTypes it
    inner join Items i on (i.itemTypeID = it.ItemTypeID)
where i.itemID IN (......)
  

В подзапросе может быть возвращено 100 результатов, и я хочу избежать этого в подзапросе.

Комментарии:

1. вы пропустили подзапрос, как мы должны выяснить, можно ли его переписать с помощью join ?

2. Почему вы хотите избежать IN ? В любом случае это полусоединение и, как правило, более эффективно в SQL Server, поскольку перезапись в качестве соединения может привести к дублированию.

3. где i.ItemId IN (12313,123123,25234,1234345234,12342,123422,34,13435), но у меня может быть 100 или более идентификаторов в предложении IN.

4. @codecompleting — Ну и что? Если они возвращаются из подзапроса, это не имеет значения. Посмотрите на план выполнения, он будет реализован как полусоединение. Менее эффективно переписывать его, используя JOIN явно, чем использовать DISTINCT , чтобы избавиться от дубликатов.

Ответ №1:

Вы могли бы использовать выражение WITH common table (CTE):

 ;with SelectedItems (selectedIDs) as
(
    select distinct itemID from [...] where [...]
)
select i.*, it.*
from ItemTypes it
inner join Items i on i.itemTypeID = it.ItemTypeID
inner join SelectedItems on selectedIDs = i.itemID
  

Вы также можете определить временную #таблицу с индексом для хранения выборок:

 create table #SelectedItems
(
    selItemID int primary key clustered
)
insert into #SelectedItems (selItemID)
select [...]

select i.*, it.*
from ItemTypes it
inner join Items i on i.itemTypeID = it.ItemTypeID
inner join #SelectedItems si on si.selItemID = i.itemID

drop table #SelectedItems
  

Но что бы вы ни делали, будьте осторожны при измерении производительности до и после любого изменения.

Комментарии:

1. SelectedItems Для представления вашего CTE также потребуется distinct ключевое слово, как указал @MartinSmith в моем ответе…

Ответ №2:

 select i.*, it.*
from ItemTypes it
    inner join Items i on (i.itemTypeID = it.ItemTypeID)
    inner join (select itemID from Items where ...) i2 ON i.itemID = i2.itemID
  

Ответ №3:

Вы могли бы написать это так

 select i.*, it.*
from ItemTypes it
    inner join Items i on (i.itemTypeID = it.ItemTypeID)
    inner join (select distinct itemID from [...] where [...]) i2
        on (i.itemID = i2.itemID)
  

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

Комментарии:

1. Для этого необходимо DISTINCT будет поддерживать ту же семантику, IN что и .

2. Может быть, мне следует поместить свои идентификаторы в табличный тип, а затем присоединиться к нему?

3. @codecompleting: вы действительно измерили, что это медленно? Есть ли у вас соответствующие индексы для всех соответствующих столбцов?