2011-09-09 11 views
6

Esta consulta de mysql se ejecuta durante alrededor de 10 horas y no ha finalizado. Algo está terriblemente mal.Eliminación muy lenta en la base de mysql con subconsulta

Dos tablas (texto y correo no deseado) están aquí. El correo no deseado almacena los identificadores de las entradas de spam en el texto que quiero eliminar.

DELETE FROM tname.text WHERE old_id IN (SELECT textid FROM spam); 

correo no deseado tiene solo 2 columnas, ambas son ints. 800,000 entradas tienen un tamaño de archivo de varios Mbs. Ambas entradas son claves principales.

texto tiene 3 columnas. id (clave prim), texto, banderas. alrededor de 1200 K entradas, y alrededor de 2,1 gigabytes de tamaño (la mayoría de spam).

El servidor es un quad xeon, 2 gigabytes ram (no me preguntes por qué). Solo apache (¿por qué?) Y mysqld se están ejecutando. Es un antiguo bsd gratuito y mysql 4.1.2 (no me preguntes por qué)

Temas: 6 Preguntas: 188805 Consultas lentas: 318 Abre: 810 Tablas rasantes: 1 Mesas abiertas: 157 consultas por segundo promedio: 7.532

Mysql my.cnf:

[mysqld] 
datadir=/usr/local/mysql 
log-error=/usr/local/mysql/mysqld.err 
pid-file=/usr/local/mysql/mysqld.pid 
tmpdir=/var/tmp 
innodb_data_home_dir = 
innodb_log_files_in_group = 2 
join_buffer_size=2M 
key_buffer_size=32M 
max_allowed_packet=1M 
max_connections=800 
myisam_sort_buffer_size=32M 
query_cache_size=8M 
read_buffer_size=2M 
sort_buffer_size=2M 
table_cache=256 
skip-bdb 
log-slow-queries = slow.log 
long_query_time = 1 

#skip-innodb 
#default-table-type=innodb 
innodb_data_file_path = /usr/local/mysql/ibdata1:10M:autoextend 
innodb_log_group_home_dir = /usr/local/mysql/ 
innodb_buffer_pool_size = 128M 
innodb_log_file_size = 16M 
innodb_log_buffer_size = 8M 
#innodb_flush_log_at_trx_commit=1 
#innodb_additional_mem_pool_size=1M 
#innodb_lock_wait_timeout=50 

log-bin 
server-id=201 

[isamchk] 
key_buffer_size=128M 
read_buffer_size=128M 
write_buffer_size=128M 
sort_buffer_size=128M 

[myisamchk] 
key_buffer_size=128M[server:~] dmesg | grep memory 
real memory = 2146828288 (2047 MB) 
avail memory = 2095534080 (1998 MB) 

read_buffer_size=128M 
write_buffer_size=128M 
sort_buffer_size=128M 
tmpdir=/var/tmp 

La consulta está utilizando sólo una CPU, la parte superior dice 25% el tiempo de CPU (de modo 1 de 4).

real memory = 2146828288 (2047 MB) 
avail memory = 2095534080 (1998 MB) 

62 processes: 2 running, 60 sleeping 
CPU states: 25.2% user, 0.0% nice, 1.6% system, 0.0% interrupt, 73.2% idle 
Mem: 244M Active, 1430M Inact, 221M Wired, 75M Cache, 112M Buf, 31M Free 
Swap: 4096M Total, 1996K Used, 4094M Free 

    PID USERNAME  THR PRI NICE SIZE RES STATE C TIME WCPU COMMAND 
11536 mysql   27 20 0 239M 224M kserel 3 441:16 94.29% mysqld 

¿Alguna idea de cómo solucionarlo?

+0

¿Cuáles son los motores de almacenamiento en las tablas? – JamesHalsall

+0

Su consulta incluye una columna old_id, pero su descripción de la tabla 'text' no tiene - ¿realmente describió la tabla completa? En general, sospecho que este problema desaparecería mágicamente con una nueva versión de MySQL. –

+1

Asegúrate de tener índices en 'text.old_id' y' spam.textid'. – Johan

Respuesta

11

En mi experiencia, las consultas secundarias a menudo son causa de tiempos de ejecución lentos en las sentencias SQL, por lo tanto trato de evitarlas. Pruebe esto:

DELETE tname FROM tname INNER JOIN spam ON (tname.old_id = spam.textid); 

Descargo de responsabilidad: ¡Esta consulta no está disponible, primero realice las copias de seguridad! :-)

+0

-1 para usar la sintaxis SQL implícita, salir de 1989 y usar combinaciones explícitas en su lugar. Además, esto no resolverá el problema ya que su afirmación no es cierta. OP necesita poner índices en los campos involucrados en la unión. – Johan

+0

Su afirmación es muy cierta para las versiones de MySQL de esa añada. Cuando introdujeron por primera vez las subconsultas, y durante un tiempo después de eso, hubo una plétora de problemas de rendimiento con ellas. –

+0

+1, también asegúrese de tener un índice en spam.textid. – nobody

1

Copie las filas que no están en spam formulario text en la nueva tabla. A continuación, elimine la tabla text y cambie el nombre de la tabla creada. Una buena idea es no agregar ninguna clave a la tabla creada. Agrega claves después de cambiar el nombre.

+0

En serio ??? ..... – Antoniossss

+0

¡Sí, en serio! ¡Por qué no pensé en eso, la mejor solución aquí en la mayoría de las aplicaciones prácticas! – taur

5

Su elección de where id in (select ...) siempre tendrá un bajo rendimiento.

su lugar, utilice una normal de unirse a la cual va a ser muy eficaz: la selección

DELETE `text` 
FROM spam 
join `text` on `text`.old_id = spam.textid; 

Aviso de correo no deseado en primer lugar, a continuación, unirse a texto, que le dará el mejor rendimiento.

0

de Corse que tomará mucho tiempo, ya que ejecuta la subconsulta para cada registro, pero mediante el uso de combinación interna directamente esta consulta se ejecuta sólo una vez deja para pensar que la consulta se llevará a

10 ms for 50000 rec full time = 50000 * 10 ms ---> 8.333 minutes !! at least don't forget the condition and deleting time ..... 

pero using join la consulta se ejecutará solo una vez:

DELETE t FROM tname.text t INNER JOIN (SELECT textid FROM spam) sq on t.old_id = sq.textid ;