性能类似包括通配符(%)

时间:2015-07-14 09:09:35

标签: mysql performance wildcard sql-like

如果我执行此查询:

SELECT * FROM table1 WHERE name LIKE '%girl%'

返回名称中包含“girl”的所有记录。但是,由于%语句中的第一个通配符LIKE,它不能(或不)使用此处所述的索引:Mysql Improve Search Performance with wildcards (%%)

然后我将查询更改为:

SELECT * FROM table1 WHERE name LIKE 'girl%' OR name LIKE '%girl%'

OR的左侧,我删除了通配符,以便它可以使用索引。但性能获胜取决于MySQL如何评估查询。

因此我的问题是:当我添加OR语句时,我的查询性能是否会提高?

2 个答案:

答案 0 :(得分:3)

不,表现会一样。由于LIKE '%girl%',MySQL仍然必须评估第一个条件(OR)。然后它可以使用索引来评估第二个条件。当您EXPLAIN查询时,您可以看到此信息(mysql将显示它仍然需要进行全表扫描,这意味着检查每一行):

EXPLAIN SELECT * FROM table1 WHERE name LIKE 'girl%' OR name LIKE '%girl%'

为了更好地处理这些类型的查询,您需要使用Fulltext indexes和特殊语法来查询它们。但FT指数表现不同,并不适合所有事情。

答案 1 :(得分:0)

(这个答案提供了评论的摘要,并且与之前的一些说明相矛盾。)

领先的通配符

SELECT * FROM table1 WHERE name LIKE 'girl%' OR name LIKE '%girl%'
SELECT * FROM table1 WHERE                      name LIKE '%girl%'

其中任何一个都会执行表扫描并忽略任何索引。这都是因为领先的外卡和OR。 (它不会使用' girl%'的索引,与@ Marki555所说的相反 - 它不值得付出额外的努力。)

通过LIKE进行范围查询(无前导通配符):

SELECT * FROM table1 WHERE name LIKE 'girl%'

可能以下列方式使用INDEX(name)

  1. 将该指数的BTree向下钻取到第一个name,以" girl";
  2. 开头
  3. 向前扫描(在索引中),直到最后一行以" girl";
  4. 开头
  5. 对于第2步中的每个项目,请覆盖数据以获取*
  6. 由于步骤3的成本很高,优化程序首先估计在步骤2中需要触摸的行数。如果超过表的20%(大约),它将恢复为表扫描。 (因此,我使用" 可能"。)

    "覆盖索引"

    SELECT name FROM table1 WHERE name LIKE '%girl%'
    

    这将始终使用INDEX(name)。那是因为索引"涵盖"。也就是说,SELECT中的所有列都可以在INDEX中找到。由于INDEX看起来像一张桌子,扫描索引是进行查询的最佳方式。由于索引通常小于表,因此索引扫描通常比表扫描快。

    这是一个不太明显的"覆盖索引",但它仅适用于InnoDB:

    PRIMARY KEY(id)
    INDEX(name)
    SELECT id FROM table1 WHERE name LIKE '%girl%'
    

    InnoDB中的每个辅助密钥(name)都隐式包含PK (id)。因此索引看起来像(name, id)。因此SELECT中的所有列都在索引中。因此它是一个覆盖索引"。因此,它将使用索引并执行"索引扫描"。

    A"覆盖索引"由Using index中显示的EXPLAIN SELECT ...表示。