Удаление строк из состязательной таблицы - PullRequest
1 голос
/ 30 октября 2009

У меня есть таблица БД, в которой в каждой строке есть случайно сгенерированный первичный ключ, сообщение и пользователь. У каждого пользователя есть около 10-100 сообщений, но есть от 10 до 50 тысяч пользователей.

Я пишу сообщения ежедневно для каждого пользователя за один раз. Я хочу выбросить старые сообщения для каждого пользователя, прежде чем писать новые, чтобы таблица была как можно меньше.

Прямо сейчас я эффективно делаю это:

delete from table where user='mk'

Затем напишите все сообщения для этого пользователя. Я вижу много споров, потому что у меня много потоков, делающих это одновременно.

У меня есть дополнительное требование сохранять самый последний набор сообщений для каждого пользователя.

У меня нет доступа к БД напрямую. Я пытаюсь угадать проблему, основываясь на некоторой обратной связи. Причина, по которой я сосредотачиваюсь на этом сценарии, заключается в том, что запрос на удаление показывает много времени ожидания (опять же, насколько мне известно), а также недавно добавленную функциональность.

Может кто-нибудь дать совет?

Было бы лучше:

select key from table where user='mk'

Тогда удалить отдельные строки оттуда? Я думаю, что это может привести к менее жестокой блокировке.

Ответы [ 7 ]

4 голосов
/ 30 октября 2009

Если вы делаете это каждый день для каждого пользователя, почему бы просто не удалить каждую запись из таблицы одним оператором? Или даже

truncate table whatever reuse storage
/

редактировать

Причина, по которой я предлагаю такой подход, заключается в том, что этот процесс выглядит как ежедневная пакетная загрузка пользовательских сообщений, за которыми следует очистка старых сообщений. То есть мне кажется, что бизнес-правила "таблица будет содержать сообщения только одного дня для любого пользователя". Если этот процесс выполняется для каждого пользователя, то одна операция будет наиболее эффективной.

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

3 голосов
/ 30 октября 2009

Нет, всегда лучше выполнить один оператор SQL для набора строк, чем для серии «строка за строкой» (или то, что Том Кайт называет «медленными за медленными») операциями. Когда вы говорите, что «видите много раздоров», что именно вы видите? Очевидный вопрос: индексируется ли столбец USER?

(Конечно, имя столбца не может быть действительно USER в базе данных Oracle, поскольку это зарезервированное слово!)

РЕДАКТИРОВАТЬ: Вы сказали, что столбец USER не проиндексирован. Это означает, что каждое удаление будет включать полное сканирование таблицы до 50K * 100 = 5 миллионов строк (или, в лучшем случае, 10K * 10 = 100 000 строк), чтобы удалить только 10-100 строк. Добавление индекса пользователя USER может решить ваши проблемы.

0 голосов
/ 30 октября 2009

Это может ускорить процесс:

Создать таблицу поиска:

create table rowid_table (row_id ROWID ,user VARCHAR2(100));
create index rowid_table_ix1 on rowid_table (user);

Ночная работа:

truncate table rowid_table;
insert /*+ append */ into rowid_table
select ROWID row_id , user
from table;
dbms_stats.gather_table_stats('SCHEMAOWNER','ROWID_TABLE');

Затем при удалении записи:

delete from table
where ROWID IN (select row_id
                from rowid_table
                where user = 'mk');
0 голосов
/ 30 октября 2009

Поговорите со своим администратором базы данных

Он здесь, чтобы помочь вам. Когда мы, администраторы баз данных, отнимаем у разработчиков доступ к чему-то подобному, предполагается, что мы предоставим вам поддержку для этой задачи. Если ваш код занимает слишком много времени для завершения, и кажется, что это время связано с базой данных, ваш администратор базы данных сможет точно посмотреть, что происходит, предложить предложения или, возможно, даже решить проблему, не меняя ничего.

Просто взглянув на формулировку проблемы, не похоже, что вы будете смотреть на спорные вопросы, но я ничего не знаю о вашей базовой структуре.

Действительно, поговорите со своим администратором базы данных. Ему, вероятно, понравится смотреть на что-то интересное, а не планировать последнее развертывание ЦП.

0 голосов
/ 30 октября 2009

Я думаю, вам нужно определить свои требования немного яснее ...

Например. Если вы знаете всех пользователей, для которых вы хотите писать сообщения, вставьте идентификаторы во временную таблицу, индексируйте их по идентификатору и удалите из пакета. Тогда потоки, которые вы запускаете, делают две вещи. Записать идентификатор пользователя во временную таблицу, Записать сообщение в другую временную таблицу. Затем, когда потоки закончили выполняться, основной поток должен

DELETE * FROM сообщений INNER JOIN TEMP_MEMBERS ON ID = TEMP_ID

ВСТАВИТЬ В СООБЩЕНИЯ ВЫБРАТЬ * ИЗ ТЕМПА_мессы

Я не знаком с синтаксисом Oracle, но я бы так к нему подошел, если бы все пользовательские сообщения обрабатывались в быстрой последовательности.

Надеюсь, это поможет

0 голосов
/ 30 октября 2009

Ваше собственное предложение кажется очень разумным.Блокировка небольшими партиями имеет два преимущества:

  • транзакции будут меньше
  • блокировка будет ограничена несколькими строками за раз

Блокировкав партиях должно быть большое улучшение.

0 голосов
/ 30 октября 2009

Вы уверены, что видите конфликт блокировки? Скорее всего, вы видите конфликт дисков из-за слишком большого количества одновременных (но не связанных обновлений). Решение этой проблемы заключается в простом сокращении числа используемых вами потоков. Меньшая конкуренция на диске будет означать более высокую общую пропускную способность.

...