Редактировать: Пожалуйста, ответьте на один из двух ответов, которые я задаю. I знаю есть другие варианты, которые были бы лучше в другом случае. Эти другие потенциальные варианты (разбиение таблицы, выполнение одной крупной операции удаления без компрометации и т. Д.): NOT вариантов в моем случае из-за вещей, находящихся вне моего контроля.Вопрос оптимизации SQL (оракул)
У меня есть несколько очень больших таблиц для удаления. У всех есть тот же самый внешний ключ, который индексируется. Мне нужно удалить определенные записи из всех таблиц.
table source
id --primary_key
import_source --used for choosing the ids to delete
table t1
id --foreign key
--other fields
table t2
id --foreign key
--different other fields
Обычно при выполнении операции удаления, как это, я посажу вместе цикл, чтобы пройти через все идентификаторы:
declare
my_counter integer := 0;
begin
for cur in (
select id from source where import_source = 'bad.txt'
) loop
begin
delete from source where id = cur.id;
delete from t1 where id = cur.id;
delete from t2 where id = cur.id;
my_counter := my_counter + 1;
if my_counter > 500 then
my_counter := 0;
commit;
end if;
end;
end loop;
commit;
end;
Однако, в каком-то коде, который я видел в другом месте, он был собран в отдельные контуры, по одному для каждого удаления.
declare
type import_ids is table of integer index by pls_integer;
my_count integer := 0;
begin
select id bulk collect into my_import_ids from source where import_source = 'bad.txt'
for h in 1..my_import_ids.count
delete from t1 where id = my_import_ids(h);
--do commit check
end loop;
for h in 1..my_import_ids.count
delete from t2 where id = my_import_ids(h);
--do commit check
end loop;
--do commit check will be replaced with the same chunk to commit every 500 rows as the above query
Так что мне нужно один из следующих ответил:
1) Какой из них лучше?
2) Как я могу узнать, что лучше для моего конкретного случая? (IE, если это зависит от того, сколько столов у меня есть, насколько они являются, и т.д.)
Edit:
Я должен сделать это в цикле из-за размера этих таблиц. Я удалю тысячи записей из таблиц с сотнями миллионов записей. Это происходит в системе, которая не может позволить себе блокировать таблицы так долго.
EDIT:
ПРИМЕЧАНИЕ: Я требуется совершить в пакетах. Объем данных слишком велик, чтобы сделать это в одной партии. Таблицы отката будут разбивать нашу базу данных.
Если есть способ совершить в партиях, кроме циклов, я бы хотел его услышать. В противном случае, не беспокойтесь, говоря, что я не должен использовать цикл ...
Если вы считаете, что вам приходится прибегать к циклам из-за большого размера таблиц, вы (и/или DBA) посмотрели на использование функций разбиения на базы данных? Это один из «вариантов использования», с которым помогает разделение. Например, если у вас таблица размером 10 терабайт с миллиардом строк, проще удалить раздел (на основе идентификатора), чем перебрать миллионы строк. – JasDev
Да, мы это рассмотрели. Мы разделили фрагменты нашей базы данных. Тем не менее, таблицы t1 и t2 (и т. Д.) Доступны несколькими способами (на основе полей, отличных от id). Таким образом, любое разбиение на них повредило бы повсюду. Я оставляю много деталей, которые не влияют на мой вопрос, но означает, что мы не можем разбивать t1, t2 и т. Д. –
Вы знаете, что независимо от того, сколько строк вы удаляете, вы не будете заблокировать стол, верно? Если бы вы удаляли строку, которую пытались обновить какой-то другой процесс, вам вряд ли удастся заблокировать, что кажется маловероятным. И если кто-то пытается обновить строку, которую вы пытаетесь удалить, кажется, что это ужасно разумно для блокировки. –