Я относительный новичок, когда дело касается баз данных. Мы используем MySQL, и в настоящее время я пытаюсь ускорить выполнение инструкции SQL, которая, как кажется, занимает некоторое время. Я посмотрел на SO для аналогичного вопроса, но не нашел его.
Цель состоит в том, чтобы удалить все строки в таблице A, имеющие соответствующий идентификатор в таблице B.
В настоящее время я делаю следующее:
DELETE FROM a WHERE EXISTS (SELECT b.id FROM b WHERE b.id = a.id);
В таблице a содержится около 100K строк в таблице a и около 22K строк в таблице b. Столбец "id" является PK для обеих таблиц.
Этот оператор занимает около 3 минут для запуска на моем тестовом поле - Pentium D, XP SP3, 2GB RAM, MySQL 5.0.67. Это кажется мне медленным. Возможно, это не так, но я надеялся ускорить процесс. Есть ли лучший/более быстрый способ достичь этого?
EDIT:
Некоторая дополнительная информация, которая может быть полезна. Таблицы A и B имеют такую же структуру, как я сделал следующее, чтобы создать таблицу B:
CREATE TABLE b LIKE a;
Таблица a (и, следовательно, таблица b) содержит несколько индексов, чтобы ускорить запросы, которые сделаны против него. Опять же, я относительный новичок в работе с БД и все еще учащийся. Я не знаю, какой эффект, если таковой имеется, имеет отношение к вещам. Я предполагаю, что это имеет эффект, поскольку индексы также должны быть очищены, верно? Я также задавался вопросом, есть ли какие-либо другие настройки БД, которые могут повлиять на скорость.
Кроме того, я использую INNO DB.
Вот дополнительная информация, которая может быть вам полезной.
Таблица A имеет структуру, подобную этой (я немного ее обработал):
DROP TABLE IF EXISTS `frobozz`.`a`;
CREATE TABLE `frobozz`.`a` (
`id` bigint(20) unsigned NOT NULL auto_increment,
`fk_g` varchar(30) NOT NULL,
`h` int(10) unsigned default NULL,
`i` longtext,
`j` bigint(20) NOT NULL,
`k` bigint(20) default NULL,
`l` varchar(45) NOT NULL,
`m` int(10) unsigned default NULL,
`n` varchar(20) default NULL,
`o` bigint(20) NOT NULL,
`p` tinyint(1) NOT NULL,
PRIMARY KEY USING BTREE (`id`),
KEY `idx_l` (`l`),
KEY `idx_h` USING BTREE (`h`),
KEY `idx_m` USING BTREE (`m`),
KEY `idx_fk_g` USING BTREE (`fk_g`),
KEY `fk_g_frobozz` (`id`,`fk_g`),
CONSTRAINT `fk_g_frobozz` FOREIGN KEY (`fk_g`) REFERENCES `frotz` (`g`)
) ENGINE=InnoDB AUTO_INCREMENT=179369 DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC;
Я подозреваю, что часть проблемы - это число индексов для этой таблицы.
Таблица B похожа на таблицу B, хотя она содержит только столбцы id
и h
.
Кроме того, результаты профилирования выглядят следующим образом:
starting 0.000018
checking query cache for query 0.000044
checking permissions 0.000005
Opening tables 0.000009
init 0.000019
optimizing 0.000004
executing 0.000043
end 0.000005
end 0.000002
query end 0.000003
freeing items 0.000007
logging slow query 0.000002
cleaning up 0.000002
решаемые
Благодаря всем ответам и комментариям. Они, конечно, заставили меня задуматься над этой проблемой. Престижность dotjoe за то, что я отступил от проблемы, задав простой вопрос: "Есть ли в других таблицах ссылка a.id?"
Проблема заключалась в том, что в таблице A была указана DELETE TRIGGER, которая вызывала хранимую процедуру для обновления двух других таблиц, C и D. Таблица C имела FK обратно в a.id и после выполнения некоторых действий, связанных с этим идентификатором в в хранимой процедуре, она имела утверждение,
DELETE FROM c WHERE c.id = theId;
Я просмотрел инструкцию EXPLAIN и переписал ее как
EXPLAIN SELECT * FROM c WHERE c.other_id = 12345;
Итак, я мог видеть, что это делает, и он дал мне следующую информацию:
id 1
select_type SIMPLE
table c
type ALL
possible_keys NULL
key NULL
key_len NULL
ref NULL
rows 2633
Extra using where
Это сказало мне, что это была болезненная операция, и поскольку она собиралась называться 22500 раз (для данного набора данных удаляется), это была проблема. Как только я создал INDEX в этом столбце other_id и повторно запустил EXPLAIN, я получил:
id 1
select_type SIMPLE
table c
type ref
possible_keys Index_1
key Index_1
key_len 8
ref const
rows 1
Extra
Гораздо лучше, на самом деле действительно здорово.
Я добавил, что Index_1 и мои времена удаления соответствуют временам, указанным mattkemp. Это была очень тонкая ошибка с моей стороны из-за того, что в последний момент была добавлена какая-то дополнительная функциональность. Оказалось, что большинство предложенных альтернативных операторов DELETE/SELECT, как указано Daniel, в итоге получили примерно такое же количество времени и как soulmerge, выражение было довольно гораздо лучшее, что я смогу построить на основе того, что мне нужно было сделать. Как только я предоставил индекс для этой другой таблицы C, мои DELETE были быстрыми.
Патологоанатомическое:
Из этого упражнения вышли два урока. Во-первых, ясно, что я не использовал возможности оператора EXPLAIN, чтобы лучше понять влияние моих SQL-запросов. Это ошибка новобранец, поэтому я не собираюсь биться об этом. Я узнаю из этой ошибки. Во-вторых, оскорбительный код был результатом "быстрого реагирования", а неадекватный дизайн/тестирование привели к тому, что эта проблема не появилась раньше. Если бы я создал несколько массивных наборов тестовых данных для использования в качестве тестового ввода для этой новой функциональности, я бы не потратил впустую свое время и ваше. На моем тестировании на стороне БД не хватало глубины, которую имеет моя сторона приложения. Теперь у меня есть возможность улучшить это.