Mysql query performance multiple and or conditions
I have this query in mysql with very poor performance.
select `notifiables`.`notification_id`
from `notifiables`
where `notifiables`.`notification_type` in (2, 3, 4)
and ( ( `notifiables`.`notifiable_type` = 16
and `notifiables`.`notifiable_id` = 53642)
or ( `notifiables`.`notifiable_type` = 17
and `notifiables`.`notifiable_id` = 26358)
or ( `notifiables`.`notifiable_type` = 18
and `notifiables`.`notifiable_id` = 2654))
order by `notifiables`.`id` desc limit 20
Is this query can be optimized in any way. Please help This table has 2M rows. and taking upto 1-4 seconds in searching
Updated indexes and Explain select
Possible solutions:
-
Turning
OR
intoUNION
(see @hongnhat) -
Row constructors (see @Akina)
-
Adding
AND notifiable_type IN (16, 17, 18)
-
Index hint. I dislike this because it often does more harm than good. However, the Optimizer is erroneously picking the
PRIMARY KEY(id)
(because of theORDER BY
instead of some filter which, according to the Cardinality should be very good. -
INDEX(notification_type, notifiable_type, notifiable_id, id, notification_id)
-- This is "covering", which can help because the index is probably 'smaller' than the dataset. When adding this index,DROP
your currentINDEX(notification_type)
since it distracts the Optimizer. -
VIEW
is very unlikely to help.
More
Give this a try: Add this to the beginning of the WHERE
WHERE notifiable_id IN ( 53642, 26358, 2654 )
AND ... (all of what you have now)
And be sure to have an INDEX
starting with notifiable_id
. (I don't see one currently.)
Use the next syntax:
SELECT notification_id
FROM notifiables
WHERE notification_type IN (2, 3, 4)
AND (notifiable_type, notifiable_id) IN ( (16, 53642), (17, 26358), (18, 2654) )
ORDER BY id DESC LIMIT 20
Create index by (notification_type, notifiable_type, notifiable_id)
or (notifiable_type, notifiable_id, notification_type)
(depends on separate conditions selectivity).
Or create covering index ((notification_type, notifiable_type, notifiable_id, notification_id)
or (notifiable_type, notifiable_id, notification_type, notification_id)
).