我需要多列索引吗?

时间:2011-05-30 15:20:51

标签: mysql

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的索引,单独删除。如何加快查询速度?

2 个答案:

答案 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答案。

在任何情况下,我认为多列索引对您没有帮助,因为您的搜索表达式中有'%'个符号。这样,只能使用多列索引中的第一列,其余的仍然需要索引扫描或全表扫描。