SQL для обновления пропустить заблокированный запрос и многопоточность Java - как это исправить - PullRequest
2 голосов
/ 21 июля 2011
SELECT 
        id
        FROM table_name tkn1,
        (SELECT 
            id, 
            ROWNUM rnum
         FROM table_name 
         WHERE 
            PROCS_DT is null
         order by PRTY desc, CRET_DT) result 
        WHERE  tkn1.id= result.id
        AND result.rnum <= 10 FOR UPDATE OF tkn1.id SKIP LOCKED

Вот моя проблема.2 потока одновременно обращаются к этому запросу

Поток 1 - выполняет выбор и блокирует 10 строк в порядке убывания приоритета и даты создания.Затем я бы обновил procs_dt как текущую дату из отдельного запроса.

Поток 2 - перед обновлением procs_dt или коммита из потока 1 этот поток выполняет этот запрос.Мое требование состоит в том, что следующие 10 разблокированных строк должны быть переданы потоку 2. Но на самом деле происходит то же самое, что тот же набор заблокированных строк получается из внутреннего запроса, поскольку procs_dt по-прежнему равен нулю и еще не обновлен потоком 1, а посколькузаблокирован во внешнем запросе, все эти 10 строк пропущены, и никакие записи не возвращаются для потока 2 для обработки

В конечном итоге это противоречит моему требованию о многопоточности.

Как исправить этот запрос?Я попытался добавить пропущенный заблокированный внутренний запрос.Но оракул 11g не позволяет.

Эксперты, пожалуйста, помогите.Я использую оракул 11g

Ответы [ 3 ]

5 голосов
/ 21 июля 2011

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

create table gm_temp
as select rownum id, table_name obj_name, date '2011-01-01' + rownum create_date 
from all_tables where rownum < 500;

CREATE TYPE tab_number IS TABLE OF NUMBER;

DECLARE
  cursor c_table IS 
    SELECT id FROM gm_temp ORDER BY create_date DESC FOR UPDATE OF id SKIP LOCKED;
  t_table_src tab_number := tab_number();
BEGIN
  OPEN c_table;
  FETCH c_table BULK COLLECT INTO t_table_src LIMIT 10;
  CLOSE c_table;
  dbms_output.put_line(':'||t_table_src.count||':'||t_table_src(1));
END;

На самом деле, я бы сначала посмотрел, будет ли лучше обрабатывать ВСЕ ожидающие строки как набор, чем многопоточность.

Тогда, если бы я решил, что мне нужна какая-то многопоточность, я бы посмотрел на конвейерные функции с включенной параллелью (при условии, что я был на Enterprise Edition).

1 голос
/ 02 июля 2014

просто удалите result.rnum <= 10 из вашего состояния where. Пропустить заблокированный механизм на самом деле работает по-другому. даже если вы удалите rownum из вашего запроса, он блокирует не все строки, а «извлеченные» строки. Таким образом, вместо использования rownum = 10, просто установите fetchSize равным 10. Он будет делать то, что вам нужно. </p>

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

Дайте мне знать, если возможно, пропустите заблокированное исполнение, спасибо.

0 голосов
/ 04 июля 2013

Для вашего решения вы все равно можете заказать свои записи, но если вам не нужно обновлять записи именно в этом порядке, я имею в виду, что он может быть почти на 98 процентов упорядочен или что-то вроде этого в зависимости от размера ваших записей. Вы можете попробовать ниже решение выбрать ваши записи немного случайно

Решение:

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

SELECT * FROM (SELECT * FROM таблицы ORDER BY dbms_random.value), ГДЕ rownum = 1

Так что, если вы установите rownum, как показано ниже, вы можете обойти проблему с производительностью. Увеличивая rownum, вы можете уменьшить возможности.

ВЫБРАТЬ * ИЗ (ВЫБРАТЬ Я бы FROM table_name tkn1, (ВЫБРАТЬ Я бы, ROWNUM rnum FROM table_name ГДЕ PROCS_DT является нулевым упорядочить по PRTY desc, CRET_DT) результат ГДЕ tkn1.id = result.id AND result.rnum <= 1000 ORDER BY dbms_random.value) ГДЕ РОУНУМ <= 10 </p>

после обновления строк после их выбора. Если вы не можете обновить, это означает, что другая транзакция уже использовала его. Затем Вам следует попытаться получить новую строку и обновить ее статус. Кстати, получить одну и ту же строку двумя разными транзакциями можно за 0,001, поскольку rownum - 1000.

...