5

I'm trying to get a simple FULLTEXT match to be faster when using order by on another column on a table with over 100 million rows. The basis is one table with a fulltext on two columns and I want to search the database but order it by either the primary (least/most recent) or popularity. Is it possible to make a FULLTEXT with an order by on another indexed column fast? SQL Fiddle below with schema and explains of all queries:

See SQL Fiddle #1

What's very fast so far is denormalization of search columns in a separate table and a join but I would rather not have another table if not necessary. SQL Fiddle below (denormalized query at the end):

See SQL Fiddle #2

2 Answers 2

4

The first problem here is something you cannot control. What is it ???

The Query Optimizer's reaction to a FULLTEXT index. Why ?

(Now imagine the start of a STAR WARS movie with scrolling words...)

A very long time ago, I discovered that FULLTEXT indexes will nullify the MySQL Query Optimizer's use of other indexes

SUGGESTION

Refactor the Query so that the MATCH ...AGAINST collects keys only

EXAMPLE #1

SELECT a.id FROM a 
WHERE
MATCH (`search1`,`search2`) AGAINST ('aaaa' IN BOOLEAN MODE)
ORDER BY a.id DESC
LIMIT 5;

should become something like

SELECT N.id FROM
(SELECT id FROM a WHERE
MATCH (`search1`,`search2`) AGAINST ('aaaa' IN BOOLEAN MODE)) M
INNER JOIN a N USING (id)
ORDER BY N.id DESC LIMIT 5;

EXAMPLE #2

SELECT a.id,a.popularity FROM a 
WHERE
MATCH (`search1`,`search2`) AGAINST ('aaaa' IN BOOLEAN MODE)
ORDER BY a.popularity DESC
LIMIT 5;

should become something like

SELECT N.id,N.popularity FROM
(SELECT id FROM a WHERE
MATCH (`search1`,`search2`) AGAINST ('aaaa' IN BOOLEAN MODE)) M
INNER JOIN a N USING (id)
ORDER BY N.popularity DESC LIMIT 5;

CONCLUSION

The main idea: Collect the keys using MATCH ...AGAINST and join it back to the source table

1
  • This suggestion made my query much slower.
    – woky
    Commented Oct 31, 2020 at 2:43
0

Got the same problem and found a convenient solution - at least for my tasks.

If you always have the same ORDER BY eg popularity or whatever and don't do frequent updates, e.g. if it's enough on a daily basis, an idea is to set up a cronjob which resorts the table every night.

ALTER TABLE my_table ORDER BY my_sort_column ASC/DESC

This way you get the sorted results without filesort and any ORDER BY clause in the query. For my tasks it took down the query time from about 0.5-0.9 sec to ~0.004 for certain queries. The nightly ALTER query takes about 5-7sec on a 250k table and 11 year old Dell server.

NOTE: Works probably only with MyISAM tables, thank you for the comment @Kevin! (demo).

2
  • 1
    Only works for MyISAM I think, since InnoDB always orders table rows according to the clustered index. Also not sure how you'd combine this with a fulltext index, since that'll order the rows too I think
    – Kevin
    Commented Jun 4 at 5:38
  • @Kevin Thank you for the comment! I can confirm that this only works with MyISAM, just tried it (updating answer). When testing with MyISAM also be aware of ft_min_word_len which defaults to 4. Commented Jun 4 at 9:45

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.