My paintings
table looks like this
| id | artist_id | name
| 1 | 7 | landscape painting
| 2 | 15 | flowers painting
| 3 | 15 | scuffed painting
The artist_id
is indexed and the name
has a fulltext
index on it. The table contains about 10M record.
Queries that match the name
agains some keywords are ok:
select * from `paintings` where match (`name`) against ('+scuffed*' in boolean mode) limit 10;
10 rows in set (0.04 sec)
But when I sometimes want to only check for a certain painting done by a certain artist:
select * from `paintings` where `artist_id` = 15 and match (`name`) against ('+scuffed*' in boolean mode) limit 10;
7 rows in set (0.40 sec)
As you can see it takes 10x longer to run the query when I include the artist_id
. I also tried running a nested query in order to get only paintings that have specific ids:
select * from `paintings` where id in (SELECT id from paintings where artist_id = 15) and match (`name`) against ('+scuffed*' in boolean mode) limit 10;
7 rows in set (0.44 sec)
This ended up being even slower.
How can this query be optimized to work well with and without a where clause on the artist_id
?
Thank you!
2
Answers
Run
EXPLAIN SELECT ...
to see how the query is performed.I think your second query is as optimal is can be. MySQL will perform the
MATCH
first, then check any other conditions.You could add
INDEX(artist_id)
, but I don’t think that will help.More
Let me provide another approach, then talk through the pros an cons.
Comments:
id
needs to be indexed to keepAUTO_INCREMENT
happy; a simpleINDEX(id)
suffices.PRIMARY KEY
must be unique; includingid
suffices.FULLTEXT
.FULLTEXT
andLIKE
have different rules for what will/won’t match. So you may get different answers.AGAINST('... +the ...' IN BOOLEAN MODE)
never finds any rows.AGAINST("+color +purple")
will findpurple color
, butLIKE '%color purple%
won’t.You need to create a COMPOSITE INDEX KEY consisting of columns (id and artist_id) to speed up your query:
And now you can test again your 2nd query: