简体   繁体   中英

Slow query with OR in where clause

Please advise how to improve this slow query.

SELECT response.`reasonid`
FROM response 
    INNER JOIN ACTION ON action.actionid = response.actionid 
WHERE 
    response.respdate BETWEEN 20160305 
    AND 20160905 
    AND 
    (
        (
         response.reasonid = 'Prospect Call' 
         AND response.typeid = '0'
         AND action.typeid = '9'
        ) 
    OR 
        (
         response.typeid = '1000'  
         AND action.typeid = '1'
        )
    ) 

There are indexes on:

response.actionid / response.reasonid / response.typeid / action.typeid / response.respdate

Explain results:

 table   type   possible_keys                   key           key_len  ref               rows   Extra

ACTION   range  PRIMARY,idx_actiontypeid    idx_actiontypeid    5      \N               310617  Using where; Using index
response ref    idx_respdate2,idx_actionid, idx_actionid        5      ACTION.actionid    1         Using where
            idx_reasonid,idx_resptypeid

try this query added some index columns into join

SELECT response.`reasonid`
FROM response 
    INNER JOIN ACTION ON action.actionid = response.actionid   and response.typeid in( '1000','0') and action.typeid in('0','1')
WHERE 
    response.respdate BETWEEN 20160305 
    AND 20160905 
    AND 
    (
        (
         response.reasonid = 'Prospect Call' 
         AND response.typeid = '0'
         AND action.typeid = '9'
        ) 
    OR 
        (
         response.typeid = '1000'  
         AND action.typeid = '1'
        )
    )

Try that: Reduce the size of the table down to only what you need to use:

select a.* 
from (
      SELECT response.`reasonid`
      FROM response 
      WHERE response.respdate BETWEEN 20160305 AND 20160905 
      ) a
INNER JOIN ACTION ON action.actionid = a.actionid
WHERE (
     response.reasonid = 'Prospect Call' 
     AND response.typeid = '0'
     AND action.typeid = '9'
    ) 
OR 
    (
     response.typeid = '1000'  
     AND action.typeid = '1'
    )

Please try to specify the dates in your query as they are in the database:

SELECT response.`reasonid`
FROM response 
    INNER JOIN ACTION ON action.actionid = response.actionid 
WHERE 
    response.respdate BETWEEN "2016-03-05" 
    AND "2016-09-05" 
    AND 
    (
        (
         response.reasonid = 'Prospect Call' 
         AND response.typeid = '0'
         AND action.typeid = '9'
        ) 
    OR 
        (
         response.typeid = '1000'  
         AND action.typeid = '1'
        )
    ) 

and check if this speeds up your query. If you write it as numeric value (20160305), the database has to do an implicit typecast on every line before comparing it, which might lead to slower performance.

Your query should not have individual indexes on it, but a composite or even covering indexes. Which I am surprised nobody else commented on. I offer the following suggestion for indexes

table index response ( typeid, respdate, reasoned, actionid ) action ( actionid, typeid )

Then I adjusted the query to use a UNION instead of an OR

select distinct
      r.reasonid
   from
      response r join action a
         on r.actionid = a.actionid
         AND a.typeid = 9
   where
          r.typeid = 0
      and r.respdate between 20160305 and 20160905
      and r.reasonid = 'Prospect Call'
union
select 
      r.reasonid
   from
      response r join action a
         on r.actionid = a.actionid
         AND a.typeid = 1
   where
          r.typeid = 1000
      and r.respdate between 20160305 and 20160905

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM