Операции LEFT JOIN, RIGHT JOIN. Join left пример
SQL Left Join
LEFT JOIN - возвращает строки из левой таблицы(table_name1), даже если их нет в правой таблице (table_name2).
Синтаксис SQL LEFT JOIN
1 2 3 4 | SELECT column_name(s) FROM table_name1 LEFT JOIN table_name2 ON table_name1.column_name=table_name2.column_name |
- Замечание: В некоторых базах данных LEFT JOIN имеет имя LEFT OUTER JOIN.
Пример SQL LEFT JOIN
Есть таблица "Persons":
1 | Hansen | Ola | Timoteivn 10 | Sandnes |
2 | Svendson | Tove | Borgvn 23 | Sandnes |
3 | Pettersen | Kari | Storgt 20 | Stavanger |
Есть таблица "Orders":
1 | 77895 | 3 |
2 | 44678 | 3 |
3 | 22456 | 1 |
4 | 24562 | 1 |
5 | 34764 | 15 |
Теперь мы хотим получить список всех лиц и их заказов из таблицы выше.
Для этого используем такой запрос:
1 2 3 4 5 | SELECT Persons.LastName, Persons.FirstName, Orders.OrderNo FROM Persons LEFT JOIN Orders ON Persons.P_Id=Orders.P_Id ORDER BY Persons.LastName |
Результат запроса:
Hansen | Ola | 22456 |
Hansen | Ola | 24562 |
Pettersen | Kari | 77895 |
Pettersen | Kari | 44678 |
Svendson | Tove |
dimonchik.com
SQL Left Join
LEFT JOIN - возвращает строки из левой таблицы(table_name1), даже если их нет в правой таблице (table_name2).
Синтаксис SQL LEFT JOIN
1 2 3 4 | SELECT column_name(s) FROM table_name1 LEFT JOIN table_name2 ON table_name1.column_name=table_name2.column_name |
- Замечание: В некоторых базах данных LEFT JOIN имеет имя LEFT OUTER JOIN.
Пример SQL LEFT JOIN
Есть таблица "Persons":
1 | Hansen | Ola | Timoteivn 10 | Sandnes |
2 | Svendson | Tove | Borgvn 23 | Sandnes |
3 | Pettersen | Kari | Storgt 20 | Stavanger |
Есть таблица "Orders":
1 | 77895 | 3 |
2 | 44678 | 3 |
3 | 22456 | 1 |
4 | 24562 | 1 |
5 | 34764 | 15 |
Теперь мы хотим получить список всех лиц и их заказов из таблицы выше.
Для этого используем такой запрос:
1 2 3 4 5 | SELECT Persons.LastName, Persons.FirstName, Orders.OrderNo FROM Persons LEFT JOIN Orders ON Persons.P_Id=Orders.P_Id ORDER BY Persons.LastName |
Результат запроса:
Hansen | Ola | 22456 |
Hansen | Ola | 24562 |
Pettersen | Kari | 77895 |
Pettersen | Kari | 44678 |
Svendson | Tove |
dimonchik.com
Команда LEFT JOIN - связывание таблиц
Команда LEFT JOIN используются для связывания таблиц по определенным полям связи.
Синтаксис
SELECT поля FROM имя_таблицы LEFT JOIN имя_связанной_таблицы ON условие_связи WHERE условие_выборкиПримеры
Все примеры будут по таблицам countries и cities, если не сказано иное.
Таблица countries:
1 | Беларусь |
2 | Россия |
3 | Украина |
Таблица cities:
1 | Минск | 1 |
2 | Витебск | 1 |
3 | Москва | 2 |
4 | Владивосток | 2 |
6 | Лондон | 0 |
Пример
В данном примере ...:
SELECT cities.id as city_id, cities.name as city_name, cities.country_id as city_country_id, countries.id as country_id, countries.name as country_name FROM cities LEFT JOIN countries ON countries.id=cities.country_idSQL запрос выберет следующие строки:
1 | Минск | 1 | 1 | Беларусь |
2 | Витебск | 1 | 1 | Беларусь |
3 | Москва | 2 | 2 | Россия |
4 | Владивосток | 2 | 2 | Россия |
6 | Лондон | 0 | NULL |
Пример
В данном примере ...:
SELECT cities.id as city_id, cities.name as city_name, cities.country_id as city_country_id, countries.id as country_id, countries.name as country_name FROM cities LEFT JOIN countries ON countries.id=cities.country_id WHERE countries.id>=2SQL запрос выберет следующие строки:
3 | Москва | 2 | 2 | Россия |
4 | Владивосток | 2 | 2 | Россия |
code.mu
Операции LEFT JOIN, RIGHT JOIN
Объединяют записи исходных таблиц при использовании в любом предложении FROM.
Синтаксис
FROM таблица1 [ LEFT | RIGHT ] JOIN таблица2ON таблица1.поле1оператор_сравнениятаблица2.поле2
Операции LEFT JOIN и RIGHT JOIN состоят из следующих элементов:
Часть |
Описание |
|
Имена таблиц, содержащих объединяемые записи. |
поле1, поле2 |
Имена связываемых полей. Поля должны относиться к одному тип данных и содержать данные одного вида. Однако имена этих полей могут быть разными. |
compopr |
Любой оператор сравнения: (=, <, >, <=, >= или <>) |
Замечания
Операция LEFT JOIN создает левое внешнее соединение. С помощью левого внешнего соединения выбираются все записи первой (левой) таблицы, даже если они не соответствуют записям во второй (правой) таблице.
Операция RIGHT JOIN создает правое внешнее соединение. С помощью правого внешнего соединения выбираются все записи второй (правой) таблицы, даже если они не соответствуют записям в первой (левой) таблице.
В следующем примере показано, как можно объединить таблицы Categories и Products по полю CategoryID. Результат запроса представляет собой список категорий, включая те, которые не содержат товаров.
SELECT CategoryName, ProductName FROM Categories LEFT JOIN Products ON Categories.CategoryID = Products.CategoryID;
В этом примере CategoryID является связующим полем, но оно не включается в результаты запроса, поскольку не указано в инструкции SELECT. Чтобы включить связующее поле в результаты запроса, укажите его имя в инструкции SELECT. В данном случае это Categories.CategoryID.
Чтобы создать запрос, результатом которого являются только те записи, для которых совпадают данные в связующих полях, воспользуйтесь операцией INNER JOIN.
-
Операции LEFT JOIN и RIGHT JOIN могут быть вложены в операцию INNER JOIN, но операция INNER JOIN не может быть вложена в операцию LEFT JOIN или RIGHT JOIN. Подробные сведения о вложении объединений можно найти в статье, посвященной операции INNER JOIN.
-
Вы можете связать несколько предложений ON. Сведения о связывании предложений см. в статье, посвященной операции INNER JOIN.
При попытке связи полей, содержащих данные типа Memo или объекты OLE, возникнет ошибка.
Left join (SQL) - пример, подробное описание, ошибки использования
В любой реальной реляционной базе данных вся информация распределяется по отдельным таблицам. Многие из таблиц имеют зафиксированные в схеме установленные связи друг с другом. Однако с помощью запросов Sql вполне реально проложить связь между данными, не заложенную в схеме. Это осуществляется путем выполнения операции соединения join, которая позволяет выстроить отношения между любым количеством таблиц и соединить даже, казалось бы, разрозненные данные.
В данной статье пойдет речь конкретно о левом внешнем соединении. Прежде чем приступить к описанию данного типа соединения, добавим в базу данных некоторые таблицы.
Подготовка необходимых таблиц
Допустим, в нашей базе данных имеется информация о людях и их недвижимом имуществе. Основная информация основывается на трех таблицах: Peoples (люди), Realty (недвижимость), Realty_peoples (таблица с отношениями, кому из людей какая недвижимость принадлежит). Предположим, в таблицах хранятся следующие данные по людям:
Чаще всего при выполнении левого соединения указывается ON, USING используют, лишь когда названия столбцов, по которым планируется выполнить соединение, совпадают.
Left join примеры использования
С помощью левого соединения мы можем посмотреть, у всех ли людей из списка Peoples имеется недвижимость. Для этого выполним следующий в left join sql пример запроса:
SELECT Peoples.*, Realty_peoples.id_realty, Realty_peoples.type FROM Peoples LEFT JOIN Realty_peoples ON Peoples.id = Realty_peoples.id_peoples; |
И получим следующий результат:
Запрос1 | ||||||
id | L_name | F_name | Middle_name | Birthday | id_realty | type |
1 | Иванова | Дарья | Борисовна | 16.07.2000 | ||
2 | Пугин | Владислав | Николаевич | 29.01.1986 | ||
3 | Евгеньин | Александр | Федерович | 30.04.1964 | 5 | Собственность |
4 | Аннина | Любовь | Павловна | 31.12.1989 | ||
5 | Герасимовская | Надежда | Павловна | 14.03.1992 | 4 | Общая долевая собственность |
6 | Герасимовский | Олег | Альбертович | 29.01.1985 | 4 | Общая долевая собственность |
7 | Сухановский | Юрий | Андреевич | 25.09.1976 | 1 | Собственность |
7 | Сухановский | Юрий | Андреевич | 25.09.1976 | 3 | Общая совместная собственность |
8 | Сухановская | Юлия | Юрьевна | 01.10.2001 | 3 | Общая совместная собственность |
Как видим, у Ивановой Дарьи, Пугина Владислава и Анниной Любови нет зарегистрированных прав на недвижимость.
А что бы мы получили, используя внутреннее соединение Inner join? Как известно, оно исключает несовпадающие строки, поэтому три человека из нашей итоговой выборки просто бы выпали:
Запрос1 | ||||||
id | L_name | F_name | Middle_name | Birthday | id_realty | type |
3 | Евгеньин | Александр | Федерович | 30.04.1964 | 5 | Собственность |
5 | Герасимовская | Надежда | Павловна | 14.03.1992 | 4 | Общая долевая собственность |
6 | Герасимовский | Олег | Альбертович | 29.01.1985 | 4 | Общая долевая собственность |
7 | Сухановский | Юрий | Андреевич | 25.09.1976 | 1 | Собственность |
7 | Сухановский | Юрий | Андреевич | 25.09.1976 | 3 | Общая совместная собственность |
8 | Сухановская | Юлия | Юрьевна | 01.10.2001 | 3 | Общая совместная собственность |
Казалось бы, второй вариант так же отвечает условиям нашей задачи. Однако, если мы дальше начнем присоединять еще и еще таблицы, три человека из результата уже безвозвратно исчезнут. Поэтому на практике при объединении множества таблиц намного чаще используются соединения Left и Right, чем Inner join.
Продолжим рассматривать с left join sql примеры. Присоединим таблицу с адресами наших объектов недвижимости:
SELECT Peoples.*, Realty_peoples.id_realty, Realty_peoples.type, Realty.address FROM Peoples LEFT JOIN Realty_peoples ON Peoples.id = Realty_peoples.id_peoples LEFT JOIN Realty ON Realty.id = Realty_peoples.id_realty |
Теперь мы получим не только вид права, но и адреса объектов недвижимости:
Запрос1 | |||||||
id | L_name | F_name | Middle_name | Birthday | id_realty | type | address |
1 | Иванова | Дарья | Борисовна | 16.07.2000 | |||
2 | Пугин | Владислав | Николаевич | 29.01.1986 | |||
3 | Евгеньин | Александр | Федерович | 30.04.1964 | 5 | Собственность | г. Архангельск, пл. Терехина, д. 89, кв. 13 |
4 | Аннина | Любовь | Павловна | 31.12.1989 | |||
5 | Герасимовская | Надежда | Павловна | 14.03.1992 | 4 | Общая долевая собственность | Архангельская область, г. Новодвинск, ул. Пролетарская, д. 16, кв. 137 |
6 | Герасимовский | Олег | Альбертович | 29.01.1985 | 4 | Общая долевая собственность | Архангельская область, г. Новодвинск, ул. Пролетарская, д. 16, кв. 137 |
7 | Сухановский | Юрий | Андреевич | 25.09.1976 | 3 | Общая совместная собственность | Архангельская область, г. Северодвинск, ул. Ленина, д. 134, кв. 85 |
7 | Сухановский | Юрий | Андреевич | 25.09.1976 | 1 | Собственность | г. Архангельск, ул. Воронина, д. 7, кв.6 |
8 | Сухановская | Юлия | Юрьевна | 01.10.2001 | 3 | Общая совместная собственность | Архангельская область, г. Северодвинск, ул. Ленина, д. 134, кв. 85 |
Left join типичные ошибки использования: неверный порядок таблиц
Основных ошибок, допускаемых при левом внешнем соединении таблиц, две:
- Неверно выбран порядок таблиц, из за которого были потеряны данные.
- Ошибки при использовании Where в запросе с объединенными таблицами.
Рассмотрим ошибку первую. Перед решением любой задачи стоит четко понимать, что именно мы хотим получить в итоге. В рассматриваемом выше примере мы вывели всех до единого людей, но абсолютно потеряли сведения об объекте под номером 2, у которого собственника не нашлось.
Если бы мы переставили таблицы в запросе местами, и начали бы с «… From Realty left join Peoples…» то ни одну недвижимость мы бы не потеряли, чего не скажешь о людях.
Однако не стоит, испугавшись левого соединения, переходить на полное внешнее, которое включит в результате и совпадающие, и не совпадающие строки.
Ведь объем выборок зачастую очень велик, и лишние данные реально ни к чему. Главное разобраться, что вы хотите в итоге получить: всех людей со списком имеющихся у них недвижимости, либо список всей недвижимости с их собственниками (если есть).
Left join типичные ошибки использования: правильность запроса при задании условий в Where
Вторая ошибка также связана с потерей данных, причем не всегда сразу очевидной.
Вернемся к запросу, когда мы с помощью левого соединения получили данные по всем людям и имеющейся у них недвижимости. Вспомните следующий с применением left join sql пример:
FROM Peoples LEFT JOIN Realty_peoples ON Peoples.id = Realty_peoples.id_peoples; |
Допустим, мы хотим уточнить запрос и не выводить данные, где тип права – «Собственность». Если мы просто допишем, применяя left join sql, пример следующим условием:
...
Where type <> "Собственность" |
то потеряем данные по людям, у которых нет никакой недвижимости, ведь пустое значение Null не сравнивается таким образом:
Запрос1 | ||||||
id | L_name | F_name | Middle_name | Birthday | id_realty | type |
5 | Герасимовская | Надежда | Павловна | 14.03.1992 | 4 | Общая долевая собственность |
6 | Герасимовский | Олег | Альбертович | 29.01.1985 | 4 | Общая долевая собственность |
7 | Сухановский | Юрий | Андреевич | 25.09.1976 | 3 | Общая совместная собственность |
8 | Сухановская | Юлия | Юрьевна | 01.10.2001 | 3 | Общая совместная собственность |
Чтобы предупредить появление ошибок по этой причине, лучше всего задать условие отбора сразу при соединении. Предлагаем рассмотреть следующий с left join sql пример.
SELECT Peoples.*, Realty_peoples.id_realty, Realty_peoples.type FROM Peoples LEFT JOIN Realty_peoples ON (Peoples.id = Realty_peoples.id_peoples AND type <> "Собственность") |
Результат будет следующим:
Запрос1 | ||||||
id | L_name | F_name | Middle_name | Birthday | id_realty | type |
1 | Иванова | Дарья | Борисовна | 16.07.2000 | ||
2 | Пугин | Владислав | Николаевич | 29.01.1986 | ||
3 | Евгеньин | Александр | Федерович | 30.04.1964 | ||
4 | Аннина | Любовь | Павловна | 31.12.1989 | ||
5 | Герасимовская | Надежда | Павловна | 14.03.1992 | 4 | Общая долевая собственность |
6 | Герасимовский | Олег | Альбертович | 29.01.1985 | 4 | Общая долевая собственность |
7 | Сухановский | Юрий | Андреевич | 25.09.1976 | 3 | Общая совместная собственность |
8 | Сухановская | Юлия | Юрьевна | 01.10.2001 | 3 | Общая совместная собственность |
Таким образом, выполнив простой с left join sql пример, мы получили список из всех людей, выведя дополнительно, у кого из них недвижимость в долевой/совместной собственности.
В качестве вывода хотелось бы еще раз подчеркнуть, что к выборке любой информации из базы данных нужно отнестись ответственно. Многие нюансы открыл перед нами с применением left join sql простой пример, объяснение которым одно – перед тем как приступить к составлению даже элементарного запроса, необходимо тщательно разобраться, что именно мы хотим получить в итоге. Удачи!
autogear.ru
JOIN MySQL Объединение таблиц, варианты
Выборку будем делать из двух таблицid name id name-- ---- -- ----1 Яблоко 1 Тыква2 Ананас 2 Яблоко3 Банан 3 Дыня4 Груша 4 БананINNER JOIN
SELECT * FROM tableA INNER JOIN tableB ON tableA.name = tableB.nameid name id name-- ---- -- ----1 Яблоко 2 Яблоко3 Банан 4 Банан
Выбираются только те записи, которые совпадают в обоих таблицах.---------------------------------------------------------------
LEFT OUTER JOIN
SELECT * FROM tableA LEFT OUTER JOIN tableB ON tableA.name = tableB.nameid name id name-- ---- -- ----1 Яблоко 2 Яблоко2 Ананас null null3 Банан 4 Банан4 Груша null null
Все записи из таблицы А и совпавшие записи из таблицы B. Если совпадение отсутствует, то правая сторона будет содержать значение null, т.к. управляющая таблица левая, об этом говорит ключевое слово LEFT.
---------------------------------------------------------------
LEFT OUTER JOIN WHERE B id IS NULL
SELECT * FROM tableA LEFT OUTER JOIN tableB ON tableA.name = tableB.name WHERE tableB.id IS nullid name id name-- ---- -- ----2 Ананас null null4 Груша null null
Уникальные в А. Записи из таблицы А, которые не совпадают с записями из таблицы В.
Если немного изменить запрос, то получим уникальные записи из таблицы B.
SELECT * FROM tableA RIGHT OUTER JOIN tableB ON tableA.name = tableB.name WHERE tableA.id IS nullid name id name-- ---- -- ----null null 1 Тыкваnull null 3 Дыня
---------------------------------------------------------------
FULL OUTER JOIN
SELECT * FROM tableA FULL OUTER JOIN tableB ON tableA.name = tableB.nameid name id name-- ---- -- ----1 Яблоко 2 Яблоко2 Ананас null null3 Банан 4 Банан4 Груша null nullnull null 1 Тыква null null 3 Дыня
Выбираем все записи в обоих таблицах с совпадением записей с обоих сторон, где это возможно. Если совпадения нет, то пропускающая сторона будет содержать значение null.---------------------------------------------------------------
FULL OUTER JOIN WHERE A or B id IS NULL
SELECT * FROM tableA FULL OUTER JOIN tableB ON tableA.name = tableB.name WHERE tableA.id IS null OR tableB.id IS nullid name id name-- ---- -- ----2 Ананас null null4 Груша null nullnull null 1 Тыкваnull null 3 Дыня
Уникальные в обоих.Статья основана на материалах: http://www.codinghorror.com/blog/2007/10/a-visual-explanation-of-sql-joins.html
tftf.ru
MySQL и JOINы / Хабр
Поводом для написания данной статьи послужили некоторые дебаты в одной из групп linkedin, связанной с MySQL, а также общение с коллегами и хабролюдьми :-)В данной статье хотел написать что такое вообще JOINы в MySQL и как можно оптимизировать запросы с ними.
Что такое JOINы в MySQL
В MySQL термин JOIN используется гораздо шире, чем можно было бы предположить. Здесь JOINом может называться не только запрос объединяющий результаты из нескольких таблиц, но и запрос к одной таблице, например, SELECT по одной таблице — это тоже джоин.
Все потому, что алгоритм выполнения джоинов в MySQL реализован с использованием вложенных циклов. Т.е. каждый последующий JOIN это дополнительный вложенный цикл. Чтобы выполнить запрос и вернуть все записи удовлетворяющие условию MySQL выполняет цикл и пробегает по записям первой таблицы параллельно проверяя соответствия условиям описанных в теле запроса, когда находятся записи, удовлетворяющие условиям — во вложенном цикле по второй таблице ищутся записи соответствующие первым и удовлетворяющие условиям проверки и т.д.
Прмер обычного запроса с INNER JOIN
SELECT * FROM Table1 INNER JOIN Table2 ON P1(Table1,Table2)INNER JOIN Table3 ON P2(Table2,Table3)WHERE P(Table1,Table2,Table3).* This source code was highlighted with Source Code Highlighter.где Р — условия склейки таблиц и фильтры в WHERE условии.
Можно представить такой псевдокод выполнения такого запроса.
FOR each row t1 in Table1 { IF(P(t1)) { FOR each row t2 in Table2 { IF(P(t2)) { FOR each row t3 in Table3 { IF P(t3) { t:=t1||t2||t3; OUTPUT t; } } } } } }* This source code was highlighted with Source Code Highlighter.где конструкция t1||t2||t3 означает конкатенацию столбцов из разных таблиц.
Если в запросе встречаются OUTER JOINs, например, LEFT OUTER JOIN
SELECT * FROM Table1 LEFT JOIN ( Table2 LEFT JOIN Table3 ON P2(Table2,Table3) ) ON P1(Table1,Table2)WHERE P(Table1,Table2,Tabke3)* This source code was highlighted with Source Code Highlighter.то алгоритм выполнения этого запроса MySQL будет выглядеть как-то так
FOR each row t1 in T1 { BOOL f1:=FALSE; FOR each row t2 in T2 such that P1(t1,t2) { BOOL f2:=FALSE; FOR each row t3 in T3 such that P2(t2,t3) { IF P(t1,t2,t3) { t:=t1||t2||t3; OUTPUT t; } f2=TRUE; f1=TRUE; } IF (!f2) { IF P(t1,t2,NULL) { t:=t1||t2||NULL; OUTPUT t; } f1=TRUE; } } IF (!f1) { IF P(t1,NULL,NULL) { t:=t1||NULL||NULL; OUTPUT t; } } }* This source code was highlighted with Source Code Highlighter.Более подробно почитать об этом можно здесь — dev.mysql.com/doc/refman/5.1/en/nested-joins.html
Итак, как мы видим, JOINы это просто группа вложенных циклов. Так почему же в MySQL и UNION и SELECT и запросы с SUBQUERY тоже джоины?
MySQL оптимизатор старается приводить запросы к тому виду к которому ему удобней обрабатывать и выполнять запросы по стандартной схеме.
С SELECT все понятно — просто цикл без вложенных циклов. Все UNION выполняются как отдельные запросы и результаты складываются во временную таблицу, и потом MySQL работает уже с этой таблицей, т.е. проходясь циклом по записям в ней. С Subquery та же история.
Приводя все к одному шаблону, например, МySQL переписывает все RIGHT JOIN запросы на LEFT JOIN эквиваленты.
Но стратегия выполнения запросов через вложенные циклы накладывает некоторые ограничения, например, в связи с такой схемой MySQL не поддерживает выполнение FULL OUTER JOIN запросов.
Но результат такого запроса можно получить с помощью UNION двух запросов на LEFT JOIN и на RIGHT JOIN Пример самого запроса можно посмотреть по ссылке на вики.
План выполнения JOIN запросов
В отличии от других СУРБД MySQL не генерирует байткод для выполнения запроса, вместо этого MySQL генерирует список инструкций в древовидной форме, которых придерживается engine выполнения запроса выполняя запрос. Это дерево имеет следующий вид и имеет название «left-deep tree»
В отличии от сбалансированных деревьев (Bushy plan), которые применяются в других СУБД (например Oracle)
JOIN оптимизация
Теперь перейдем к самому интересному — к оптимизации джоинов. MySQL оптимизатор, а именно та его часть, которая отвечает за оптимизацию JOIN-ов выбирает порядок в котором будет производиться склейка имеющихся таблиц, т.к. можно получить один и тот же результат (датасет) при различном порядке таблиц в склейке. MySQL оптимизатор оценивает стоимость различных планов и выбирает с наименьшей стоимостью. Единицей оценки является операция единичного чтения страницы данных размером в 4 килобайта из произвольного места на диске.
Для выбранного плана можно узнать стоимость путем выполнения команды
SHOW SESSION STATUS LIKE 'Last_query_cost';
после выполнения интересующего нас запроса. Переменная Last_query_cost является сессионной переменной. Описание переменной Last_query_cost в MySQL документации можно найти здесь — dev.mysql.com/doc/refman/5.1/en/server-status-variables.html#option_mysqld_Last_query_cost
Оценка основана на статистике: количество страниц памяти, занимаемое таблицей и/или индексами для этой таблицы, cardinality (число уникальных значений) индексов, длинна записей и индексов, их распределение и т.д. Во время своей оценки оптимизатор не рассчитывает на то, что какие-то части попадут в кеш, оптимизатор предполагает, что каждая операция чтения это обращение к диску.
Иногда анализатор-оптимизатор не может проанализировать все возможные планы выполнения и выбирает неправильный. Например, если у нас INNER JOIN по 3м таблицам, то возможных вариантов у анализатора — 3! = 6, а если у нас склейка по 10 таблицам, то тут возможных вариантов уже 10! = 3628800… MySQL не может проанализировать столько вариантов, поэтому в таком случае он использует алгоритм "жадного" поиска.
И вот как раз для решения данной проблемы, нам может пригодиться конструкция STRAIGHT_JOIN. На самом деле я противник подобных хаков как FORCE INDEX и STRAIGH_JOIN, точней против их бездумного использования везде где только можно и нельзя. В данном случае — можно :-) Выяснив (либо экспериментальным путем делая запросы с STRAIGH_JOIN и оценивая Last_query_cost, либо эмпирическим путем) нужный порядок джоинов можно переписать запрос с таблицами в соответствующем порядке и добавить STRAIGH_JOIN к данному запросу, таким образом мы сразу убьем двух зайцев — определим правильный план выполнения запроса (это главный заяц) и сэкономим время на стадии «Statistic» (Все стадии выполнения запроса можно посмотреть установив профайлинг запросов командой SET PROFILING =1, я описывал это в своей предыдущей статье по теме профайлинга запросов в MySQL )
Но не стоит применять этот хак ко всем запросам, расчитывая произвести оптимизацию на спичках и сэкономить время на составление плана выполнения запроса оптимизатором и добавлять STRAIGH_JOIN ко всем запросам с джоинами, т.к. данные меняются и склейка, которая оптимальна сейчас может перестать быть оптимальной со временем, и тогда запросы начнуть очень сильно лагать.
Также, как уже говорилось выше, результаты джоинов помещаются во временные таблицы, поэтому зачастую уместно применять «derived table» в котором мы накладываем все необходимые нам условия на выборку, а также указываем LIMIT и порядок сортировки. В данном случае мы избавимся от избыточности данных во временной таблице, а также проведем сортировку на раннем этапе (по результату одной выборки, а не финальной склейки, что уменьшит размеры записей которые будут сортироваться).
Стандартный пример подхода описанного выше. Простая выборка для отношения много к многим: новости и теги к ним.
SELECT t.tid, t.description, n.nid, n.title, n.extract, n.modtimeFROM ( SELECT n.nid FROM news n WHERE n.type = 1321 AND n.published = 1 AND status = 1 ORDER BY n.modtime DESC LIMIT 200 ) as newsINNER JOIN news n ON n.nid = news.nidINNER JOIN news_tag nt ON n.nid = nt.nidINNER JOIN tags t ON nt.tid = t.tid* This source code was highlighted with Source Code Highlighter.Ну и на последок небольшая задачка, которую я иногда задаю на собеседованиях :-)
Есть новостной блоггерный сайт. Есть такие сущности как новости и комментарии к ним.
Задача — нужно написать запрос, который выводит список из 10 новостей определенного типа (задается пользователем) отсортированные по времени издания в хронологическом порядке, а также к каждой из этих новостей показать не более 10 последних коментариев, т.е. если коментариев больше — показываем только последние 10.
Все нужно сделать одним запросом. Да, это, может, и не самый лучший способ, и вы вольны предложить другое решение :-)
habr.com