MySQL subquery is slower than two separate queries
I am puzzling over a simple subquery. I have the following request that runs within 30+ seconds:
SELECT DISTINCT SUBSTRING( 6pp, 1, 4 ) AS postcode
FROM 6pp
WHERE gemeenteID
IN (
SELECT gebiedID
FROM tmp_orderimport
WHERE typeGebied = 'Gemeente'
AND idorder =1733
AND STATUS = TRUE );
Explain:
If I break the query in 2 queries and run the IN part first, it all takes less than a second. But of course I prefer to use a single query. The tables are in MYISAM. Any suggestions?
Update:
Following the lead of Gordon Linoff. I changed the SQL to:
SELECT DISTINCT SUBSTRING( 6pp, 1, 4 ) AS postcode
FROM `6pp`
WHERE EXISTS (SELECT 1
FROM tmp_orderimport oi
WHERE oi.gebiedID = `6pp`.gemeenteID AND
typeGebied = 'Gemeente' AND idorder = 1733 AND STATUS = TRUE
);
And added an index for tmp_orderimport (gebiedID, typeGebied, idorder, status). The request now takes less than 4 seconds to complete.
New explanation:
source to share
Try using instead exists
:
SELECT DISTINCT SUBSTRING( 6pp, 1, 4 ) AS postcode
FROM `6pp`
WHERE EXISTS (SELECT 1
FROM tmp_orderimport oi
WHERE oi.gebiedID = `6pp`.gemeenteID AND
typeGebied = 'Gemeente' AND idorder = 1733 AND STATUS = TRUE
);
You can also speed it up with an index on tmp_orderimport(gebiedID, typeGebied, idorder, status)
.
MySQL can be inefficient (sometimes depending on the version) when used IN
with a subquery. exists
usually fixes the problem. The particular problem is that the subquery is executed for every comparison. When you create a temporary table, you work around this.
source to share
MySQL probably executes the subquery once for each record of the main query. This results in exponential processing.
Its subquery is independent of the main query, you can run the subquery first and store the value in memory (possibly a temporary table) and then use the main query.
source to share
I didn't see any comments about your 6pp table and had an index for that for (gemeenteID, 6pp). I also have an index on your tmp_orderimport table (idorder, tpeGebied, status, gebiedID) and then change it a bit.
SELECT DISTINCT
SUBSTRING( P.6pp, 1, 4 ) AS postcode
FROM
( SELECT gebiedID
FROM tmp_orderimport
WHERE typeGebied = 'Gemeente'
AND idorder =1733
AND STATUS = TRUE ) G
JOIN 6pp P
on G.gebiedID = P.gemeenteID
source to share