简体   繁体   中英

MySQL how to optimize %LIKE% query?

Trying to optimize MySQL query. The reason of needed optimization is table growth. For now it has approx 300K rows and in future it will be much more.

Table structure

CREATE TABLE `activity_log` (
  `id` int(11) UNSIGNED NOT NULL,
  `date_created` datetime NOT NULL,
  `user_id` int(11) UNSIGNED NOT NULL,
  `event_id` smallint(6) UNSIGNED NOT NULL,
  `activity_by` tinyint(4) NOT NULL DEFAULT '0' COMMENT '''0'' - by client himself; ''-1'' - by admin; other - ap_user.id;',
  `text` text NOT NULL,
  `notes` text NOT NULL,
  `ip` char(46) DEFAULT NULL
) ENGINE=Aria DEFAULT CHARSET=utf8;

ALTER TABLE `activity_log`
  ADD PRIMARY KEY (`id`),
  ADD KEY `client_id` (`user_id`),
  ADD KEY `event_id` (`event_id`),
  ADD KEY `date_created` (`date_created`),
  ADD KEY `ip` (`ip`);
ALTER TABLE `activity_log` ADD FULLTEXT KEY `text` (`text`);

ALTER TABLE `activity_log`
  MODIFY `id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=2435463;
COMMIT;

Query need to optimize:

SELECT a.id,a.activity_by,a.user_id,a.date_created,
            DATE_FORMAT(a.date_created,'%e %b, %Y') as date,
            DATE_FORMAT(a.date_created,'%H:%i') as time ,
            a.text,a.notes,e.color,e.link_icon,  u.id as user_id, u.login, r.role 
                  FROM `activity_log` a
                        LEFT JOIN `ap_user` u ON a.activity_by = u.id
                        LEFT JOIN `ap_role` r ON u.role_id = r.id,
                  `activity_log_events` e
                  WHERE 1
                  AND a.event_id=e.id
                  AND a.text LIKE '%test tester%'
         ORDER BY `date_created` DESC, `id` DESC

What I already tried is to replace %LIKE% query with FULLTEXT

SELECT a.id,a.activity_by,a.user_id,a.date_created,
        DATE_FORMAT(a.date_created,'%e %b, %Y') as date,
        DATE_FORMAT(a.date_created,'%H:%i') as time ,
        a.text,a.notes,e.color,e.link_icon,  u.id as user_id, u.login, r.role 
              FROM `activity_log` a
                    LEFT JOIN `ap_user` u ON a.activity_by = u.id
                    LEFT JOIN `ap_role` r ON u.role_id = r.id,
              `activity_log_events` e
              WHERE 1
              AND a.event_id=e.id
    AND MATCH (a.text) AGAINST ('test tester*' IN BOOLEAN MODE) ORDER BY `date_created` DESC, `id` DESC 

At finish this query will has its LIMIT 15 approx for DataProvider and pagination if this info is important.

So I added FULLTEXT index and placed fake data into this table and it has ~1 million rows.

The one of the strange things is that like query gives 1300 results for 1 million rows table and MATCH query gives 200_000 for the same table.

First thought this is because of table contains equal rows as I duplicated them for test. Is that possible? FULLTEXT search is very slow because of that and like search gives unfair results - 1k instead of 200k. This is specific table that anyway will contain a lot of similar words like names and standard phrases like "has added" or "has removed".

How to optimize this %like% query? Is it possible without FULLTEXT ? If not - what exactly am I doing wrong with FULLTEXT query?

Thanks for any help.

The ORDER BY is ambiguous; I'm surprised it did not give you a syntax error. There are two tables with id .

Is there a reason for using Aria instead of InnoDB?

Consider changing to

('+test +tester*' IN BOOLEAN MODE)

Consider also

('+"test tester*"' IN BOOLEAN MODE)

And, to double check with LIKE :

MATCH(...) AGAINST(...)
AND text LIKE "..."

This last suggestion handles some cases where FULLTEXT will efficiently find the 'words', then LIKE makes sure they are together. For example to avoid matching "test or tester" (because of the intervening word). Or "James Smith and Bob Doyle".

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM