【发布时间】:2011-09-01 07:33:23
【问题描述】:
有一个fewquestions关于如何在Oracle和SQL Server中实现一个类似队列的表(锁定特定行,选择一定数量的行,跳过当前锁定的行)。
假设至少有 N 行符合条件,我如何保证检索到一定数量的 (N) 行?
据我所知,Oracle 在确定要跳过哪些行之前应用了WHERE 谓词。这意味着如果我想从表中提取一行,并且两个线程同时执行相同的 SQL,一个将接收该行,另一个将接收一个空结果集(即使有更多符合条件的行)。
这与 SQL Server 处理UPDLOCK、ROWLOCK 和READPAST 锁定提示的方式相反。在 SQL Server 中,TOP 似乎神奇地限制了在成功获得锁后的记录数。
甲骨文
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);
在两个单独的会话中,执行:
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
注意第一个返回一行,第二个会话不返回一行:
会话 1
ID ---- 4第 2 节
ID ----SQL 服务器
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);
在两个单独的会话中,执行:
BEGIN TRANSACTION
SELECT TOP 1 qt.ID
FROM QueueTest qt
WITH (UPDLOCK, ROWLOCK, READPAST)
WHERE Locked IS NULL
ORDER BY Priority;
请注意,两个会话都返回不同的行。
会话 1
ID ---- 4第 2 节
ID ---- 3如何在 Oracle 中获得类似的行为?
【问题讨论】:
-
我将赏金给可以给我一个比 Gary Myers 更简单的答案的人,因为我也想省略光标,就像 OP 一样
标签: sql sql-server oracle queue