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 SELECTing, 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 JOINfrom one or both of the sub queries. - Remove the
WHEREconditions. - Replace the
orwithandin theWHEREconditions.
Notes:
- As it should be possible to add where conditions for
flight_servicesandhotel_services, the aliases given for the left join sub-queries match the table names. - I use
GROUP BYbecause every booking should returned only once, of course.
How can I accelerate this?
where existsinstead of the joins? Also, you shouldn'tselect flight_services.*when all you need isbooking_id.WHERE EXISTSwould take away the possibility to setWHEREconditions on those tables. The user should be able to filter the bookings by flight and hotel services.