Имя: Пароль:
1C
 
Что лучше условие В или внутреннее соединение с таблицей?
0 Черный всадник
 
08.04.09
12:57
Собственно как будет лучше так:
...
 ГДЕ
   Таблица_1.Поле_1 В
     (ВЫБРАТЬ
         Таблица_2.Поле_2
       ИЗ
         Таблица_2 КАК Таблица_2
     )
...
или так:
...
 ИЗ
   Таблица_1 КАК Таблица_1
   ВНУТРЕННЕЕ СОЕДИНЕНИЕ Таблица_2 КАК Таблица_2
     ПО Таблица_1.Поле_1 = Таблица_2.Поле_2
...

Таблица Таблица_2 может содержать несколько десятков тясяч записей.
1 Mort
 
08.04.09
12:58
ИМХО соединение.
2 sur0k
 
08.04.09
13:02
(0) Сделай замер производительности
3 Черный всадник
 
08.04.09
13:02
(1) Я то же думаю соединение,  но уверенности нет. Условие В рекомендовано для списков из 100-300 записей.
4 Черный всадник
 
08.04.09
13:03
(2) Наверняка тут кто-то уже делал. Сейчас стенда под рукой нет :(
5 ShoGUN
 
08.04.09
13:05
Я думаю что соединение, плюс - оно читабельней.
6 Кириллка
 
08.04.09
13:05
(0)так это разные механизмы и используются для разных вещей.
Их сравнивать можно только для какой-то конкретной задачи.
7 Черный всадник
 
08.04.09
13:12
(6) Что неконкретного в (0)? Мне необходимо сделать выборку из таблицы Таблица_1 с описаными условиями. Я понимаю, что это разные механизмы, вот и спрашиваю как получше сделать.
8 Кириллка
 
08.04.09
13:15
(7)на пальцах объяснить?
9 Кириллка
 
08.04.09
13:16
+8 стоп, не буду объяснять, пока ты не уберешь из своего профиля Интересы: Проектирование БД
10 Джинн
 
08.04.09
13:16
Должно быть пофигу с точки зрения производительности.
11 Черный всадник
 
08.04.09
13:17
(8) Объясни.
12 dimoff
 
08.04.09
13:18
По простой логике В должно отрабатывать как минимум не дольше, чем внутреннее соединение.
13 dimoff
 
08.04.09
13:19
Так что на чем основываются имхи (0) и (1) вообще непонятно.
14 Черный всадник
 
08.04.09
13:22
(10, 12, 13) Опираясь на логику Если поле Поле_2 индексировано?
15 Кириллка
 
08.04.09
13:22
В первой таблице:
Строка1
Строка2
Строка3
Строка4

Во второй таблице:
Строка1
Строка2
Строка3
Строка3
Строка3
Строка4

Результатом в случае с IN будет:
Строка1
Строка2
Строка3
Строка4

Результатом в случае с INNER JOIN будет:
Строка1
Строка2
Строка3
Строка3
Строка3
Строка4
16 Черный всадник
 
08.04.09
13:24
(15) Сори, забыл - дублирование строк в результате не принципиально.
17 Черный всадник
 
08.04.09
15:02
Больше никто этим не интересовался что ли...
18 Defender aka LINN
 
08.04.09
15:05
запрос в "В" отрабатывает на каждую строку исходной таблицы.
Вопросы?
19 73
 
08.04.09
15:05
По моему опыту соединение быстрее.
20 FreeArcher
 
08.04.09
15:09
Запросы будут работать по разному:
1. В
Будет производится сервером обход по таблице и по каждой строке проверятся условие.
2. соединение
Возьмутся обе таблице проиндексируются (если нет индексов) по полю через которое происходит соединение. А затем будет произведена связь по индексу и выйдет результирующая таблица.

вариант 2 должен быть эффективнее на больших объемах хотя бы из-за индексов и внутренней оптимизации СУБД.
21 Stepa86
 
08.04.09
15:10
(18) а если временной таблице
22 Stepa86
 
08.04.09
15:11
+(21)а если временной таблицей заменить запрос в "В"
23 nop
 
08.04.09
15:11
я думаю что лучше пакетный запрос + "В"
24 Defender aka LINN
 
08.04.09
15:11
(21) А разница?
25 Kolyasik
 
08.04.09
15:11
сделай через временные таблицы проиндексируй поля, а потом соедини...
26 Sadovnikov
 
08.04.09
15:12
(0) Ситуации разные бывают. Есть примеры, когда замена INNER JOIN на IN сократила время выполнения запроса с нескольких минут до нескольких секунд.
27 Stepa86
 
08.04.09
15:12
(24) "отрабатывает на каждую строку исходной таблицы" означает, что каждый раз запрос выполняется? или результат там кэшируется
28 Черный всадник
 
08.04.09
15:13
(20) Вот я подозревал, что как то так должно происходить. Но все как то времени не было проверить :) Спасибо.
29 Sadovnikov
 
08.04.09
15:13
(20) "проиндексируются (если нет индексов) " - ничего не путаешь?
30 Невский Александр
 
08.04.09
15:14
(6) +1
31 orefkov
 
08.04.09
15:17
(26)
Если поле в присоединяемой таблице не индексированное?
32 Кириллка
 
08.04.09
15:17
(20)Странно говорить об внутренней оптимизации СУБД (какой?) и индексах (они есть?).
33 Sadovnikov
 
08.04.09
15:20
(31) Не совсем понял...
34 Черный всадник
 
08.04.09
15:25
(26) В мем случае таблица_1 содержит в среднем 1 000 000 записей, таблица_2 в среднем 5 000 записей. Поле)1 и Поле_2 индексированы. Поле_2 содержит уникальные значения, значения в Поле_1 могут повторяться. Тут будет лучше INNER JOIN или IN?
35 Sadovnikov
 
08.04.09
15:27
(34) Я бы сделал ставку на JOIN. Тольк по возможности LEFT JOIN, а не INNER.
А еще бы большую ставку я сделал на тест данной ситуации :) Проверить-то не долго.
36 Черный всадник
 
08.04.09
15:30
(35) Ночью сервак освободится потесчу. Почему LEFT, а не INNER? Тогда ведь придется условие по NULL накладывать, чтоб отсечь лишние записи.
37 fisher
 
08.04.09
15:31
(0) Тут сложно сказать. Ведь какой именно план выполнения запроса будет выбран оптимизатором запросов - неизвестно. Это зависит от многих факторов (как явных, так и неявных).
На практике рекомендовано, всегда когда только можно (и логично) использовать соединения, а не альтернативные способы. Считается, что в этом случае больше вероятность того, что оптимизатором запросов будет выбран оптимальный план выполнения.
Т.е. изначально лучше всего следовать общим рекомендациям (использовать JOIN, где можно), а когда уже речь идёт об оптимизации выполнения конкретного тяжелого запроса - анализировать план выполнения на предмет узких мест и пробовать варианты.
38 fisher
 
08.04.09
15:36
(36) В данном конкретном простом случае (0), рискну предположить что план выполнения будет выбран одинаковый (или сопоставимый по скорости).
39 Sadovnikov
 
08.04.09
15:47
(0)
Set NoCount On

Declare @Счетчик Int, @Начало DateTime, @Конец DateTime

Create Table T1 (P1 Int)
Create Table T2 (P1 Int)

Set @Счетчик = 0

While @Счетчик < 1000000 Begin
   Insert Into T1 Values (@Счетчик)
   Set @Счетчик = @Счетчик + 1
End

Set @Счетчик = 0

While @Счетчик < 5000 Begin
   Insert Into T2 Values (@Счетчик)
   Set @Счетчик = @Счетчик + 1
End

Create Index _1 On T1 (P1)
Create Index _2 On T2 (P1)

Set @Счетчик = 0
While @Счетчик < 10 Begin
   Set @Начало = GETDATE()
   
   Select *
   From T1 (NoLock)
   Inner Join T2 (NoLock) On T1.P1 = T2.P1
   
   Set @Конец = GETDATE()
   Print 'JOIN ' + Str(DATEDIFF(ms, @Начало, @Конец))
   
   Set @Начало = GETDATE()
   
   Select *
   From T1 (NoLock)
   Where T1.P1 In (Select P1 From T2 (NoLock))
   
   Set @Конец = GETDATE()
   Print 'IN ' + Str(DATEDIFF(ms, @Начало, @Конец))

   Set @Счетчик = @Счетчик + 1
End

Drop Table T1
Drop Table T2
.
Результат:
JOIN         96

IN         30

JOIN         93

IN         16

JOIN         93

IN         16

JOIN        110

IN         13

JOIN        110

IN         16

JOIN         93

IN         16

JOIN         90

IN          0

JOIN         96

IN         30

JOIN         80

IN         13

JOIN        110

IN          0
40 Черный всадник
 
08.04.09
15:49
(39) Спасибо :) Придется переписывать...
41 Широкий
 
08.04.09
15:55
(39) В первом запросе выводятся все поля, а во втором только первой таблицы - не справедливо
42 Леха Дум
 
08.04.09
15:56
(39) а если поменять местами порядок выборки сначала IN потом JOIN? Кэш на сервере не влияет на результат?
43 Черный всадник
 
08.04.09
15:57
(42) Они уже должны быть в кэше
44 Леха Дум
 
08.04.09
16:02
(43) хотя да, временные таблы сразу в кэше, но все же если поменять местами?
45 Sadovnikov
 
08.04.09
16:10
(44) Попробуй. А то я таблицы уже грохнул - лень ждать, пока они снова заполнятся...
А еще - кто помнит как программно кэши чистить?
46 Леха Дум
 
08.04.09
16:12
(45) уже, от перемены мест слагаемых сумма практически не меняется :)
47 Кириллка
 
08.04.09
16:36
(45)
DBCC DROPCLEANBUFFERS
–- дает возможность тестировать запросы при незаполненном буфере данных

DBCC FREEPROCCACHE
–- дает возможность тестирования запросов при незаполненном кэше планов исполнения.
48 fisher
 
08.04.09
17:16
(39) Считаю данный тест нифига не показательным. На его основе ни в коем случае нельзя делать вывод, что IN производительнее JOIN. Обязательно нужно сравнивать в боевых условиях. На этом примере в самом деле для IN был сформирован более оптимальный план выполнения. Если модифицировать пример или наполнение таблиц - результат может обратный получиться.
Когда я на первой попавшейся рабочей базе тестанул (на примере таблицы дока и его табличной части), то получил одинаковые планы выполнения.
49 Sadovnikov
 
08.04.09
21:38
(47) Пасиб!
(48) +1. Был взят самый простой пример. Причем, пример, результаты которого противоречат моему предположению в (35). Каждый случай надо рассматривать отдельно на реальных боевых данных и железе.
Именно по этому в классе, отвечающем за фильтры в запросе, сделали свойство - как фильтровать. С ипользованием In или Join. Скуль, зараза, штука хитрая :)