У меня довольно сложный запрос, который я действительно хочу структурировать, используя LEFT JOIN без каких-либо операторов UNION, но он выполняется слишком медленно.Даже когда я упрощаю его, чтобы изолировать проблему, я не понимаю, почему один запрос должен выполняться намного быстрее.
Я использую версию MySQL: 5.6.36-82.1-log
Можно ли как-нибудь оптимизировать этот запрос без использования UNION?
select SQL_NO_CACHE distinct `locations`.* from `locations`
left join `location_address` on `location_address`.`location_id` = `locations`.`id`
left join `addresses` on `location_address`.`address_id` = `addresses`.`id`
left join `cities` on `addresses`.`city_id` = `cities`.`id`
where `cities`.`name` = 'New York'
or `locations`.`description` like '%New York%'
Время выполнения: 13,422 секунды
Когда я разделяю это и использую UNION, это намного быстрее:
(select SQL_NO_CACHE distinct `locations`.* from `locations`
left join `location_address` on `location_address`.`location_id` = `locations`.`id`
left join `addresses` on `location_address`.`address_id` = `addresses`.`id`
left join `cities` on `addresses`.`city_id` = `cities`.`id`
where `cities`.`name` = 'New York')
union
(select distinct `locations`.* from `locations`
left join `location_address` on `location_address`.`location_id` = `locations`.`id`
left join `addresses` on `location_address`.`address_id` = `addresses`.`id`
left join `cities` on `addresses`.`city_id` = `cities`.`id`
where `locations`.`description` like '%New York%')
Время выполнения: 0,219 секунд
Если я изменю «левое соединение» на (внутреннее) «соединение», это будет намного быстрее (но пропускает местоположения без адреса):
select SQL_NO_CACHE distinct `locations`.* from `locations`
join `location_address` on `location_address`.`location_id` = `locations`.`id`
join `addresses` on `location_address`.`address_id` = `addresses`.`id`
join `cities` on `addresses`.`city_id` = `cities`.`id`
where `cities`.`name` = 'New York'
or `locations`.`description` like '%New York%'
Время выполнения: 0,219 секунды
Кроме того, добавление условия cities
. name
в LEFT JOIN не помогает:
select SQL_NO_CACHE distinct `locations`.* from `locations`
left join `location_address` on `location_address`.`location_id` = `locations`.`id`
left join `addresses` on `location_address`.`address_id` = `addresses`.`id`
left join `cities` on `addresses`.`city_id` = `cities`.`id` AND `cities`.`name` = 'New York'
where `cities`.`name` = 'New York'
or `locations`.`description` like '%New York%'
Время выполнения: 13,812 секунды
Записи в каждой таблице:
- местоположения: ~ 5000 строк
- location_address: ~ 4900 строк (~ 100 местоположений имеют 2 записи, ~ 200 местоположений имеют 0)
- адреса: ~ 5500 строк (~ 600 адресов связаны с другими таблицами)
- цитирует: ~ 30000 строк (с использованием полной базы данных городов США)
Поле id
в каждой таблице является первичным индексом, а cities
. name
также является индексом.locations
. index
- это длинное текстовое поле.
Вот несколько примеров структуры и данных:
местоположений
+----+----------------------+
| id | description |
+----+---------------------+
| 1 | Somewhere out there |
+----+----------------------+
| 2 | In New York |
+----+----------------------+
| 3 | Elsewhere |
+----+----------------------+
адрес_адреса
+----+-------------+------------+
| id | location_id | address_id |
+----+-------------+------------+
| 1 | 1 | 1 |
+----+-------------+------------+
| 2 | 1 | 2 |
+----+-------------+------------+
| 3 | 3 | 3 |
+----+-------------+------------+
адреса
+----+---------+
| id | city_id |
+----+---------+
| 1 | 1 |
+----+---------+
| 2 | 2 |
+----+---------+
| 3 | 2 |
+----+---------+
города
+----+-----------+
| id | name |
+----+-----------+
| 1 | New York |
+----+-----------+
| 2 | Chicago |
+----+-----------+
| 3 | Houston |
+----+-----------+
Я очень хочучтобы избежать использования UNION, поскольку у меня много условных фильтров, и иногда мне приходится пропускать часть объединения, поскольку я хочу использовать только местоположения с адресами.Использование UNION также значительно усложнило мой код построения запросов.Я также хотел бы избежать подзапросов.