Обработка изменений в Oracle
У меня есть таблица сказать:
CREATE TABLE "DataNode" (
"ID" NUMBER(7,0),
"TYPE" NUMBER(7,0),
"NAME" VARCHAR2(100),
"STATUS" NUMBER(7,0),
"REVISION" NUMBER(4,0),
"MODIFIEDAT" DATE
);
CREATE TABLE "DataNode_Revisions" (
"ID" NUMBER(7,0),
"NODEID" NUMBER(7,0),
"TYPE" NUMBER(7,0),
"NAME" VARCHAR2(100),
"STATUS" NUMBER(7,0),
"REVISION" NUMBER(4,0),
"MODIFIEDAT" DATE
) COMPRESS;
Итак, у меня есть эти две таблицы. Я делаю все свои чтения из "DataNode", и когда происходит изменение, я записываю текущую запись в "DataNode_Revisions", а затем изменяю свою существующую запись "DataNode". Имеет смысл?
Это лучший способ сделать это? Я уже могу сказать, что столкнусь с проблемами при изменении схемы. Я не вижу лучшей альтернативы, но если есть, пожалуйста, дайте мне знать! Я предполагаю, что хранение всего этого в одной таблице приведет к огромным потерям производительности, не так ли? Я имею в виду, что я бы увеличил число записей более чем в четыре раза, а их уже немало. Я думаю, что Drupal хранит такие ревизии узлов, и мне любопытно, как они не страдают от проблем с производительностью.
"DataNode" постоянно читается многими пользователями. Тем не менее, очень мало записей происходит. "DataNode_Revisions" только для чтения из иногда. Я просто беспокоюсь о том, чтобы поддерживать так много таблиц. "DataNode" - одна из 25 таблиц, очень похожих на эту.
4 ответа
Будут ли какие-либо последствия для производительности от сохранения старых строк в таблице DataNode, зависит от того, как осуществляется доступ к строкам DataNode. Если все операции чтения являются однострочными поисками для текущей строки, количество строк в таблице является относительно несущественным - не нужно больше усилий, чтобы найти текущую строку для определенного идентификатора, чем для получения строки для этого идентификатора из текущей таблицы DataNode (здесь я предполагаю, что идентификатор является ключом для таблицы). С другой стороны, если у вас есть несколько запросов, которые выполняют сканирование таблицы таблицы DataNode, то увеличение числа строк в четыре раза увеличит время, необходимое для выполнения этих запросов.
Если вы хотите пойти по пути помещения исторических строк в таблицу DataNode, вы, вероятно, захотите добавить столбец EXPIRATION_DATE, имеющий значение NULL для текущей строки и заполненный для строк с истекшим сроком. Затем можно создать индекс на основе функции на основе EXPIRATION_DATE, который будет иметь данные только для текущих строк, т.е.
CREATE INDEX idx_current_ids
ON DataNode( (CASE WHEN expiration_date IS NULL THEN id ELSE null END) );
который будет использоваться в запросе, как
SELECT *
FROM DataNode
WHERE (CASE WHEN expiration_date IS NULL THEN id ELSE null END) = <<some id>>
Очевидно, что вы, вероятно, захотите создать представление с таким условием, а не переписывать его каждый раз, когда вам нужна текущая строка, т.е.
CREATE VIEW CurrentDataNode
AS
SELECT (CASE WHEN expiration_date IS NULL THEN id ELSE null END) id,
type,
name,
status
FROM DataNode;
SELECT *
FROM CurrentDataNode
WHERE id = <<some value>>
Я обычно использую триггеры для записи в таблицу "Редакции". Да, изменения схемы вынуждают вас обновить зеркальную таблицу и функцию триггера / архива.
Я думаю, вы пожалеете, что сохранили всю свою историю, а также текущую редакцию в одной таблице, поэтому я думаю, что вы поняли правильную идею.
Если вы хотите попытаться найти общее решение, которое не требует зеркальной таблицы для каждой из ваших транзакционных таблиц, вы можете подумать о том, чтобы иметь только одну таблицу ревизий, где вы конвертируете записи в XML и сохраняете их в сгустке. Не очень полезно, если вам нужно часто или быстро получить к нему доступ, но хорошо, если вы действительно просто хотите заархивировать все.
Это будет зависеть от приложения. Если вы используете 11g, возможно, вы захотите взглянуть на новый архив данных Flashback. Я только начинаю смотреть на это, чтобы сохранить историю всех наших финансовых и других важных данных.
У вас есть несколько вариантов. Какое бизнес-требование заставляет вас отслеживать изменения данных?
если вам нужно сохранить изменения только в течение некоторого "короткого" периода времени, вы можете прочитать данные из UNDO, используя запрос флешбека. select * from table from timestamp (bla);
если вам нужно хранить эту информацию в течение длительного времени, посмотрите на функцию под названием Oracle Total Recall. Он делает то же самое, что Flashback Query, но сохраняет изменения на неопределенный срок.
если вам нужно что-то более простое, не заставляйте приложение вставлять "старую" версию строк. Используйте триггер, который заполняет данные.
если система очень занята, вы можете разделить две таблицы, имея промежуточную таблицу, которую вы используете в качестве "очереди"