Должен ли SELECT… FOR UPDATE всегда содержать ORDER BY?

Допустим, мы выполняем ...

SELECT * FROM MY_TABLE FOR UPDATE

... и в MY_TABLE более одной строки.

Теоретически, если дваconcurrent Транзакции выполняют этот оператор, но происходит обход (и, следовательно, блокировка) строк в другом порядке, может возникнуть тупик. Например:

Transaction 1: Locks row A. Transaction 2: Locks row B. Transaction 1: Attempts to lock row B and blocks. Transaction 2: Attempts to lock row A and deadlocks.

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

Итак, мой вопрос: возникнет ли когда-нибудь этот теоретический тупик на практике? Я знаю, что есть способыискусственно вызвать его, но могло ли это когда-либо произойти при нормальной работе? Должны ли мы просто всегда использовать ORDER BY, или это действительно безопасно опускать?

Меня в первую очередь интересует поведение Oracle и MySQL / InnoDB, но комментарии к другим СУБД также будут полезны.

--- EDIT ---

Вот как воспроизвести тупик под Oracle, если порядок блокировки не тот же:

Создайте тестовую таблицу и заполните ее некоторыми тестовыми данными ...

CREATE TABLE DEADLOCK_TEST (
    ID INT PRIMARY KEY,
    A INT 
);

INSERT INTO DEADLOCK_TEST SELECT LEVEL, 1 FROM DUAL CONNECT BY LEVEL <= 10000;

COMMIT;

... из одного сеанса клиента (я использовал SQL Developer), запустите следующий блок:

DECLARE
    CURSOR CUR IS 
        SELECT * FROM DEADLOCK_TEST
        WHERE ID BETWEEN 1000 AND 2000 
        ORDER BY ID 
        FOR UPDATE;
BEGIN
    WHILE TRUE LOOP
        FOR LOCKED_ROW IN CUR LOOP
            UPDATE DEADLOCK_TEST 
            SET A = -99999999999999999999 
            WHERE CURRENT OF CUR;
        END LOOP;
        ROLLBACK;
    END LOOP;
END;
/

Изdifferent сеанс клиента (я просто запустил еще один экземпляр SQL Developer), запустите тот же блок, но сDESC вORDER BY, Через несколько секунд вы получите:

ORA-00060: deadlock detected while waiting for resource

Кстати, вы, вероятно, достигнете того же результата, полностью удаливORDER BY (так что оба блока идентичны), и добавление ...

ALTER SESSION SET OPTIMIZER_INDEX_COST_ADJ = 1;

... перед одним блоком, но ...

ALTER SESSION SET OPTIMIZER_INDEX_COST_ADJ = 10000;

... перед другим (поэтому Oracle выбирает разные планы выполнения и, вероятно, выбирает строки в другом порядке).

Это показывает, что блокировка действительно выполняется, когда строки выбираются из курсора (а не для всего набора результатов сразу, когда курсор открыт).

Ответы на вопрос(3)

Ваш ответ на вопрос