Очень медленное удаление на базе MySQL с подзапросом - PullRequest
10 голосов
/ 09 сентября 2011

Этот запрос mysql выполняется около 10 часов и еще не завершен.Что-то ужасно не так.

Здесь две таблицы (текст и спам).Спам хранит идентификаторы записей спама в тексте, который я хочу удалить.

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

спам содержит только 2 столбца, оба являются целыми.800K записей имеет размер файла несколько мегабайт.Оба целых являются первичными ключами.

текст имеет 3 столбца.id (первичный ключ), текст, флаги.около 1200 тысяч записей и около 2,1 гигабайта (больше всего спама).

Сервер представляет собой xeon quad, 2 ГБ ОЗУ (не спрашивайте меня, почему).Только apache (почему?) И mysqld запущены.Это старый бесплатный BSD и MySQL 4.1.2 (не спрашивайте меня, почему)

Тем: 6 Вопросы: 188805 Медленные запросы: 318 Открытий: 810 Сброс таблиц: 1 Открытых таблиц: 157 Запросов в секунду, в среднем: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

В запросе используется только один процессор, в верхней части указано 25% времени процессора (т. Е. 1 из 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

Есть идеи как это исправить?

Ответы [ 4 ]

13 голосов
/ 09 сентября 2011

По моему опыту, подзапросы часто являются причиной медленного времени выполнения операторов SQL, поэтому я стараюсь их избегать. Попробуйте это:

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

Отказ от ответственности: Этот запрос не проверен, сначала сделайте резервные копии! : -)

5 голосов
/ 09 сентября 2011

Ваш выбор where id in (select ...) всегда будет работать плохо.

Вместо этого используйте обычное объединение, которое будет очень эффективным:

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

Сначала обратите внимание на выбор из спама, затем присоединитесь ктекст, который даст лучшее исполнение.

3 голосов
/ 31 марта 2017

разумеется, это займет много времени, потому что он выполняет подзапрос для каждой записи, но, используя INNER JOIN напрямую, этот запрос выполняется только один раз, что позволяет предположить, что запрос займет

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

, нос помощью join запрос будет выполнен только один раз:

DELETE t FROM tname.text t INNER JOIN (SELECT textid FROM spam) sq on t.old_id = sq.textid ;
1 голос
/ 09 сентября 2011

Копировать строки, которые не находятся в spam форме text, в новую таблицу.Затем удалите таблицу text и переименуйте созданную таблицу.Хорошая идея - не добавлять ключи в созданную таблицу.Добавьте ключи после переименования.

...