Я относительный новичок, когда дело доходит до баз данных. Мы используем MySQL, и в настоящее время я пытаюсь ускорить выполнение оператора SQL, который, похоже, требует времени для запуска. Я посмотрел вокруг на SO на похожий вопрос, но не нашел.
Цель состоит в том, чтобы удалить все строки в таблице A, которые имеют совпадающий идентификатор в таблице B.
В настоящее время я делаю следующее:
DELETE FROM a WHERE EXISTS (SELECT b.id FROM b WHERE b.id = a.id);
В таблице a приблизительно 100 000 строк и около 22 000 строк в таблице b. Столбец id - это PK для обеих таблиц.
Это утверждение занимает около 3 минут для запуска на моем тестовом компьютере - Pentium D, XP SP3, 2 ГБ оперативной памяти, 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, как заявил Даниэль , в конечном итоге заняли, по существу, такое же количество времени, и, как упоминалось soulmerge , это заявление было в значительной степени Лучше всего я смогу построить на основе того, что мне нужно было сделать. Как только я предоставил индекс для этой другой таблицы C, мои DELETE были быстрыми.
Посмертное
Из этого упражнения извлечены два урока. Во-первых, ясно, что я не использовал возможности оператора EXPLAIN, чтобы лучше понять влияние моих SQL-запросов. Это ошибка новичка, так что я не собираюсь изводить себя этим. Я учусь на этой ошибке. Во-вторых, нарушающий код был результатом менталитета «сделай это быстро», а неадекватный дизайн / тестирование привели к тому, что эта проблема не появилась раньше. Если бы я сгенерировал несколько значительных наборов тестовых данных для использования в качестве входных данных теста для этой новой функциональности, я бы не потратил впустую ни свое, ни ваше. Моему тестированию на стороне БД не хватало глубины, которую имеет моя прикладная сторона. Теперь у меня есть возможность улучшить это.
Ссылка: ОБЪЯСНИТЕ Заявление