简体   繁体   中英

how to optimize the following mysql query

I have a trouble in the mysql query . the query is following.

SELECT *  
FROM group 
WHERE  (level IN (3,4,5,6) AND  last_time BETWEEN  0 AND 3) 
OR     (level IN (4,5,6,7) AND  last_time BETWEEN  0 AND 6);

how can I optimize the query to which maybe can drop the OR word . thanks.

also, the query may be extended like follow .

SELECT *  
    FROM group 
    WHERE  (level IN (3,4,5,6) AND  last_time BETWEEN  0 AND 3) 
    OR     (level IN (4,5,6,7) AND  last_time BETWEEN  0 AND 6)
    OR     ... ;

can someone explain about the Train of thought of The solution, thanks very much.

The query looks fine as is. Sometimes it is the case that you want one or another condition met. It is the optimizer's job to find the best way to execute the query.

You can try help the optimizer, but that shouldn't actually be necessary, so do this only if you really have performance issues.

Your query could be written as

SELECT *  
FROM group 
WHERE  (level = 3 AND  last_time BETWEEN  0 AND 3) 
OR     (level IN (4,5,6,7) AND  last_time BETWEEN  0 AND 6);

because of overlapping criteria, but I doubt that would help the optimizer much.

You could also do:

SELECT *  
FROM group 
WHERE Level in (3,4,5,6,7) 
AND last_time BETWEEN 0 AND 6
AND 
(
  (level IN (3,4,5,6) AND  last_time BETWEEN  0 AND 3) 
OR
  (level IN (4,5,6,7) AND  last_time BETWEEN  0 AND 6)
);

So you'd list all values in question first (there is no condition that requires a level not in 3-7, and there is no condition requiring last_time outside 0-6). Only then list the single conditions. This may or may not help the optimizer.

In any way you should have a composite index on level + last_time . Whether using this index or doing a full table scan is faster depends on the data, but you should offer such index anyway.

Often the quickest solution is the split it to multiple UNIONed queries. Then each smaller query can use indexes efficiently.

SELECT *  
FROM group 
WHERE  (level IN (3,4,5,6) AND  last_time BETWEEN  0 AND 3) 
UNION
SELECT *  
FROM group 
WHERE  (level IN (4,5,6,7) AND  last_time BETWEEN  0 AND 6);

Let's check if MySQL is smart enough to optimize the OR:

mysql> explain splain select * from seqid in (1,2,3) or id in (4,5,6);
+----+-------------+-------+------------+-------+---------------+---------+---------+------+------+----------+-----------------------+
| id | select_type | table | partitions | type  | possible_keys | key     | key_len | ref  | rows | filtered | Extra                 |
+----+-------------+-------+------------+-------+---------------+---------+---------+------+------+----------+-----------------------+
|  1 | SIMPLE      | seq   | NULL       | range | PRIMARY       | PRIMARY | 4       | NULL |    6 |   100.00 | Using index condition |
+----+-------------+-------+------------+-------+---------------+---------+---------+------+------+----------+-----------------------+

"seq" is a table which contains 1M ints.

Well, MySQL optimizes the OR just fine. It uses the index just as you'd expect. There is no need to tweak the query further.

I suggest you check EXPLAIN of your query to verify your MySQL optimizes it properly.

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