2012-06-02 91 views
-1

解決使用多線程SQL服務器從一個單一的表中讀取,並確保使用C#使用多線程

不讀同一個記錄兩次在不同的線程,最好的辦法在SQL Server從單個表中讀取謝謝在您的幫助提前

+0

爲什麼你必須確保線程不讀取相同的記錄?出於性能原因或商業原因? @Despertar是正確的,因爲我們需要更多的細節來幫助。 – bluevector

回答

2

你們是不是要並行從表中讀取記錄,以加快檢索數據,還是你只是擔心與訪問相同的數據線數據損壞?

像MSSQL處理併發非常好,所以在這方面的線程安全數據庫管理系統是不是你會在你的代碼予以關注,如果你有多發性線程讀取相同的表。

如果你想沒有任何重疊,你可以運行具有分頁功能的SQL命令來讀取並行數據,只是讓每個線程讀取不同的頁面。你可以說20個線程一次讀取20個不同的頁面,並且可以保證它們不讀取相同的行。然後你可以連接數據。頁面尺寸越大,創建線程的性能提升越多。

efficient way to implement paging

0

假設SQL Server上的依賴,你可能看SQL Server服務中介功能,爲排隊你。有一點要在與該想到的是,當前的SQL Server Service Broker是不適用於SQL Azure的,所以如果你對移動到Azure雲這可能是一個問題的計劃。

反正 - 與SQL Server服務代理的併發訪問是在數據庫引擎層管理。另一種做法是讓一個線程讀取數據庫,然後將該消息作爲輸入分派線程。這比試圖在數據庫中使用事務來確保消息不被讀取兩次要容易得多。

就像我雖然說,SQL Server服務代理可能是要走的路。或者一個適當的外部排隊機制。

0

解決方案1:
我假設你正在嘗試處理或從大的表中提取數據。如果我分配了這個任務,我會先看看分頁。如果您試圖在線程中分割工作。因此,線程1處理頁面0到10,線程2處理頁面11到20等等,或者您可以使用實際的rownumber對行進行批處理。所以在你的存儲過程中,你會這樣做;

WITH result_set AS (
    SELECT 
    ROW_NUMBER() OVER (ORDER BY <ordering>) AS [row_number], 
    x, y, z 
    FROM 
    table 
    WHERE 
    <search-clauses> 
) SELECT 
    * 
FROM 
    result_set 
WHERE 
    [row_number] BETWEEN @IN_Thread_Row_Start AND @IN_Thread_Row_End; 

這將是更高效的另一種選擇是,如果你有一個自然的關鍵,還是不錯的替代品,是網頁使用,並在關鍵參數螺紋通,而不是把它記錄有興趣(或頁碼)。

這種解決方案迫切關注的是:

  1. ROW_NUMBER性能
  2. CTE性能(我相信他們存儲在內存中)

因此,如果這是我的問題,以解決我會通過一個鍵看分頁。

解決方案2:
第二個解決辦法是,以紀念行,因爲它們的處理,幾乎鎖定他們,那就是如果你有數據寫入的權限。所以你的表會有一個叫做Processed或Locked的字段,因爲這些行是你的線程選中的,它們被更新爲Locked = 1;

然後,您從其他線程中選擇僅選擇未鎖定的行。當您的過程完成並且所有行都被處理後,您可以重置鎖。

很難說會有什麼表現最佳WO一些試驗... GL

0

這個問題是超舊,但仍然非常相關的,我花了很多時間尋找這種解決方案,所以我想ID發佈它爲別人誰沿着這發生。當使用sql表格作爲隊列而不是msmq時,這是非常常見的。

溶液(大量的調查之後)是簡單的,並且可以通過在SSMS與每個選項卡運行其自己的事務,以模擬多個進程/線程擊中相同的表2周打開的選項卡進行測試。

簡單的回答是這樣的:關鍵這是使用UPDLOCK和READPAST提示您選擇。

爲了說明沒有重複的讀取操作,請查看這個簡單的示例。

--on在SSMS標籤1

begin tran 
SELECT TOP 1 ordno FROM table_queue WITH (updlock, readpast) 

--on標籤2 SSMS

begin tran 
SELECT TOP 1 ordno FROM table_queue WITH (updlock, readpast) 

你會發現,第一個選定的記錄已被鎖定,並沒有得到通過選擇複製聲明觸發第二個選項卡/進程。

現在在現實世界中你不會只執行對你的表像上面的簡單的例子,一個選擇。如果您將表格用作隊列,則會將您的記錄更新爲「isprocessing = 1」或類似的內容。上面的代碼只是表明這允許併發讀取而沒有重複。

所以在現實世界中(如果您正在使用表作爲隊列和處理這個隊列,例如多個服務),你會在一個子查詢最有可能執行你的選擇爲更新語句。

就是這樣。

begin tran 
    update table_queue set processing= 1 where myId in 
    (
     SELECT TOP 50 myId FROM table_queue WITH (updlock, readpast) 
    ) 

commit tran 

您還可以結合夜更新與輸出關鍵字聲明,所以你現在已經被鎖定所有ID(處理= 1)的列表,這樣你就可以與他們合作。

,如果你正在處理使用表作爲隊列中的數據,這將確保你不會沒有任何需要分頁或其他任何複製在你的SELECT語句記錄。

該解決方案在我們經歷了很多重複的在我們的SELECT語句時由許多不同的機器上運行許多服務正在監控的企業級應用進行測試。