MySQL覆盖索引和LIKE运算符

时间:2015-09-23 10:10:48

标签: mysql query-optimization query-performance

我正在阅读"高性能MySQL",O' Reilly,第2版。 第122页:

  

MySQL无法在索引中执行LIKE操作。等

在同一页面中,后续示例是(其中有一个关于actor,title,prod_id的索引):

EXPLAIN SELECT * FROM products JOIN ( SELECT prod_id FROM products WHERE actor='SEAN CARREY' AND title LIKE '%APOLLO%' ) AS t1 ON (t1.prod_id=products.prod_id)\G

然后它说:

  

现在MySQL在查询的第一阶段使用覆盖索引,当它在FROM子句中的子查询中找到匹配的行时。

我不明白为什么,LIKE声明仍然存在......

2 个答案:

答案 0 :(得分:2)

假设表格为InnoDB

SELECT prod_id
     FROM products
     WHERE actor='SEAN CARREY' AND title LIKE '%APOLLO%'

INDEX(actor, title, prod_id)处理,因为它是“覆盖”

SELECT * FROM ...

未被“覆盖”,因为(我假设)*中有很多其他字段。

他们展示的“技巧”是:

  1. 在索引中进行所有搜索,假设它比表小得多。注意:索引是BTree;该表是一个不同的BTree。
  2. 从第1步获取PRIMARY KEY值。即获取prod_id的列表。
  3. 使用*进入表格PRIMARY KEY,有效地查找其余数据(products)。
  4. 假设共有40行actor='SEAN CARREY',其中只有3行 title LIKE '%APOLLO%'。让我们比较两种方法:

    SELECT * FROM products
        WHERE actor='SEAN CARREY' AND title LIKE '%APOLLO%'
    
    1. 查看INDEX(actor, ...)以查找40 prod_id
    2. 将数据覆盖40次。
    3. 过滤掉那些没有理想title
    4. 提供3行。
    5. 在I / O界限中(读取:巨大的表),这将是I / O计数:

      1. 1个块可能包含所有40个索引条目;他们会在一起,因为索引的第一部分是相同的。
      2. 需要在表格中查看近40个街区。
      3. 总计:约41个单位的工作。

        现在用子查询查看查询。

        1. 仅扫描索引。再一次阻止。
        2. 4次进入主表。
        3. 总计:4个工作单位。

          4<< 41,因此更复杂的查询实际上运行得更快。 (你不太可能真正看到完整的10倍改进 - 因为我遗漏了很多细节。)

答案 1 :(得分:0)

因为索引是从左到右工作所以如果你想使用索引 -

,左边不应该是变量

如果您的标题字段已编入索引,请按以下方式检查 -

title like '%APOLLO%' : Will not use index

title like '%APOLLO' : Will not use index

title like 'APOLLO%' : Will use index

title like 'APOLLO' : Will use index

在您的情况下,不需要子查询,因为您可以通过简单查询获得相同的结果,并且如果actor字段被索引,则查询将仅使用此索引。