Querre 1:
select distinct email from mybigtable where account_id=345
prend 0,1S
Query 2:
Select count(*) as total from mybigtable where account_id=123 and email IN (<include all from above result>)
prend 0,2s
Query 3:
Select count(*) as total from mybigtable where account_id=123 and email IN (select distinct email from mybigtable where account_id=345)
prend 22 minutes et 90%, c'est dans l'état "préparant". Pourquoi cela prend-il tellement de temps?.
La table est innodub avec 3,2 millions de lignes sur MySQL 5.0
Dans Query 3, vous exécutez essentiellement une sous-requête pour chaque rangée de mybigble contre lui-même.
Pour éviter cela, vous devez faire deux changements majeurs:
Voici votre requête originale
Select count(*) as total from mybigtable
where account_id=123 and email IN
(select distinct email from mybigtable where account_id=345)
Tu pourrais essayer
select count(*) EmailCount from
(
select tbl123.email from
(select email from mybigtable where account_id=123) tbl123
INNER JOIN
(select distinct email from mybigtable where account_id=345) tbl345
using (email)
) A;
ou peut-être le comte par email
select email,count(*) EmailCount from
(
select tbl123.email from
(select email from mybigtable where account_id=123) tbl123
INNER JOIN
(select distinct email from mybigtable where account_id=345) tbl345
using (email)
) A group by email;
Je pense que vous avez déjà cela depuis que la requête 1 et la requête 2 courent vite. Assurez-vous d'avoir un index composé sur (comptent_id, email). Faire SHOW CREATE TABLE mybigtable\G
et assurez-vous d'en avoir un. Si vous ne l'avez pas ou si vous n'êtes pas sûr, créez-vous quand même l'index:
ALTER TABLE mybigtable ADD INDEX account_id_email_ndx (account_id,email);
Si vous voulez faire un non pas dans (), changer le INNER JOIN
à un LEFT JOIN
et vérifier le côté droit étant null, comme ceci:
select count(*) EmailCount from
(
select tbl123.email from
(select email from mybigtable where account_id=123) tbl123
LEFT JOIN
(select distinct email from mybigtable where account_id=345) tbl345
using (email)
WHERE tbl345.email IS NULL
) A;
S'il vous plaît lire ces deux liens sur faire des jointures
Voici une excellente vidéo YouTube où j'ai appris à refacteur requis et au livre qu'il reposait sur
Dans MySQL, les sous-éléments de la clause de la clause sont ré-exécutés pour chaque rangée de la requête extérieure, créant ainsi O (n ^ 2). La courte histoire est, n'utilisez pas (sélectionnez).
Avez-vous un index sur compte_id?
Le deuxième problème peut être avec les sous-requêtes imbriquées qui ont une performance terrible en 5.0.
Le groupe avec une clause ayant une clause est plus rapide que distinct.
Qu'essayez-vous de faire ce qui peut être mieux fait par des jointures en plus du point n ° 3?
Il y a beaucoup de traitement impliqué lors de la manipulation d'une sous-requête () telle que la vôtre. Vous pouvez en savoir plus à ce sujet ici .
Ma première suggestion serait d'essayer de ré-écrire la sous-requête dans une jointure à la place. Quelque chose comme (non testé):
SELECT COUNT(*) AS total FROM mybigtable AS t1
INNER JOIN
(SELECT DISTINCT email FROM mybigtable WHERE account_id=345) AS t2
ON t2.email=t1.email
WHERE account_id=123