簡體   English   中英

在sybase中,如何鎖定正在執行的存儲過程並更改該存儲過程返回的表?

[英]In sybase, how would I lock a stored procedure that is executing and alter the table that the stored procedure returns?

我有一張桌子,如下所示:

id    status
--    ------
1     pass
1     fail
1     pass
1     na
1     na

另外,我有一個存儲過程,該過程返回一個表,其中前100條記錄的狀態為“ na”。 該存儲過程可由環境中的多個節點調用,我不希望它們獲取重復的數據。 因此,我想在執行過程中鎖定存儲過程,並將從存儲過程中獲取的記錄的狀態設置為“進行中”,然后返回該表,然后釋放該鎖,以使不同的節點不會獲取相同的內容數據。 我將如何完成?

在ms sql中已經有針對類似問題的解決方案,但在sybase中使用時會顯示錯誤。

我不確定100%如何在Sybase中執行此操作。 但是,想法如下。

首先,在表中添加一個新列,該列代表用於更改數據的會話或連接。 您將使用此列提供隔離。

然后, 更新行:

update top (100) t
    set status = 'in progress',
        session = @session
    where status = 'na'
    order by ?;  -- however you define the "top" records

然后,您可以返回或處理給定連接的“進行中”的100個ID。

  1. 創建另一個具有一行的表proc_lock
  2. 當控制進入存儲過程時,啟動一個事務並在proc_lock中的行上進行選擇以進行更新(請參閱鏈接)。 如果這對於Sybase不起作用,則可以嘗試使用此答案中的技術鎖定行。
  3. 在該過程退出之前,請確保提交事務。

這樣可以確保一次只有一個用戶可以執行該過程。 當第二個用戶嘗試執行proc時,它將阻塞直到釋放第一個用戶對proc_lock行的鎖定(例如,提交事務時)

假設Sybase ASE ...

您可能要考慮的更大的問題是,是要在獲取前100行時使用單個進程來鎖定整個 ,還是希望其他進程仍然訪問該表?

另一個問題是,您是否希望多個進程同時從表中拉出100行而不互相阻塞?

我將假設您a)不想鎖定整個表,並且b)您可能希望允許多個進程同時從表中提取行。

1-如果可能,請確保該表正在使用數據鎖定(默認通常是allpages ); 這將減小鎖定到行級別的粒度(而不是所有頁面的頁面級別); 如果要允許多個進程同時查找/更新表中的行,則該表將需要是數據

2 -確保鎖升級桌子上設置足夠高,以確保單個進程的100行的更新不鎖表( sp_setpglockpromote 所有頁sp_setrowlockpromote數據行 ); 這里的關鍵是確保您的update不會升級到表級鎖!

3-到時候要抓取100行的集合時...要在事務內...用會話唯一的statusupdate 100行,選擇關聯的id ,然后更新status再次顯示為“進行中”

該操作的要旨如下所示:

declare @mysession varchar(10)

select  @mysession = convert(varchar(10),@@spid)  -- replace @@spid with anything that
                                                  -- uniquely identifies your session
set rowcount 100  -- limit the update to 100 rows

begin tran get_my_rows

    -- start with an update so that get exclusive access to the desired rows;
    -- update the first 100 rows you find with your @@spid

    update mytable
    set    status = @mysession   -- need to distinguish your locked rows from
                                 -- other processes; if we used 'In Progress'
                                 -- we wouldn't be able to distinguish between
                                 -- rows update earlier in the day or updated
                                 -- by other/concurrent processes

    from   mytable readpast      -- 'readpast' allows your query to skip over
                                 -- locks held by other processes but it only
                                 -- works for datarows tables
    where  status = 'na'

    -- select your reserved id's and send back to the client/calling process

    select  id
    from    mytable
    where   status = @mysession

    -- update your rows with a status of 'In Progress'

    update mytable
    set    status = 'In Progress'
    where  status = @mysession

commit            -- close out txn and release our locks

set rowcount 0    -- set back to default of 'unlimited' rows

潛在問題:

  • 如果您的表很大,並且沒有status索引,那么查詢所花的時間可能比運行查詢所需的時間長; 通過確保鎖升級足夠高並且您正在使用數據鎖定(因此readpast有效),無論查找所需行需要多長時間,您都應該看到對其他進程的最小阻塞

  • status列上有一個索引,請考慮所有這些update將強制執行許多索引更新,這可能會導致某些昂貴的延遲更新

  • 如果使用數據並且鎖升級太低,則更新可能會查看整個表,這將導致另一個(並發)進程重新readpast表鎖,並且找不到要處理的行

  • 如果使用所有頁面 ,則將無法使用readpast因此並發進程將阻塞您的鎖(即,它們將無法讀取您的鎖)

  • 如果您具有status的索引,並且有多個並發進程鎖定表中的不同行,則可能會發生死鎖(可能在status列的索引的索引樹中),這又需要您編碼客戶端/應用程序以預期並解決死鎖

想一下:

  • 如果表相對較小,以至於表掃描成本不高,則可以在status列上刪除任何索引,這將減少延遲更新的性能開銷(與更新索引有關)

  • 如果您可以使用特定於會話的status值(例如,“進行中-@mysession”),則可以消除第二條update語句(如果在索引status列上進行延遲更新,可以派上用場)

  • 如果表中還有另一列可用於唯一標識會話的行(例如, last_updated_by_spid = @@ spid, last_updated_date = @mydate-其中@mydate最初設置為getdate() ),則第一次update可以將status設置為'In Progress',則select會將@@ spid和@mydate用作where子句,並且不需要第二次update [注意:實際上,這是Gordon試圖解決的相同問題他的session專欄。]

  • 假設您可以使用特定於會話的status值,請考慮使用一些可以跟蹤和修復孤立行的方法(例如,行status保持為“進行中-@mysession”,因為調用進程已死亡且從未返回到(重新)設置狀態)

  • 如果您可以將id列表作為連接的id值的單個字符串傳遞回調用程序,則可以使用此答案中概述的方法在第一次更新期間將id附加到@variable中,以設置status =第一次更新中為“進行中”,還可以消除select和第二次update

  • 您如何知道哪些行被孤立了? 您可能希望能夠使用發布update時的getdate()來更新(small)datetime列; 然后,如果您通常希望status在5分鍾之內更新,則可以進行監視,以查找status為'In Progress'且距上一個status已超過10分鍾的孤立行。 update

如果數據readpast ,鎖升級設置和/或死鎖可能性太大,並且您可以在表上使用短暫的表級鎖,則可以讓該進程在執行updateselect語句之前獲取表級獨占鎖。 ; 排他鎖需要在用戶定義的事務中獲取,以便在工作期間“持有”該鎖; 一個簡單的例子:

begin tran get_my_rows

    -- request an exclusive table lock; wait until it's granted

    lock table mytable in exclusive mode

    update ...

    select ...

    update ...

commit

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM