La Force d'Oracle pour revenir en HAUT à N lignes avec SKIP VERROUILLÉ

Il y a un quelques questions sur la façon de mettre en œuvre une file d'attente-comme la table (verrouiller des lignes, la sélection d'un certain nombre d'entre eux, et le fait de sauter actuellement verrouillé lignes) dans Oracle et SQL Server.

Comment puis-je garantir que j'ai récupérer un certain nombre (N) lignes, en supposant qu'au moins N lignes éligibles?

De ce que j'ai vu, Oracle s'applique la WHERE prédicat avant de déterminer quelles lignes à ignorer. Cela signifie que si je veux tirer une ligne d'une table, et deux threads simultanément exécuter le SQL, on ne va le recevoir de la ligne et de l'autre un jeu de résultats vide (même si il y a plusieurs lignes).

C'est contraire à la façon dont SQL Server s'affiche pour gérer la UPDLOCK, ROWLOCK et READPAST indicateurs de verrou. Dans SQL Server, TOP apparaît comme par magie à limiter le nombre d'enregistrements après avec succès la réalisation de serrures.

Note, deux articles intéressants ici et ici.

ORACLE

CREATE TABLE QueueTest (
    ID NUMBER(10) NOT NULL,
    Locked NUMBER(1) NULL,
    Priority NUMBER(10) NOT NULL
);

ALTER TABLE QueueTest ADD CONSTRAINT PK_QueueTest PRIMARY KEY (ID);

CREATE INDEX IX_QueuePriority ON QueueTest(Priority);

INSERT INTO QueueTest (ID, Locked, Priority) VALUES (1, NULL, 4);
INSERT INTO QueueTest (ID, Locked, Priority) VALUES (2, NULL, 3);
INSERT INTO QueueTest (ID, Locked, Priority) VALUES (3, NULL, 2);
INSERT INTO QueueTest (ID, Locked, Priority) VALUES (4, NULL, 1);

En deux sessions distinctes, exécuter:

SELECT qt.ID
FROM QueueTest qt
WHERE qt.ID IN (
    SELECT ID
    FROM
        (SELECT ID FROM QueueTest WHERE Locked IS NULL ORDER BY Priority)
    WHERE ROWNUM = 1)
FOR UPDATE SKIP LOCKED

Noter que la première renvoie une ligne, et la deuxième session ne renvoie pas une ligne:

Session 1

 ID 
---- 
4 

Session 2

 ID 
---- 

SQL SERVER

CREATE TABLE QueueTest (
    ID INT IDENTITY NOT NULL,
    Locked TINYINT NULL,
    Priority INT NOT NULL
);

ALTER TABLE QueueTest ADD CONSTRAINT PK_QueueTest PRIMARY KEY NONCLUSTERED (ID);

CREATE INDEX IX_QueuePriority ON QueueTest(Priority);

INSERT INTO QueueTest (Locked, Priority) VALUES (NULL, 4);
INSERT INTO QueueTest (Locked, Priority) VALUES (NULL, 3);
INSERT INTO QueueTest (Locked, Priority) VALUES (NULL, 2);
INSERT INTO QueueTest (Locked, Priority) VALUES (NULL, 1);

En deux sessions distinctes, exécuter:

BEGIN TRANSACTION
SELECT TOP 1 qt.ID
FROM QueueTest qt
WITH (UPDLOCK, ROWLOCK, READPAST)
WHERE Locked IS NULL
ORDER BY Priority;

Noter que les deux sessions de retour d'une autre ligne.

Session 1

 ID 
---- 
4 

Session 2

 ID 
---- 
3 

Comment puis-je obtenir un comportement similaire dans Oracle?

  • Je vais vous donner la prime à quelqu'un qui peut me donner une simple réponse de Gary Myers avec son curseur, comme je veux oublier le curseur en tant que bien, tout comme l'OP
InformationsquelleAutor Travis | 2011-05-24