Skip to content
Advertisement

Optimize MySQL FULL TEXT search

I have a search with only one field that allows me to search in several columns of a MySQL table.

This is the SQL query:

SELECT td__user.*
FROM td__user LEFT JOIN td__user_oauth ON td__user.id = td__user_oauth.user_id 
WHERE ( td__user.id LIKE "contact@mywebsite.com" OR (MATCH (email, firstname, lastname) AGAINST (+"contact@mywebsite.com" IN BOOLEAN MODE)) ) 
ORDER BY date_accountcreated DESC LIMIT 20 OFFSET 0

The exact SQL query with PHP pre-processing of the search field to separate each word:

if($_POST['search'] == '') {
    $searchId = '%';
} else {
    $searchId = $_POST['search'];
}

$searchMatch = '';
foreach($arrayWords as $word) {
    $searchMatch .= '+"'.$word.'" ';
}

$sqlSearch = $dataBase->prepare('SELECT td__user.*,
                                        td__user_oauth.facebook_id, td__user_oauth.google_id
                                 FROM td__user
                                 LEFT JOIN td__user_oauth ON td__user.id = td__user_oauth.user_id
                                 WHERE (
                                         td__user.id LIKE :id OR 
                                         (MATCH (email, firstname, lastname) AGAINST (:match IN BOOLEAN MODE)) ) 

                                 ORDER BY date_accountcreated DESC LIMIT 20 OFFSET 0);

$sqlSearch->execute(['id'    => $searchId,
                     'match' => $searchMatch]);

$searchResult = $sqlSearch->fetchAll();
$sqlSearch->closeCursor();

And these are my index:enter image description here

The SQL query works well, when I put an ID in the search field or a first name or a last name, or an email even not complete I have results. I can also put a first name and a last name in my search field and I will only result in people with this name.

On the other hand, in a table containing 500,000 contacts, the query takes more than 5 seconds. Are there any possible points for improvement in the query or in the indexes to be done in order to have a faster query?

Advertisement

Answer

Did you try to use “UNION” 2 sets of results instead of using the “OR” operator in the “WHERE” clause? Because I’m just afraid of the index can not be used with the “OR” operator.

The query will be something like this:

SELECT td__user.*,
    td__user_oauth.facebook_id, 
    td__user_oauth.google_id
FROM td__user
LEFT JOIN td__user_oauth ON td__user.id = td__user_oauth.user_id
WHERE td__user.id LIKE :id

UNION
SELECT td__user.*,
    td__user_oauth.facebook_id, 
    td__user_oauth.google_id
FROM td__user
LEFT JOIN td__user_oauth ON td__user.id = td__user_oauth.user_id
WHERE MATCH (email, firstname, lastname) AGAINST (:match IN BOOLEAN MODE))

ORDER BY date_accountcreated DESC LIMIT 20 OFFSET 0

Hope this can help!

User contributions licensed under: CC BY-SA
6 People found this is helpful
Advertisement