Вопрос

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

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

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

delete from table where user='mk'

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

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

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

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

Было бы лучше, если бы:

select key from table where user='mk'

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

Это было полезно?

Решение

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

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

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

Другие советы

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

truncate table whatever reuse storage
/

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

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

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

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

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

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

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

ВСТАВЬТЕ В СООБЩЕНИЯ ВЫБРАТЬ * ИЗ TEMP_messges

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

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

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

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

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

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

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

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

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');

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

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top