优化MySQL搜索查询

Den*_* O. 14 mysql query-optimization

需要你帮助优化一个mysql查询.让我们以简单的表格为例.

CREATE TABLE `Modules` (
 `ID` int(11) NOT NULL AUTO_INCREMENT,
 `moduleName` varchar(100) NOT NULL,
 `menuName` varchar(255) NOT NULL,
PRIMARY KEY (`ID`),
KEY `moduleName` (`moduleName`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
Run Code Online (Sandbox Code Playgroud)

让我们填写一些数据:

INSERT INTO  `Modules` (`moduleName` ,`menuName`)
VALUES 
    ('abc1',  'name1'), 
    ('abc',  'name2'), 
    ('ddf',  'name3'), 
    ('ccc',  'name4'), 
    ('fer',  'name5');
Run Code Online (Sandbox Code Playgroud)

还有一些样本字符串.让它成为abc_def;

传统上我们试图找到包含搜索字符串的所有行.

相反,我的任务是找到包含moduleName在输入字符串中的所有行.现在我有以下查询来获得所需的结果:

SELECT `moduleName` ,`menuName` 
FROM `Modules` 
WHERE 'abc_def' LIKE(CONCAT(`moduleName`,'%'))
Run Code Online (Sandbox Code Playgroud)

这将返回

moduleName   | menuName 
---------------------------
abc          | name2
Run Code Online (Sandbox Code Playgroud)

问题是,此查询未使用索引.

有没有办法强迫它使用一个?

new*_*ver 11

您似乎误解了什么是索引以及它如何帮助加快查询速度.

让我们来看看你的moduleName指数是什么.它基本上是从moduleName到ID的映射的排序列表.你在选择什么?

SELECT moduleName, menuName 
FROM Modules
WHERE 'abc_def' LIKE CONCAT(moduleName,'%');
Run Code Online (Sandbox Code Playgroud)

也就是说,您希望每行有两个字段,这些字段与moduleName字段的某种映射值有某种关系.怎么能索引帮助你?没有完全匹配,并且没有办法利用我们对moduleNames进行排序的事实.

您需要利用索引来检查条件是否完全匹配:

SELECT moduleName, menuName 
FROM Modules
WHERE moduleName = LEFT('abc_def', LENGTH(moduleName));
Run Code Online (Sandbox Code Playgroud)

现在我们确实有一个完全匹配,但由于条件的右边部分也取决于moduleName,因此将检查每一行的这个条件.因为在他的情况下,MySQL无法预测将匹配多少行,但它可以预测它将需要randon磁盘访问来获取每个匹配行的menuNames,MySQL将不会使用该索引.

所以你基本上有两种方法:

  1. 如果您知道条件会显着缩小匹配行的数量,那么您可以强制索引
  2. 另一种选择是将索引扩展到覆盖复合索引(moduleName, menuName),然后查询的所有结果将直接从索引中获取(即从内存中获取).

方法#2(参见SQLfiddle)将通过简单的查询获得索引命中,并且应该在更大的表上提供更好的性能.在小桌子上,我(即lserni - 见评论)不认为这是值得的.


Ste*_*veP 7

你实际上正在对该领域进行正则表达式,因此没有密钥可以正常工作.但是,在您的示例中,您可以使其更有效,因为匹配的每个moduleName必须小于或等于'abc_def',因此您可以添加:

and moduleName <= 'abc_def'
Run Code Online (Sandbox Code Playgroud)

我能想到的唯一另一种选择是:

where modleName in ('a','ab','abc','abc_','abc_d','abc_de','abc_def')
Run Code Online (Sandbox Code Playgroud)

不漂亮.