EXPLAIN SELECT *
FROM (
`phppos_items`
)
WHERE (
name LIKE 'AB10LA2%'
OR item_number LIKE 'AB10LA2%'
OR category LIKE 'AB10LA2%'
)
AND deleted =0
ORDER BY `name` ASC
LIMIT 16
+----+-------------+--------------+-------+-----------------------------------+------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+--------------+-------+-----------------------------------+------+---------+------+------+-------------+
| 1 | SIMPLE | phppos_items | index | item_number,name,category,deleted | name | 257 | NULL | 32 | Using where |
+----+-------------+--------------+-------+-----------------------------------+------+---------+------+------+-------------+
此查询需要9秒才能运行(该表有100万+行)。
我有一个关于item_number,name,category的索引,单独删除。如何加快查询速度?
答案 0 :(得分:3)
最好我知道,MySQL不知道如何执行位图或索引扫描。但是你可以将它重写为三个查询的联合,以强制它做这样的事情,如果你在每个字段上有一个索引。如果是这样,这将非常快:
select *
from (
select * from (
select *
from phppos_items
where name like 'AB10LA2%' and deleted = 0
order by `name` limit 16
) t
union
select * from (
select *
from phppos_items
where item_number like 'AB10LA2%' and deleted = 0
order by `name` limit 16
) t
union
select * from (
select *
from phppos_items
where category like 'AB10LA2%' and deleted = 0
order by `name` limit 16
) t
) as top rows
order by `name` limit 16
答案 1 :(得分:1)
OR
运算符可能是执行计划的毒药。您可以尝试使用等效OR
替换UNION
子句来重新表达您的查询:
SELECT *
FROM (
SELECT * FROM `phppos_items`
WHERE name LIKE 'AB10LA2%'
UNION
SELECT * FROM `phppos_items`
WHERE item_number LIKE 'AB10LA2%'
UNION
SELECT * FROM `phppos_items`
WHERE category LIKE 'AB10LA2%'
)
WHERE deleted =0
ORDER BY `name` ASC
LIMIT 16
这将允许MySQL在将UNION
运算符应用于每个子查询的结果之前并行运行多个子查询。我知道这对Oracle有很大帮助。也许MySQL可以做类似的事情?注意:我假设LIKE 'AB10LA2%'
是一个非常有选择性的过滤器。否则,由于延迟排序和限制执行计划,这可能无法改善。有关更一般的方法,请参阅Denis's答案。
在任何情况下,我认为多列索引对您没有帮助,因为您的搜索表达式中有'%'
个符号。这样,只能使用多列索引中的第一列,其余的仍然需要索引扫描或全表扫描。