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?
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
- Si desea realizar consultas más rápido,
no haga un
SELECT *
solo seleccione los campos que realmente necesitas. - Asegúrese de tener un indexar en
relevant_field
para acelerar el equi-join. - Asegúrese de
group by
en la clave primaria. - 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)
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
)
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
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!
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?
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;
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
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
Buscando registro que tienen
account_code='101.100'
entabel_buku_besar
que tienencompanyarea='20000'
y también tienenIDR
comocurrency
-
Necesito obtener todos los registros de
tabel_buku_besar
que tienen account_code igual que el paso 1 pero tienentransaction_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`
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.
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;
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