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

attached indexs of the table

Updated indexes and Explain select

updated indexes

explain select


Possible solutions:

  • Turning OR into UNION (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 the ORDER 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 current INDEX(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)).