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将不会使用该索引.
所以你基本上有两种方法:
(moduleName, menuName)
,然后查询的所有结果将直接从索引中获取(即从内存中获取).方法#2(参见SQLfiddle)将通过简单的查询获得索引命中,并且应该在更大的表上提供更好的性能.在小桌子上,我(即lserni - 见评论)不认为这是值得的.
你实际上正在对该领域进行正则表达式,因此没有密钥可以正常工作.但是,在您的示例中,您可以使其更有效,因为匹配的每个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)
不漂亮.