У меня очень простая таблица students
, структура, как показано ниже, где первичный ключ id
. Эта таблица представляет собой стенд для около 20 многомиллионных таблиц строк, которые объединяются вместе.Поддержание логической согласованности с мягким удалением при сохранении исходной информации
+----+----------+------------+ | id | name | dob | +----+----------+------------+ | 1 | Alice | 01/12/1989 | | 2 | Bob | 04/06/1990 | | 3 | Cuthbert | 23/01/1988 | +----+----------+------------+
Если Боб хочет изменить свою дату рождения, то у меня есть несколько вариантов:
Update
students
с новой датой рождения.Положительные: 1 операция DML; к таблице всегда можно получить доступ с помощью одного первичного ключа.
Отрицательный: я теряю тот факт, что Боб когда-либо думал, что он родился 04/06/1990
Добавить колонку,
created date default sysdate
, к столу и изменить первичный ключid, created
. Каждыйupdate
становится:insert into students(id, name, dob) values (:id, :name, :new_dob)
Затем, когда я хочу, самая последняя информация не выполните следующие действия (Oracle, но вопрос стоит для каждого RDBMS):
select id, name, dob from (select a.*, rank() over (partition by id order by created desc) as "rank" from students a) where "rank" = 1
Положительных: Я никогда не теряют какой-либо информации ,
Отрицательные: Все запросы по всей базе данных занимают немного больше времени. Если таблица указана в указанном размере, это не имеет значения, но как только вы на своем 5-м
left outer join
, используя сканирование по диапазону, а не уникальное сканирование начинает иметь эффект.Добавить другой столк,
deleted date default to_date('2100/01/01','yyyy/mm/dd')
, или еще что-то слишком раннее, или футуристическое, дата принимает мое воображение. Измените первичный ключid, deleted
затем каждыйupdate
становится:update students x set deleted = sysdate where id = :id and deleted = (select max(deleted) from students where id = x.id); insert into students(id, name, dob) values (:id, :name, :new_dob);
и запрос, чтобы получить из текущей информации становится:
select id, name, dob from (select a.*, rank() over (partition by id order by deleted desc) as "rank" from students a) where "rank" = 1
Положительных: Я никогда не теряют какой-либо информации.
Отрицательные: Две операции DML; Я все еще должен использовать ранжированные запросы с дополнительной стоимостью или сканирование диапазона, а не уникальное сканирование индекса в каждом запросе.
Создайте вторую таблицу, скажет
student_archive
и изменить каждое обновление в:insert into student_archive select * from students where id = :id; update students set dob = :newdob where id = :id;
Положительные: Никогда не теряйте никакой информации.
Отрицательные: 2 DML-операции; если вы когда-либо захотите получить всю информацию, когда-либо вы должны использовать
union
или дополнительноleft outer join
.Для полноты есть чудовищно де-нормированная структура данных:
id, name1, dob, name2, dob2...
и т.д.
Если номер 1 не вариант, если я не хочу потерять какую-либо информацию и всегда делать мягкие удаления. Номер 5 можно безопасно отбросить, поскольку это вызывает больше проблем, чем того стоит.
У меня остались варианты 2, 3 и 4 с их негативными аспектами. Обычно я использую опцию 2 и потрясающие 150 строк (хорошо распределенные) множественные суб-выборки, которые идут вместе с ним.
Т.Л., д-р Я понимаю, что катание близко к линии на «не конструктивные» голосованиях здесь, но:
Что такое оптимального (в единственном числе!) Способ поддержания логического непротиворечивость, а never удаление любых данных?
Есть ли более эффективный способ, чем те, которые я документировал? В этом контексте я буду определять эффективность как «меньше операций DML» и/или «возможность удалить подзапросы». Если вы можете думать о лучшем определении, когда (если) отвечаете, пожалуйста, не стесняйтесь.
Спасибо! Я изменил # 4 на 'insert ... update'; очевидно, не слишком много думал об этом. – Ben