简体   繁体   中英

MySql Left Join very slow query

i have 2 tables of about 3000/4000 rows. I need to make a relation using Left Join for filter the results by searching a text or datetime. I need also to count a total row for pagination. When i run the query is epic slow, consider about 40/45 seconds by console and more than a minute from webpage. The relation is: for 1 of tableA have N in tableB. There is a solution for have a fast query? The sample query is:

SELECT X,Y,Z, (SELECT COUNT(*) 
     FROM tableB WHERE tableB.idTa=tableA.id) AS CountTB 
FROM tableA 
LEFT JOIN tableB ON tableA.id = tableB.idA
WHERE tableA.X LIKE'%mytext%' OR tableB.Z LIKE'%mytext%' 
GROUP BY tableA.id 
ORDER BY tableA.Y LIMIT 0,10

Thank you all

ON clause is present of course. only mistyped from my phone. Now it's correct and very slow :)

New update: If I change the relationship from LEFT JOIN to RIGHT JOIN it become pretty fast....why??

Start from correct JOIN I believe that should work pretty fast.

Something like:

SELECT a.X,a.Y,a.Z, COUNT(b.id)  CountTB 
FROM tableA a
LEFT JOIN tableB b
ON b.idTa = a.id AND b.Z LIKE'%mytext%' 
WHERE a.X LIKE '%mytext%'
GROUP BY tableA.id 
ORDER BY tableA.Y LIMIT 0,10

Your conditions are not very clear. If you can provide good data sample, we can find better query.

I have a guess that you don't need to bZ LIKE'%mytext%' . start from just:

SELECT a.X,a.Y,a.Z, COUNT(b.id)  CountTB 
FROM tableA a
LEFT JOIN tableB b
ON b.idTa = a.id 
WHERE a.X LIKE '%mytext%'
GROUP BY tableA.id 
ORDER BY tableA.Y LIMIT 0,10

Taking a wild stab at this, just to point you in the general direction, here's a possible rewrite of that query: (I don't promise that it works ...)

SELECT X,Y,Z, COUNT(B.id) AS CountTB
FROM tableA A
  LEFT JOIN tableB B
    USING (id)
WHERE tableA.X LIKE'%mytext%' OR tableB.Z LIKE'%mytext%' 
GROUP BY X, Y, Z
ORDER BY tableA.Y 
LIMIT 0,10

Notice my many changes:

  1. There is no nested query.
  2. The tables are identified for convenience by the alises, A and B .
  3. The LEFT JOIN is USING (id) , which is shorthand for WHERE A.id = B.id .
  4. The GROUP BY clause specifies that the data is to be grouped by these three variables. All of these must appear in the SELECT clause, and everything else that appears must be an aggregate function such as COUNT() or SUM() .

Again, I do not promise that this query works. But it should illustrate how such a query should generally be constructed.

Don't use LEFT unless you want NULLs from the 'righthand' table. I don't think you do in this case.

The positioning of the ( SELECT COUNT... ) means that it needs to be re-evaluated for ever row, which it does not. Get rid of it; use SQL_CALC_FOUND_ROWS .

AX and BZ are being searched for the same substring? Do they always have the same value? If so, then only search one of them. ( LIKE '%...' is a costly part of your query.)

Using JOIN inflates the number of rows; then you added GROUP BY to deflate it. This inflate/deflate is costly.

The COUNT(*) fails to filter by '%mytext%', so it won't give you what you want for "rows 30-39 of 145".

Is it AZ or BZ??

SELECT SQL_CALC_FOUND_ROWS
        a.X, a.Y,
        ( SELECT Z FROM tableB WHERE idTa = a.id AND Z LIKE'%mytext%' ) AS Z
    FROM tableA AS a
    WHERE a.X LIKE '%mytext%'
    ORDER BY a.Y
    LIMIT 0,10

SELECT FOUND_ROWS();   -- to get the "of 156 rows"

and you need these

tableB: INDEX(idTa)
tableA: INDEX(Y)

Caveat: Since it is unclear what the relationship between A and B is (1:many vs many:many), this solution may be incorrect. The incorrectness will jump out by the subquery returning multiple rows.

So, I may not have given you the 'correct' answer, but hopefully I have given you enough clues so you can get much closer.

After that, perhaps you can make the pagination faster by "remembering where you left off" instead of using OFFSET . See my blog .

If you want to discuss this further, please provide SHOW CREATE TABLE and do not obfuscate the column names -- often the names give clues of your intent.

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