MySQL-SELECCIONAR DÓNDE campo EN (subconsulta) - Extremadamente lento ¿por qué?


Tengo un par de duplicados en una base de datos que quiero inspeccionar, así que lo que hice para ver cuáles son duplicados, hice esto:

SELECT relevant_field
FROM some_table
GROUP BY relevant_field
HAVING COUNT(*) > 1

De esta manera, obtendré todas las filas con relevant_field ocurriendo más de una vez. Esta consulta tarda milisegundos en ejecutarse.

Ahora, quería inspeccionar cada uno de los duplicados, así que pensé que podía SELECCIONAR cada fila en some_table con un relevant_field en la consulta anterior, así que hice esto:

SELECT *
FROM some_table 
WHERE relevant_field IN
(
    SELECT relevant_field
    FROM some_table
    GROUP BY relevant_field
    HAVING COUNT(*) > 1
)

Esto resulta ser extremadamente lento por alguna razón (toma minutos). ¿Qué es exactamente lo que está pasando aquí para que sea tan lento? relevant_field está indexado.

Finalmente intenté crear una vista "temp_view" a partir de la primera consulta (SELECT relevant_field FROM some_table GROUP BY relevant_field HAVING COUNT(*) > 1), y luego hice mi segunda consulta como esta:

SELECT *
FROM some_table
WHERE relevant_field IN
(
    SELECT relevant_field
    FROM temp_view
)

Y eso funciona muy bien. MySQL hace esto en unos milisegundos.

¿Hay expertos en SQL aquí que puedan explicar lo que está pasando?

Author: Gabriele Petrioli, 2011-05-26

10 answers

Reescribe la consulta en este

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

Creo que st2.relevant_field debe estar en select, porque de lo contrario la cláusula having dará un error, pero no estoy 100% seguro

Nunca use IN con una subconsulta; esto es notoriamente lento.
Solo use IN con una lista fija de valores.

Más consejos

  1. Si desea realizar consultas más rápido, no haga un SELECT * solo seleccione los campos que realmente necesitas.
  2. Asegúrese de tener un indexar en relevant_field para acelerar el equi-join.
  3. Asegúrese de group by en la clave primaria.
  4. Si estás en InnoDB y solo seleccionas campos indexados (y las cosas no son demasiado complejas) entonces MySQL resolverá tu consulta usando solo los índices, acelerando las cosas.

Solución general para el 90% de sus consultas IN (select

Utilice este código

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) 
 104
Author: Johan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-05-26 09:59:32

La subconsulta se ejecuta para cada fila porque es una consulta correlacionada. Uno puede convertir una consulta correlacionada en una consulta no correlacionada seleccionando todo de la subconsulta, así:

SELECT * FROM
(
    SELECT relevant_field
    FROM some_table
    GROUP BY relevant_field
    HAVING COUNT(*) > 1
) AS subquery

La consulta final se vería así:

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
)
 89
Author: quano,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-05-27 21:18:27
 5
Author: edze,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:18:23
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;

He intentado su consulta en una de mis bases de datos, y también lo intenté reescrito como un join a una sub-consulta.

Esto funcionó mucho más rápido, pruébalo!

 4
Author: ceteras,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-05-26 09:08:05

He reformateado su consulta sql lenta con www.prettysql.net

SELECT *
FROM some_table
WHERE
 relevant_field in
 (
  SELECT relevant_field
  FROM some_table
  GROUP BY relevant_field
  HAVING COUNT ( * ) > 1
 );

Cuando se usa una tabla tanto en la consulta como en la subconsulta, siempre debe usar el alias de ambas, de la siguiente manera:

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
 );

¿eso ayuda?

 3
Author: plang,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-05-26 08:23:10

Prueba esto

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;
 3
Author: user2244323,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-04-04 10:33:40

A veces cuando los datos crecen mysql DONDE ins podría ser bastante lento debido a la optimización de consultas. Intente usar STRAIGHT_JOIN para decirle a mysql que ejecute la consulta tal cual, por ejemplo,

SELECT STRAIGHT_JOIN table.field FROM table WHERE table.id IN (...)

Pero cuidado: en la mayoría de los casos mysql optimizer funciona bastante bien, por lo que recomendaría usarlo solo cuando tenga este tipo de problema

 1
Author: Andrey Posudevsky,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-03-10 12:39:40

Esto es similar a mi caso, donde tengo una tabla llamada tabel_buku_besar. Lo que necesito son

  1. Buscando registro que tienen account_code='101.100' en tabel_buku_besar que tienen companyarea='20000' y también tienen IDR como currency

  2. Necesito obtener todos los registros de tabel_buku_besar que tienen account_code igual que el paso 1 pero tienen transaction_number en el resultado del paso 1

Al usar select ... from...where....transaction_number in (select transaction_number from ....), mi consulta se ejecuta extremadamente lenta y, a veces, causa que la solicitud se extinga o que mi aplicación no responder...

Intento esta combinación y el resultado...No está 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`
 0
Author: Hilarius L. Doren,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-09-25 04:08:07

Encuentro que esto es lo más eficiente para encontrar si existe un valor, la lógica se puede invertir fácilmente para encontrar si un valor no existe (ie ES NULO);

SELECT * FROM primary_table st1
LEFT JOIN comparision_table st2 ON (st1.relevant_field = st2.relevant_field)
WHERE st2.primaryKey IS NOT NULL

* Reemplace relevant_field con el nombre del valor que desea verificar que existe en su tabla

*Reemplace PrimaryKey con el nombre de la columna de clave primaria en la tabla de comparación.

 0
Author: Matt,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-11-30 11:51:48

En primer lugar, puede encontrar filas duplicadas y buscar recuento de filas se utiliza cuántas veces y ordenarlo por número como este;

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
) 

Después de eso, cree una tabla e inserte el resultado en ella.

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
) 

Finalmente, eliminar dublicar rows.No es inicio 0. Excepto el primer número de cada grupo eliminar todas las filas dublicate.

delete from  CopyTable where No!= 0;
 0
Author: harun ugur,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-08-21 12:53:13