I've got bookings (bookings
) in my database. A booking can have 0 to n flight services (flight_services
) and 0 to n hotel services (hotel_services
). A user on my website can filter the bookings by setting where conditions on each of these tables.
When SELECT
ing, only bookings that have at least one flight service or at least one hotel service should be returned. Furthermore, there's a flight_pivot_table
and a hotel_pivot_table
and only the services should be considered that have a fix id (here 82
) in those pivot tables.
The query:
select `bookings`.*
from `bookings`
left join (
select `flight_services`.*
from `flight_services`
inner join `flight_pivot_table`
on `flight_services`.`id` = `flight_pivot_table`.`flight_service_id`
where `flight_pivot_table`.`some_id` = 82
) as `flight_services`
on `bookings`.`id` = `flight_services`.`booking_id`
left join (
select `hotel_services`.*
from `hotel_services`
inner join `hotel_pivot_table`
on `hotel_services`.`id` = `hotel_pivot_table`.`hotel_service_id`
where `hotel_pivot_table`.`some_id` = 82
) as `hotel_services`
on `bookings`.`id` = `hotel_services`.`booking_id`
where (
flight_services.id is not null or
hotel_services.id is not null
)
group by `bookings`.`id`
Unfortunately, this is extremely slow, although all indexes are used. With the data I've got, this query takes about 300 ms to execute. Here's the output of EXPLAIN
:
id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
---|---|---|---|---|---|---|---|---|---|---|---|
1 | SIMPLE | bookings | index | PRIMARY | PRIMARY | 4 | 35173 | 100 | |||
1 | SIMPLE | flight_services | ref | PRIMARY,flight_services_uq | flight_services_uq | 4 | my_db.bookings.id | 2 | 100 | Using index | |
1 | SIMPLE | flight_pivot_table | eq_ref | PRIMARY | PRIMARY | 8 | const,my_db.flight_services.id | 1 | 100 | Using index | |
1 | SIMPLE | hotel_services | ref | PRIMARY,hotel_services_uq | hotel_services_uq | 4 | my_db.bookings.id | 1 | 100 | Using where; Using index | |
1 | SIMPLE | hotel_pivot_table | eq_ref | PRIMARY | PRIMARY | 8 | const,my_db.hotel_services.id | 1 | 100 | Using index |
One of the following actions reduces the time to about 3 ms but obviously break the functionality:
- Remove the
INNER JOIN
from one or both of the sub queries. - Remove the
WHERE
conditions. - Replace the
or
withand
in theWHERE
conditions.
Notes:
- As it should be possible to add where conditions for
flight_services
andhotel_services
, the aliases given for the left join sub-queries match the table names. - I use
GROUP BY
because every booking should returned only once, of course.
How can I accelerate this?
where exists
instead of the joins? Also, you shouldn'tselect flight_services.*
when all you need isbooking_id
.WHERE EXISTS
would take away the possibility to setWHERE
conditions on those tables. The user should be able to filter the bookings by flight and hotel services.