Mysql查询不使用索引

时间:2015-02-12 10:28:25

标签: mysql sql

我在mysql中有一个非常大的订单表(大约120k行,并且正在增长),我在mysql-slow日志中看到一些查询花了太长时间。 此外,由于这个原因,我在服务器中有一些峰值负载。

其中一个问题:

SELECT [list of fields] 
FROM   orders o 
       LEFT JOIN orders_total ot 
              ON ( o.orders_id = ot.orders_id ) 
       LEFT JOIN orders_status s 
              ON o.orders_status = s.orders_status_id 
WHERE  s.language_id = '3' 
       AND ot.class = 'ot_total' 
       AND ( o.customers_name LIKE '%126627%' 
              OR o.customers_company LIKE '%126627%' 
              OR o.orders_id LIKE '%126627%' 
              OR o.delivery_name LIKE '%126627%' 
              OR o.delivery_company LIKE '%126627%' 
              OR o.customers_email_address LIKE '%126627%' 
              OR o.customers_telephone LIKE '%126627%' 
              OR o.billing_name LIKE '%126627%' 
              OR o.billing_company LIKE '%126627%' 
              OR o.billing_nif LIKE '%126627%' ) 
ORDER  BY o.orders_id DESC 
LIMIT  0, 20; 

解释了这些查询并得到了这个:

id  select_type table   type    possible_keys   key key_len ref rows    Extra
1   SIMPLE  o   index   PRIMARY,order_status    PRIMARY 4   NULL    127733  Using where
1   SIMPLE  s   eq_ref  PRIMARY PRIMARY 8   o.orders_status,const   1   Using where
1   SIMPLE  ot  ref idx_orders_total_orders_id  idx_orders_total_orders_id  4   o.orders_id 4   Using where

正如您所看到的,查询将遍历表顺序的所有记录。

表格顺序为orders_status索引。

怎么能避免这个? 它是一个MyISAM表,使其成为InnoDB将解决此峰值负载?

由于

1 个答案:

答案 0 :(得分:0)

这可能无法修复您的查询,但left join应该是内部join。无论如何,它们都被where子句变成了内连接。

查看此版本查询的解释:

SELECT [list of fields] 
FROM orders o JOIN
     orders_total ot 
     ONo.orders_id = ot.orders_id JOIN
     orders_status s 
     ON o.orders_status = s.orders_status_id 
WHERE s.language_id = '3' AND ot.class = 'ot_total' AND
      (o.customers_name LIKE '%126627%' OR
       o.customers_company LIKE '%126627%' OR
       o.orders_id LIKE '%126627%' OR
       o.delivery_name LIKE '%126627%' OR
       o.delivery_company LIKE '%126627%' OR
       o.customers_email_address LIKE '%126627%' OR
       o.customers_telephone LIKE '%126627%' OR
       o.billing_name LIKE '%126627%' OR
       o.billing_company LIKE '%126627%' OR
       o.billing_nif LIKE '%126627%'
      ) 
ORDER BY o.orders_id DESC 
LIMIT 0, 20; 

注意:还要检查s.language_id是字符串还是数字。如果是数字,请删除单引号。有时这些会影响优化。

假设您拥有正确的索引(例如orders(orders_id, status_id)orders_total(class, order_id)order_status(order_status_id)),则仍有多种方法可以运行查询。

由于除了广泛的like子句之外还有其他条件,因此查询不会 进行全表扫描。但是,一个很大的问题是,其他两个条件(类和状态)的选择性如何。我的猜测是这些不是很有选择性 - 即超过1%的行符合这些条件。优化器决定扫描表是解决此查询的最有效方法。

顺便说一下,like条件看起来非常可疑。如果您正在寻找字符字段中的单词,您可以考虑全文搜索,这要快得多。