如果我执行此查询:
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
语句时,我的查询性能是否会提高?
答案 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)
:
name
,以" girl"; *
。由于步骤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 ...
表示。