Мне нужно хранить таблицу элементов задач, где каждый элемент имеет уникальный идентификатор.Задачи могут приходить несколько раз, поэтому идентификатор не является первичным ключом.Однако меня волнует только последняя версия задачи, которую я определяю по последовательности.Каждый экземпляр задачи может быть NEW или DONE .Таблицы выглядят примерно так:
CREATE SEQUENCE TASKSEQ;
CREATE TABLE TASKS (
ID VARCHAR2(100),
STATE VARCHAR2(50),
SEQ NUMBER(20)
);
При моделировании данных учтите, что таблица содержит миллион выполненных задач, но новый пакет ранее существующих задач поступил сразу после установки состояния NEW
.
BEGIN
FOR IDX IN 1..1000000
LOOP
INSERT INTO TASKS (ID, STATE, SEQ)
VALUES (IDX, 'DONE', TASKSEQ.NEXTVAL);
END LOOP;
FOR IDX IN 900001..1000000
LOOP
INSERT INTO TASKS (ID, STATE, SEQ)
VALUES (IDX, 'NEW', TASKSEQ.NEXTVAL);
END LOOP;
END;
Я сейчас пытаюсь выбрать задачи, помеченные как NEW
в их последней редакции.Меня не особо волнует порядок, в котором я выполняю эти задачи, просто тот факт, что эти задачи помечены NEW
в их отдельных последних версиях.Я хотел бы сначала прочитать «старые» задачи, чтобы избежать живых блокировок.Я извлекаю блоки задач с заданным размером пакета.
Оператор select выглядит примерно так:
SELECT L.ID, L.SEQ
FROM TASKS L
INNER JOIN (
SELECT ID, MAX(SEQ) MAXSEQ
FROM TASKS
GROUP BY ID
) R
ON L.ID = R.ID
AND L.SEQ = R.MAXSEQ
WHERE L.STATE = 'NEW'
ORDER BY L.SEQ
FETCH FIRST 100 ROWS ONLY;
Как только задачи поступают в приложение, они обрабатываются и обновляются вбаза данных через:
UPDATE TASKS
SET STATE = 'DONE'
WHERE ID = ?
AND SEQ = ?;
Как только это обновление завершено, опрашивается следующий пакет задач.Возможно, при обработке задач выполнялись параллельные записи в таблицу, но, кроме приведенных выше операторов, ни одна задача никогда не удалялась из таблицы.
Например, в таблице могут быть следующие данные:
ID|STATE|SEQ
A |NEW |1
A |DONE |2
B |DONE |3
B |NEW |4
C |NEW |5
C |NEW |6
В этом случае я ожидал бы, что опрос будет содержать (B, 4) и (C, 6), но не A. После обновления этих состояний кортежа до DONE , я ожидаю, что последующийОпрос не будет содержать никаких данных, если в таблицу не будет добавлено больше данных.
Мне интересно, можно ли эффективно реализовать этот дизайн таблицы с индексом и как этот индекс будет выглядеть.Простой индекс, такой как
CREATE UNIQUE INDEX NEW_TASK_INDEX ON TASKS (ID, SEQ, STATE);
, не справляется с ограничением порядка, и мне интересно, как я могу изменить или добавить индекс для достижения своей цели.Мне также интересно, если бы материализованное представление было бы лучшим вариантом для определения индекса для него.
Обновление: Что касается предлагаемых решений, вот планы запроса для выполнения операторов при добавлении
CREATE UNIQUE INDEX tasks_idx1 ON tasks (ID ASC, SEQ DESC);
CREATE UNIQUE INDEX tasks_idx2 ON tasks (STATE, SEQ);
Я получаю следующий план:
Для измененного оператора select я получаю следующий план, который кажется более эффективным, ноработает немного медленнее, чем вышеуказанный выбор: