Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Optimizing MySQL search query

Need yours help optimizing one mysql query. Lets take simple table for example.

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

Lets Fill it with some data:

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

And some sample string. Let it be abc_def;

Traditionally we are trying to find all the rows containing search string.

On the contrary, my task is, to find all rows which contains moduleName in input string. For now I have following query to get desired result:

SELECT `moduleName` ,`menuName` 
FROM `Modules` 
WHERE 'abc_def' LIKE(CONCAT(`moduleName`,'%'))

This will return

moduleName   | menuName 
---------------------------
abc          | name2

The problem is, that this query is not using index.

Is there some way to force it to use one?

like image 501
Denis O. Avatar asked Mar 26 '13 12:03

Denis O.


People also ask

What are the ways to optimize MySQL?

One of the first things you can do to optimize your queries is to focus on indexing. Indexes are used to help operations find data more quickly in tables stored in the database. You can help your index be more efficient by indexing all your predicates by WHERE, JOIN, ORDER BY, and GROUP BY clauses.

How can I make my database search faster?

Try these five tips to boost the speed of your database: Make sure all of your tables have primary keysRunning a table without a primary key is like running a four-cylinder engine with only two active pistons. Open every table in Design view and make sure each has a primary key.


1 Answers

You seem to misunderstand what is index and how it can help to speed up a query.

Let's look at what is your moduleName index. It is basically a sorted list of mappings from moduleName to ID. And what you are selecting?

SELECT moduleName, menuName 
FROM Modules
WHERE 'abc_def' LIKE CONCAT(moduleName,'%');

That is you want some two fields for each row that has some relation to a somehow mapped value of moduleName field. How can ever index help you? There is no exact match, and there is no way to take advantage from the fact that we have moduleNames sorted.

What you need to take advantage from the index, is to have a check for exact match in the condition:

SELECT moduleName, menuName 
FROM Modules
WHERE moduleName = LEFT('abc_def', LENGTH(moduleName));

Now we do have an exact match, but since the right part of the condition depends on the moduleName as well, this condition will be checked for each row. Since in his case MySQL can not predict how many rows will match, but it can predict that it will need randon disk access to fetch menuNames for each matching row, MySQL will not use the index.

So you have basically two approaches:

  1. if you know that the condition narrows the number of matching rows significantly, then you can just force the index
  2. another option is to extend your index to a covering composite index (moduleName, menuName), then all results for query will be fetched from the index directly (that is from memory).

Approach #2 (see SQLfiddle) will get you an index hit with a simple query, and should offer much better performances on a larger table. On small tables, I (i.e., lserni - see comment) don't think it's worth the effort.

like image 165
newtover Avatar answered Oct 19 '22 18:10

newtover