выберите только новую строку в оракуле - PullRequest
2 голосов
/ 23 марта 2010

У меня есть таблица с "varchar2" в качестве первичного ключа.
У него около 1 000 000 транзакций в день.

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

  1. У вас есть идея, как сделать запрос с хорошей производительностью?
    Я могу добавить новый столбец при необходимости.

  2. Как вы думаете, что этот процесс должен делать?

    • PLSQL?
    • Java

Ответы [ 10 ]

3 голосов
/ 23 марта 2010

Все здесь действительно очень близки. Тем не менее:

Скотт Бэйли ошибается в использовании растрового индекса, если таблица находится под какой-либо непрерывной загрузкой DML. Это совершенно неподходящее время для использования растрового индекса.

Ответ всех остальных о столбце PROCESSED CHAR(1) check in ('Y','N') правильный, но отсутствует способ его индексации; Вы должны использовать индекс на основе функций, например:

CREATE INDEX MY_UNPROCESSED_ROWS_IDX ON MY_TABLE
  (CASE WHEN PROCESSED_FLAG = 'N' THEN 'N' ELSE NULL END);

Затем вы запросите его, используя то же выражение:

SELECT * FROM MY_TABLE
 WHERE (CASE WHEN PROCESSED_FLAG = 'N' THEN 'N' ELSE NULL END) = 'N';

Причиной использования индекса на основе функций является то, что Oracle не записывает записи индекса для индексируемых значений NULL, поэтому приведенный выше индекс на основе функций будет содержать только строки с PROCESSED_FLAG = 'N'. Когда вы обновите свои строки до PROCESSED_FLAG = 'Y', они будут «выпадать» из индекса.

2 голосов
/ 23 марта 2010

Ах, я очень не хочу добавлять другой ответ, когда другие так близко подошли к нему. Но

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

Астандер тут же, но ему нужно несколько предостережений. Добавить новый столбец needs_processed CHAR (1) DEFAULT 'Y' и добавить индекс BITMAP. Для столбцов с низкой мощностью («Y» / «N») растровый индекс будет быстрее. Как только у вас есть отдых, это довольно легко. Но вы должны быть осторожны, чтобы не выбирать новые строки, обрабатывать их и помечать их как обработанные за один шаг. В противном случае во время обработки могут быть вставлены строки, помеченные как обработанные, даже если они не были обработаны.

Самый простой способ - использовать pl / sql для открытия курсора, который выбирает необработанные строки, обрабатывает их и затем обновляет строку как обработанную. Если у вас есть отвращение к движущимся курсорам, вы можете собрать pk или rowids во вложенную таблицу, обработать их, а затем обновить, используя вложенную таблицу.

2 голосов
/ 23 марта 2010

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

Тогда запрос должен быть только для тех строк, которые были недавно добавлены, а не обработан .

Это легко сделать с помощью SQL-запросов.

0 голосов
/ 16 июня 2016

Я думаю, что это решение должно работать .. Что нужно сделать, выполнив следующие шаги

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

вставить в new_table (max_rowid) как (Выберите max (rowid) из вашей таблицы);

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

Выберите * из вашей таблицы, где rowid> (выберите max_rowid из новой_таблицы);

Как только вы закончите обработку вышеуказанного запроса, просто обрежьте new_table и вставьте max (rowid) из вашей таблицы.

Я думаю, что это должно работать и было бы самым быстрым решением;

0 голосов
/ 26 марта 2010

Как насчет использования Материализованных журналов просмотра ?У вас есть много вариантов игры:

SQL> create table test (id_test number primary key, dummy varchar2(1000));

Table created

SQL> create materialized view log on test;

Materialized view log created

SQL> insert into test values (1, 'hello');

1 row inserted

SQL> insert into test values (2, 'bye');

1 row inserted

SQL> select * from mlog$_test;

   ID_TEST SNAPTIME$$  DMLTYPE$$ OLD_NEW$$ CHANGE_VECTOR$$
---------- ----------- --------- --------- ---------------------
         1 01/01/4000  I         N         FE
         2 01/01/4000  I         N         FE

SQL> delete from mlog$_test where id_test in (1,2);

2 rows deleted

SQL> insert into test values (3, 'hello');

1 row inserted

SQL> insert into test values (4, 'bye');

1 row inserted

SQL> select * from mlog$_test;

   ID_TEST SNAPTIME$$  DMLTYPE$$ OLD_NEW$$ CHANGE_VECTOR$$
---------- ----------- --------- --------- ---------------
         3 01/01/4000  I         N         FE
         4 01/01/4000  I         N         FE
0 голосов
/ 26 марта 2010

Я в значительной степени согласен с ответом Адама.Но я бы хотел провести серьезное тестирование по сравнению с альтернативой.

Проблема, которую я вижу, заключается в том, что вам нужно не только выбирать строки, но и обновлять эти строки.Хотя это должно быть довольно быстро, я бы хотел избежать обновления.И избегайте больших транзакций (см. Ниже).

В качестве альтернативы можно добавить системную дату по умолчанию CREATE_DATE.Индекс это.А затем выберите записи, где create_date> = (дата / время начала вашего предыдущего выбора).

Но у меня недостаточно данных об относительной стоимости установки системной даты в качестве значения по умолчанию и установки значения Y, обновления функции на основе индекса даты и выбора диапазона для даты противконкретный выбор по одному значению для Y. Вы, вероятно, захотите сохранить статистику или намекнуть запрос, чтобы использовать индекс для столбца Y / N, и определенно захотите использовать подсказку для столбца даты - статистикана столбце даты почти наверняка будет старый.

Если данные также постоянно добавляются в таблицу, в том числе в течение периода выполнения запроса, необходимо следить за контролем транзакций.В конце концов, вы не хотите читать 100 000 записей с флагом = Y, а затем обновлять 120 000, в том числе 20 000, поступивших при выполнении запроса.

В случае флага есть два простых способа: SET TRANSACTION перед вашим выбором и фиксацией после вашего обновления, или начните с обновления от Y до Q, затем сделайте свой выбор для тех, которые являются Q, изатем обновите до N. Согласованность чтения Oracle - это замечательно, но с ней нужно обращаться осторожно.

Для версии столбца даты, если вы не возражаете против риска обработки нескольких строк более одного раза, просто обновитетаблица с последней обработанной датой / временем непосредственно перед вашим выбором.

Если в таблице не так много информации, рассмотрите возможность ее организации в индекс.

0 голосов
/ 25 марта 2010

Почему бы не создать дополнительную таблицу, содержащую два столбца. Столбец ID и столбец обработанного флага. Сделайте триггер вставки в исходную таблицу, поместите его ID в эту новую таблицу. Ваш процесс регистрации может затем выбрать записи из этой новой таблицы и пометить их как обработанные. Окончательно удалите обработанные записи из этой таблицы.

0 голосов
/ 24 марта 2010

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

0 голосов
/ 23 марта 2010

"Astander" в значительной степени сделал работу за вас. Вам нужно ALTER вашу таблицу, чтобы добавить еще один столбец ( скажем, PROCESSED) ..

Вы также можете рассмотреть возможность создания INDEX на PROCESSED ( a bitmap index может иметь некоторое преимущество, поскольку возможное значение может быть только 'y' и 'n', но проверьте его ), чтобы при запросе он использовал INDEX.

Также, если вы уверены, что вы запрашиваете только каждые 5 минут, проверьте, можете ли вы добавить еще один столбец с типом TIMESTAMP и разбейте на нем таблицу. ( не уверен, проверьте снова ).

Я бы также подумал о написании работы или чего-то подобного и написал бы, используя UTL_FILE, и показал бы его, если это возможно.

0 голосов
/ 23 марта 2010

В мире MS SQL Server, где я работаю, в наших таблицах есть столбец «версия» типа «отметка времени».

Итак, чтобы ответить на вопрос № 1, я бы добавил новый столбец.

Чтобы ответить # 2, я бы сделал это в plsql для производительности.

Mark

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...