Все технические форумы на одном сайте Удобный поиск информации с популярных форумов в одном месте
Вопрос: Какая разница между Left Join и Right Join

Нашел в документации такое:
автор
RIGHT JOIN реализован аналогично LEFT JOIN.

А про LEFT JOIN пишут такое :
автор
Выражение "A LEFT JOIN B" в MySQL реализовано следующим образом:
...
Таблица B устанавливается как зависимая от таблицы A и от всех таблиц, от которых зависит A.
....
Выполняются все стандартные способы оптимизации соединения, за исключением того, что таблица всегда читается после всех таблиц, от которых она зависит.

Получается таблица А используя LEFT JOIN будет читаться первой, но и в запросе "A RIGHT JOIN B" таблица А все равно будет читаться первой.
Поэтому:
SELECT * FROM
    t1 RIGHT JOIN t2
    USING (blah_id)

будет выполнятся с такой же скоростью что и запрос:
SELECT * FROM
    t1 LEFT JOIN t2
    USING (blah_id)
    WHERE t2.blah_id IS NOT NULL


Я правильно понял?
Ответ:
Vano34
Получается таблица А используя LEFT JOIN будет читаться первой, но и в запросе "A RIGHT JOIN B" таблица А все равно будет читаться первой.
Нет. Всегда первой читается ЛЕВАЯ таблица.
Vano34
А еще там было написано, что предпочтительнее использовать LEFT JOIN

Да. Это снимает видимую неоднозначность при смешении типов соединений и отсутствии задающих порядок соединения скобок.
Впрочем, парсер-оптимизатору по барабану. Первое, что он сделает - это трансформирует текст запроса во внутренний псевдокод, а там нет правого и левого связываний, это одно и то же связывание.
Вопрос: LEFT JOIN + WHERE не дружит с derived таблицами

  SET @dt = (select CONCAT(2016, '-', 02, '-', '01'));
  SET @mx = DAYOFMONTH(DATE_SUB(DATE_ADD(@dt, INTERVAL 1 MONTH), INTERVAL 1 DAY));
  
  select * FROM (
         SELECT DATE_ADD(@dt, INTERVAL Days DAY) D, weekday(DATE_ADD(@dt, INTERVAL Days DAY)) + 1 month_weekdays
         FROM (select @d:=0 as Days
               union
               select @d:=@d+1 as Days from 
                  (SELECT 1 a UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9 
                    UNION SELECT 10 UNION SELECT 11 UNION SELECT 12 UNION SELECT 13 UNION SELECT 14 UNION SELECT 15 UNION SELECT 16 UNION SELECT 17
                    UNION SELECT 18 UNION SELECT 19 UNION SELECT 20 UNION SELECT 21 UNION SELECT 22 UNION SELECT 23 UNION SELECT 24 UNION SELECT 25
                    UNION SELECT 26 UNION SELECT 27 UNION SELECT 28 UNION SELECT 29 UNION SELECT 30 UNION SELECT 31
                  ) t
               limit 0, 31
              ) v 
         WHERE DATE_ADD(@dt, INTERVAL Days DAY) < DATE_ADD(@dt, INTERVAL 1 MONTH)
    ) mon
    LEFT JOIN rs_sched r ON r.dtDate = mon.D
    WHERE r.centerid = 0

Смысл derived таблицы "v" - список дней-дат для выбранного месяца и года (если есть более элегатное решение без UNION и без временных-постоянных таблиц - welcome please).

Стоит убрать WHERE - все появляется как надо - то есть все 29 дней февраля с некоторыми записями из rs_sched.
Как только добавляю WHERE, ограничивающий записи из rs_sched - получаю только две записи, которые есть в rs_sched.

И что это за LEFT JOIN такой и что с этим делать?

PS: версия 5.5.44-37.3-log
Ответ:
MasterZiv
_Промешан_
Хм... действительно.

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


К ограничиваемой таблице оно будет относится только внутри фразы ... JOIN ON

Да, это я уже осознал :)

Но спасибо.
Вопрос: Оптимизация запроса с left outer join

Добрый вечер !
Господа помогите советом.
Не получается оптимизировать запрос c left outer join, так чтобы не было full table scan (2 шт.) и cost был поменьше.


имеются 2 таблицы (поля и констраинты не имеющие отношения к вопросу я выкинул)

create table TableA
    (Id                             number(18,0) default 0 not null,
    Version                        number(18,0))
/

-- Indexes for TableA

create index Idx_TableA_Version on TableA
  (
    Version                         asc
  )
/

alter table TableA
add constraint Pk_TableA primary key (Id)
using index
/

create table TableB
    (Id                             number(18,0) not null,
    Version                        number(18,0),
    Querysend_Date                 date)
/

-- Indexes for TableB

create unique index Idx_TableB_Version on TableB
  (
    Version                         asc
  )
/

create index Idx_TableB_Id_Vers on TableB
  (
    Id                              asc,
    Version                         asc
  )
/

-- Constraints for TableB

alter table TableB
add constraint Pk_TableB primary key (Id)
using index
/

-- Foreign Key
alter table TableB
add constraint Fk_TableB_Stmtturn foreign key (Id)
references TableA (Id)
/


Во второй таблице не обязательно будет содержаться запись соответствующая записи в первой, поэтому использую left (outer) join
Мне нужно получить все записи (в объединении двух таблиц) значения поля version которых больше заданной.
в таблицах десятки миллионов записей.
интересно что если я заменяю left join на inner join от full table scan исчезает и cost становится маленьким,
что бы могли посоветовать чтобы избавиться от Full table scan и снизить cost используя внешнее объединение ?




SQL_ID az1y2cda66zcg, child number 0
-------------------------------------
select T.Id from TableA T
left join TableB Stq
on Stq.Id = T.Id where (T.Version > 1216913415 or Stq.Version> 1216913415)

Plan hash value: 105757921

----------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | TQ |IN-OUT| PQ Distrib |
----------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | | | 38592 (100)| | | | |
| 1 | PX COORDINATOR | | | | | | | | |
| 2 | PX SEND QC (RANDOM) | :TQ10002 | 2 | 52 | 38592 (1)| 00:07:44 | Q1,02 | P->S | QC (RAND) |
|* 3 | FILTER | | | | | | Q1,02 | PCWC | |
|* 4 | HASH JOIN RIGHT OUTER| | 2 | 52 | 38592 (1)| 00:07:44 | Q1,02 | PCWP | |
| 5 | PX RECEIVE | | 9350K| 115M| 962 (1)| 00:00:12 | Q1,02 | PCWP | |
| 6 | PX SEND HASH | :TQ10001 | 9350K| 115M| 962 (1)| 00:00:12 | Q1,01 | P->P | HASH |
| 7 | PX BLOCK ITERATOR | | 9350K| 115M| 962 (1)| 00:00:12 | Q1,01 | PCWC | |
|* 8 | TABLE ACCESS FULL| TableB | 9350K| 115M| 962 (1)| 00:00:12 | Q1,01 | PCWP | |
| 9 | BUFFER SORT | | | | | | Q1,02 | PCWC | |
| 10 | PX RECEIVE | | 9350K| 115M| 37622 (1)| 00:07:32 | Q1,02 | PCWP | |
| 11 | PX SEND HASH | :TQ10000 | 9350K| 115M| 37622 (1)| 00:07:32 | | S->P | HASH |
| 12 | TABLE ACCESS FULL| TableA | 9350K| 115M| 37622 (1)| 00:07:32 | | | |
----------------------------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

3 - filter(("T"."VERSION">1216913415 OR "STQ"."VERSION">1216913415))
4 - access("STQ"."ID"="T"."ID")
8 - access(:Z>=:Z AND :Z<=:Z)

Ответ:
Upstream
C union all вместо union будет быстрее.
Это если вы не против задвоения данных в результате:
SQL> select 1 from dual union select 1 from dual;
 
         1
----------
         1
 
SQL> select 1 from dual union all select 1 from dual;
 
         1
----------
         1
         1
Вопрос: LEFT JOIN и Using join buffer (Block Nested Loop)

Доброго времени суток всем, хотелось бы попросить у сообщества помощи, т.к. не могу понять, это баг MySQL или я что-то делаю не так. Опишу проблему. Имеется таблица (table1), которая связывается с другой (table2) с помощью LEFT JOIN.
Если используется в выборке один столбец из table2, то индекс успешно используется.
SELECT
	`table1`.`id`,
	`table2`.`value`
FROM 
	`table1`
LEFT JOIN `table2` ON `table2`.`table1_id` = `table1`.`id`
WHERE 
	`table1`.`level` = 'test'

idselect_typetabletypepossible_keyskeykey_lenrefrowsExtra
1SIMPLEtable1ALLNULLNULLNULLNULL49200Using where
1SIMPLEtable2refPRIMARYPRIMARY4test1.table1.id1NULL


Если используются два столбца из table1, то в EXPLAIN'е красуется загадочная надпись Using join buffer (Block Nested Loop), индекс не используется и запрос выполняется нереально долго.
SELECT 
	`table1`.`id`,
	`table2`.`value`, 
	`table2`.`count`
FROM 
	`table1`
LEFT JOIN `table2` ON `table2`.`table1_id` = `table1`.`id`
WHERE 
	`table1`.`level` = 'test'

idselect_typetabletypepossible_keyskeykey_lenrefrowsExtra
1SIMPLEtable1ALLNULLNULLNULLNULL49200Using where
1SIMPLEtable2ALLPRIMARYNULLNULLNULL1Using where; Using join buffer (Block Nested Loop)


Пока в качестве решения данной проблемы решил добавить второй аналогичный LEFT JOIN.
SELECT 
	`table1`.`id`,
	`table2`.`value`, 
	`table3`.`count`
FROM 
	`table1`
LEFT JOIN `table2` ON `table2`.`table1_id` = `table1`.`id`
LEFT JOIN `table3` ON `table3`.`table1_id` = `table1`.`id`
WHERE 
	`table1`.`level` = 'test'

И теперь все работает замечательно, индексы используются.
idselect_typetabletypepossible_keyskeykey_lenrefrowsExtra
1SIMPLEtable1ALLNULLNULLNULLNULL49200Using where
1SIMPLEtable2refPRIMARYPRIMARY4test1.table1.id1NULL
1SIMPLEtable3refPRIMARYPRIMARY4test1.table1.id1NULL


Теперь назревает вопрос, это норма или баг?
Ответ:
javajdbc
"глюков" = "нестабильности пограничного состояния"...

Вот нехрен было делать - почти два часа пробовал воспроизвести такое пограничное состояние на приведённом примере. Как и следовало ожидать - с нулевым результатом.
Вопрос: Есть ли разница между left join и right join?

Нашел такую наглядную ссылку с иллюстрациями:


Возник вопрос - если right join полностью идентичен left join (с учетом зеркальности), то зачем он вообще нужен?
Только для удобства или есть другие причины?
Ответ: Понятно, спасибо за пояснения.
Вопрос: По сиквелу. INNER JOIN VS WHERE

Нужен столбец, пиши JOIN
Не нужен столбец пиши WHERE
Зачем писать INNER JOIN если столбец не нужен?
или я что то пропустил
Ответ: MSSQLAndDotNet,

Разработчик пишет запрос исходя из порядка логической обработки операторов () выстраивая запрос в зависимости от того, что хочет получить и используя разные языковые конструкции (inner join, where, left join, exists, etc).

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

В зависимости от условий оптимизатор может:
- проталкивать предикаты из ON/WHERE на уровень доступа к таблицам
- заменять outer join на inner join
- заменять semi join (который часто используется для языковой конструкции Exists) на inner join
и много других приемов, в зависимости от разных условий - главное - сохранить смысл запроса.

Так что абстрактно рассуждать, что быстрее/медленнее не имеет особого смысла, точнее, рассуждать можно, приводя разные примеры, но правила "серебряной пули" сформулировать нельзя, поэтому лучше смотреть конкретный план.
Вопрос: Не работает LEFT JOIN

Сделал выборку в конструкторе. По умолчанию он взял таблицу peni c объединением LEFT JOIN, однако мне нужно сделать RIGHT JOIN. При выполнении запроса выдает ошибку Не поддерживается выражение объединения JOIN

PARAMETERS DATE_CUR DateTime,
           OF_CAT_ID Long;


SELECT offers.offer_id,
       offers.offer_number,
       offer_cats.offer_cat_name,
       clients.client_name,
       Nz([sum_on_date],0) AS p_sum_on_date,
       Nz([sum_payed_on_date],0) AS p_sum_payed_on_date,
       Nz([sum_payed_on_date],0)-Nz([sum_on_date],0) AS saldo,
       Sum(peni.peni_sum) AS [Sum-peni_sum]
FROM (offer_cats
      INNER JOIN (clients
                  INNER JOIN ((offers
                               LEFT JOIN qrySaldoPayed ON offers.offer_id = qrySaldoPayed.offer_id)
                              LEFT JOIN qrySaldoPlanPayment2 ON offers.offer_id = qrySaldoPlanPayment2.offer_id) ON clients.client_id = offers.client_id) ON offer_cats.offer_cat_id = offers.offer_cat_id)
*вот этот*RIGHT JOIN peni ON offers.offer_id = peni.offer_id
WHERE (((offers.offer_cat_id)=[OF_CAT_ID]))
  OR ((([OF_CAT_ID])=0))
GROUP BY offers.offer_id,
         offers.offer_number,
         offer_cats.offer_cat_name,
         clients.client_name,
         Nz([sum_on_date],0),
         Nz([sum_payed_on_date],0),
         Nz([sum_payed_on_date],0)-Nz([sum_on_date],0);


К сообщению приложен файл. Размер - 46Kb
Ответ:
Radzhab
однако мне нужно сделать RIGHT JOIN./b]
Вы уверены?
"offers RIGHT JOIN peni" гласит о том, что "peni" - главная таблица и в ней могут быть записи, не имеющие подчиненных в "offers", что маловероятно.
Возможно вам просто нужно заменить RIGHT JOIN на INNER JOIN.
Если же настаиваете на RIGHT JOIN (желательно с аргументами), то тогда и INNER JOIN к "offer_cats" и "clients" тоже замените на RIGHT JOIN.
Вопрос: совет по inner join

select *
from tbFIO
inner join tbAdres on tbFIO.idAdres=tbAdres.id
inner join tbRayonGorod on tbAdres.idGorodRayon=tbRayonGorod.ID
inner join tbStreet on tbAdres.idStreet=tbStreet.id
inner join tbNomerDoma on tbAdres.idNomerDoma=tbNomerDoma.id and
inner join tbNomerKvartira on tbAdres.idNomerKvartira=tbNomerKvartira.id
where surname='Иванов'
order by name,o_name


Проблема в том, что не выводятся Ивановы у которых квартира пустая.
Я новичок, помогите как выйти из этой ситуации.
Ответ: спасибо дорогие, поменял на left и о чуда все заработало
Вопрос: Почему left join выполняет чтение таблицы, при невыполнимом условии?

SQL 2000

select
 t1.id, t2.id, t3.id
from
 t1
left join
 t2
on t1.f1 =1 and t2.id = t1.f2
left join
 t3
on t1.f1 =2 and t3.id = t1.f2


не смотря на то, что t1.f1 со значением 1 не существует, в плане видны чтения таблицы и в статистике
Table 't2'. Scan count 125, logical reads 553, physical reads 9, read-ahead reads 24.
зачем он читает таблицу?
можно ли как-то этого избежать?

да, я понимаю, что такая структура БД не по феншую, но делал ее не я и реструктурировать возможности нет
Ответ:
Glory
select t1.id, t2.id, NULL
from t1 inner join t2 on t2.id = t1.f2
where t1.f1 =1 
union 
select t1.id, NULL, t3.id
from t1 inner join  t3 on t3.id = t1.f2
where t1.f1 =2


похоже, это то что нужно! спасибо! :))
Вопрос: Что значит "employees e join employees Davis"

Доброго времени суток.
не могу понять что значит "employees e join employees Davis".
Код Oracle 11 SQL
1
2
3
4
SELECT e.last_name, e.hire_date
FROM employees e JOIN employees Davies
ON (Davies.last_name='Davies')
WHERE Davies.hire_date<e.hire_date;
в в чем отличие join от inner join
объясните пожалуйста.
Ответ:
Сообщение от Jarry
не могу понять что значит "employees e join employees Davis".
Соединение таблицы с собой. Чтобы различать их в запросе, каждой дается алиас (хотя я предпочитаю давать алиасы таблицам в любом случае - читабельность лучше).

Сообщение от Jarry
в чем отличие join от inner join
Ни в чем. И то, и другое - внутреннее соединение. INNER можно писать для наглядности (с точки зрения английского языка), можно не писать, результат один и тот же.