J'ai deux ou trois doublons dans une base de données que je veux inspecter, alors ce que j'ai fait pour voir lesquels sont des doublons, j'ai fait ceci:
SELECT relevant_field
FROM some_table
GROUP BY relevant_field
HAVING COUNT(*) > 1
De cette façon, toutes les lignes contenant pertinentes_field apparaîtront plus d'une fois. Cette requête prend quelques millisecondes à exécuter.
Maintenant, je voulais inspecter chacun des doublons, alors je pensais pouvoir CHOISIR chaque ligne de la table some_table avec un champ pertinent dans la requête ci-dessus.
SELECT *
FROM some_table
WHERE relevant_field IN
(
SELECT relevant_field
FROM some_table
GROUP BY relevant_field
HAVING COUNT(*) > 1
)
Cela s'avère être extrêmement lent pour une raison quelconque (cela prend des minutes). Qu'est-ce qui se passe exactement ici pour le ralentir? relevant_field est indexé.
Finalement, j'ai essayé de créer une vue "temp_view" à partir de la première requête (SELECT relevant_field FROM some_table GROUP BY relevant_field HAVING COUNT(*) > 1)
, puis de créer ma deuxième requête comme suit:
SELECT *
FROM some_table
WHERE relevant_field IN
(
SELECT relevant_field
FROM temp_view
)
Et ça marche très bien. MySQL le fait en quelques millisecondes.
Tous les experts SQL ici qui peuvent expliquer ce qui se passe?
La sous-requête est en cours d'exécution pour chaque ligne car il s'agit d'une requête corrélée. On peut transformer une requête corrélée en une requête non corrélée en sélectionnant tous les éléments de la sous-requête, comme suit:
SELECT * FROM
(
SELECT relevant_field
FROM some_table
GROUP BY relevant_field
HAVING COUNT(*) > 1
) AS subquery
La requête finale ressemblerait à ceci:
SELECT *
FROM some_table
WHERE relevant_field IN
(
SELECT * FROM
(
SELECT relevant_field
FROM some_table
GROUP BY relevant_field
HAVING COUNT(*) > 1
) AS subquery
)
Réécrivez la requête dans cette
SELECT st1.*, st2.relevant_field FROM sometable st1
INNER JOIN sometable st2 ON (st1.relevant_field = st2.relevant_field)
GROUP BY st1.id /* list a unique sometable field here*/
HAVING COUNT(*) > 1
Je pense que st2.relevant_field
doit être dans la sélection, car sinon la clause having
donnera une erreur, mais je ne suis pas sûr à 100%
N'utilisez jamais IN
avec une sous-requête; c'est notoirement lent.
Ne jamais utiliser IN
avec une liste fixe de valeurs.
Plus de conseils
SELECT *
uniquement les champs dont vous avez réellement besoin.relevant_field
pour accélérer l'équi-jointure.group by
sur la clé primaire. Solution générale pour 90% de vos requêtes IN (select
Utilisez ce code
SELECT * FROM sometable a WHERE EXISTS (
SELECT 1 FROM sometable b
WHERE a.relevant_field = b.relevant_field
GROUP BY b.relevant_field
HAVING count(*) > 1)
SELECT st1.*
FROM some_table st1
inner join
(
SELECT relevant_field
FROM some_table
GROUP BY relevant_field
HAVING COUNT(*) > 1
)st2 on st2.relevant_field = st1.relevant_field;
J'ai essayé votre requête sur l'une de mes bases de données et je l'ai également réécrite en tant que jointure d'une sous-requête.
Cela a fonctionné beaucoup plus vite, essayez-le!
Essaye ça
SELECT t1.*
FROM
some_table t1,
(SELECT relevant_field
FROM some_table
GROUP BY relevant_field
HAVING COUNT (*) > 1) t2
WHERE
t1.relevant_field = t2.relevant_field;
J'ai reformaté votre requête SQL lente avec www.prettysql.net
SELECT *
FROM some_table
WHERE
relevant_field in
(
SELECT relevant_field
FROM some_table
GROUP BY relevant_field
HAVING COUNT ( * ) > 1
);
Lorsque vous utilisez une table à la fois dans la requête et dans la sous-requête, vous devez toujours aliaser les deux, comme ceci:
SELECT *
FROM some_table as t1
WHERE
t1.relevant_field in
(
SELECT t2.relevant_field
FROM some_table as t2
GROUP BY t2.relevant_field
HAVING COUNT ( t2.relevant_field ) > 1
);
Est ce que ça aide?
parfois, lorsque les données deviennent plus volumineuses, mysql WHERE IN peut être assez lent en raison de l'optimisation des requêtes. Essayez d’utiliser STRAIGHT_JOIN pour indiquer à mysql d’exécuter la requête telle quelle, par exemple.
SELECT STRAIGHT_JOIN table.field FROM table WHERE table.id IN (...)
mais attention: dans la plupart des cas, l'optimiseur mysql fonctionne plutôt bien, je vous recommande donc de ne l'utiliser que lorsque vous avez ce genre de problème
Tout d'abord, vous pouvez rechercher des lignes en double et trouver le nombre de lignes utilisé autant de fois que vous le souhaitez, et le classer par numéro comme ceci;
SELECT q.id,q.name,q.password,q.NID,(select count(*) from UserInfo k where k.NID= q.NID) as Count,
(
CASE q.NID
WHEN @curCode THEN
@curRow := @curRow + 1
ELSE
@curRow := 1
AND @curCode := q.NID
END
) AS No
FROM UserInfo q,
(
SELECT
@curRow := 1,
@curCode := ''
) rt
WHERE q.NID IN
(
SELECT NID
FROM UserInfo
GROUP BY NID
HAVING COUNT(*) > 1
)
après cela, créez une table et y insérez le résultat.
create table CopyTable
SELECT q.id,q.name,q.password,q.NID,(select count(*) from UserInfo k where k.NID= q.NID) as Count,
(
CASE q.NID
WHEN @curCode THEN
@curRow := @curRow + 1
ELSE
@curRow := 1
AND @curCode := q.NID
END
) AS No
FROM UserInfo q,
(
SELECT
@curRow := 1,
@curCode := ''
) rt
WHERE q.NID IN
(
SELECT NID
FROM UserInfo
GROUP BY NID
HAVING COUNT(*) > 1
)
Enfin, supprimez les doublons de lignes.No signifie début 0. Sauf le premier nombre de chaque groupe, supprimez toutes les rangées de doublons.
delete from CopyTable where No!= 0;
Ceci est similaire à mon cas, où j'ai une table nommée tabel_buku_besar
. Ce dont j'ai besoin
Recherche d'un enregistrement qui a account_code='101.100'
dans tabel_buku_besar
qui a companyarea='20000'
et qui a aussi IDR
comme currency
Je dois obtenir tous les enregistrements de tabel_buku_besar
qui ont le code account_code identique à l'étape 1 mais ont transaction_number
à l'étape 1 résultat
lors de l'utilisation de select ... from...where....transaction_number in (select transaction_number from ....)
, ma requête était extrêmement lente et pouvait parfois entraîner l'expiration du délai de requête ou rendre mon application ne répondant pas ...
J'essaie cette combinaison et le résultat ... pas mal ...
`select DATE_FORMAT(L.TANGGAL_INPUT,'%d-%m-%y') AS TANGGAL,
L.TRANSACTION_NUMBER AS VOUCHER,
L.ACCOUNT_CODE,
C.DESCRIPTION,
L.DEBET,
L.KREDIT
from (select * from tabel_buku_besar A
where A.COMPANYAREA='$COMPANYAREA'
AND A.CURRENCY='$Currency'
AND A.ACCOUNT_CODE!='$ACCOUNT'
AND (A.TANGGAL_INPUT BETWEEN STR_TO_DATE('$StartDate','%d/%m/%Y') AND STR_TO_DATE('$EndDate','%d/%m/%Y'))) L
INNER JOIN (select * from tabel_buku_besar A
where A.COMPANYAREA='$COMPANYAREA'
AND A.CURRENCY='$Currency'
AND A.ACCOUNT_CODE='$ACCOUNT'
AND (A.TANGGAL_INPUT BETWEEN STR_TO_DATE('$StartDate','%d/%m/%Y') AND STR_TO_DATE('$EndDate','%d/%m/%Y'))) R ON R.TRANSACTION_NUMBER=L.TRANSACTION_NUMBER AND R.COMPANYAREA=L.COMPANYAREA
LEFT OUTER JOIN master_account C ON C.ACCOUNT_CODE=L.ACCOUNT_CODE AND C.COMPANYAREA=L.COMPANYAREA
ORDER BY L.TANGGAL_INPUT,L.TRANSACTION_NUMBER`
Je trouve que c'est le moyen le plus efficace de rechercher si une valeur existe, la logique peut facilement être inversée pour rechercher si une valeur n'existe pas (c'est-à-dire IS NULL);
SELECT * FROM primary_table st1
LEFT JOIN comparision_table st2 ON (st1.relevant_field = st2.relevant_field)
WHERE st2.primaryKey IS NOT NULL
* Remplacez pertinent_field par le nom de la valeur que vous voulez vérifier existe dans votre table
* Remplacez primaryKey par le nom de la colonne de clé primaire du tableau de comparaison.