I have a FULLTEXT search on the database, with the WHERE IN condition which checks that search results exists in another table. The query takes more than 1 hour to complete (companies table has 67k rows, and employees table has 82k rows).
Desired result: get search results for "company ABC" in table A only if we have employees data for that company in table B.
The query I have is:
SELECT *,
MATCH (name, keywords, description) AGAINST ('+searchKeyword*') as relevance,
(SELECT COUNT(customerID) FROM customers WHERE MATCH (name, keywords, description) AGAINST ('+searchKeyword*' IN BOOLEAN MODE) AND customerID IN(SELECT customerID FROM customersPersonelData)) as totalResults
FROM customers
WHERE MATCH (name, keywords, description) AGAINST ('+searchKeyword*' IN BOOLEAN MODE)
AND customerID IN(SELECT customerID FROM customersPersonelData)
ORDER BY relevance DESC, name ASC
LIMIT 0,10
For testing I removed "relevance" and "totalResults" subqueries, and this query then takes 72 seconds:
SELECT *
FROM customers
WHERE MATCH (name, keywords, description) AGAINST ('+searchKeyword*' IN BOOLEAN MODE)
AND customerID IN(SELECT customerID FROM customersPersonelData)
ORDER BY name ASC
LIMIT 0,10
I tried using EXIST and JOIN, the result is the same.
How can I speed this query up?
Best Answer
If I understand correctly, you are getting count to satisfy your Pagination requirements. Generally, two separate queries are executed; one to get the 10 records, and another to get the total count.
The problem in your approach is that you are calculating the Count in a subquery inside the SELECT clause. For every row returned by the SELECT clause, is going to be executing the same count again and again. You can move the count calculation part to a Derived Table instead (Subquery inside the FROM clause), and CROSS JOIN it.
Another noteworthy thing is that MySQL is (unfortunately) generally inefficient when optimizing subqueries inside the
IN(...)
condition. You can convert this intoEXISTS
based Correlated Subquery instead (JOIN
may result in Duplicates).For good performance, you would need an index on
customerID
incustomersPersonelData
table. Also, a composite Full Text Index should exists on(name, keywords, description)
columns in thecustomers
table.Now, if I were you, and this was a Pagination problem, I would look at this article to rethink how pagination should be done: https://mariadb.com/kb/en/library/pagination-optimization/