2014-02-05 17 views
1

我正在處理一個大型的SQL Server數據庫,這是建立在主鍵值的計數器表的基礎上的。每個表在此計數器表中都有一行,其中包含PK名稱和下一個要用作主鍵(用於該表)的值。我們目前得到的計數值的方法是這樣的:SQL Server中「計數器」表的最佳實現

BEGIN TRAN 
UPDATE CounterValue + 1 
SELECT Counter Value 
COMMIT TRAN 

這作品大多很好,因爲在開始交易,然後更新該行的過程中,鎖定行/頁/表(鎖定ISN水平對於這個話題來說太重要了),直到交易被提交。

這裏的問題是,如果事務長時間保持打開狀態,訪問該表/頁/行的時間太長。我們有在單個事務中可能出現數百個插入的情況(需要訪問此計數器表)。

解決此問題的一個嘗試是始終使用應用程序中不會保持事務處於打開狀態的單獨連接。訪問表和事務處理會很快,所以訪問表通常是可用的。這裏的問題是,使用觸發器可能也需要訪問這些計數器值,這是一個相當不合理的規則。換句話說,我們有觸發器也需要計數器值,而這些觸發器有時在較大的父事務處理的上下文中運行。

解決此問題的另一個嘗試是使用SQL Server應用程序鎖來序列化對錶/行的訪問。大多數情況下也是如此,但有缺點。這裏最大的缺點之一還涉及觸發器。由於觸發器在觸發查詢的上下文中運行,應用程序鎖將被鎖定,直到任何父事務完成。

因此,我試圖找出一種方法來序列化訪問行/表可以從應用程序或SP /觸發器,永遠不會運行在父事務的上下文中運行。如果父母交易回滾,我不需要計數器值回滾。總是可用的情況下,如果父事務處理回滾,則快速訪問計數器值比丟失一些計數器值要重要得多。

我應該指出,我完全意識到使用GUID值或標識列可以解決我的很多問題,但正如我所提到的,我們正在討論一個龐大的系統,其中包含大量的數據,在合理的時間範圍內改變,而不會給我們的客戶帶來很大的痛苦(我們正在談論成百上千萬行的數百張表)。

有關實現這種櫃檯表的最佳方法的任何想法,將不勝感激。請記住 - 訪問應始終可用於許多應用程序,服務,觸發器和其他SP,並且阻塞很少。

編輯 - 我們可以假設的SQL Server 2005+

+0

您正在使用什麼版本的SQL Server? –

+2

SQL Server 2012最終支持序列。我非常肯定,那些在引擎之外構建的任何東西都更加健壯和快速。因此,如果您不在SQL Server 2012上,升級可能比實施和維護本土解決方案更便宜。 –

+0

您仍然可以使用標識列而不更改其他表格。就像'CREATE TABLE counter(counter INT IDENTITY(1,1)PRIMARY KEY);',然後'INSERT INTO counter DEFAULT VALUES; SELECT @@ SCOPE_IDENTITY; DELETE FROM counter WHERE counter = @@ SCOPE_IDENTITY;',也許? – hvd

回答

0

系統目前工作在不可擴展的方式。你已經注意到了你自己。這裏有偏好的粗糙爲了一些解決方案:

  1. 使用的IDENTITY列(可以設置IDENTITY屬性不重建表在網上搜索,看看如何。)
  2. 使用序列
  3. 使用Hi-Lo ID生成(What's the Hi/Lo algorithm?)。簡而言之,ID(應用程序實例)的消費者在單獨的事務中檢查大範圍的ID(如100)。該方案的開銷非常低。

與下面您的評論的約束工作:可以實現可擴展的計數器一代甚至一個單一的交易,並沒有應用程序級的變化。這是一種最後的手段措施。

將計數器條紋。對於每個表格,你有100個計數器。計數器N跟蹤符合ID % 100 = N的ID。所以每個計數器都跟蹤所有ID的1/100。

當你想取一個ID,你從隨機選擇的計數器。這個計數器沒有被併發事務使用的機會很好。由於SQL Server中的行級鎖定,您將幾乎沒有阻塞。

您將計數器N初始化爲N並將其增加100.這將確保所有計數器生成不同的ID範圍。

計數器0生成0, 100, 200, ...。計數器1生成1, 101, 201, ...。等等。 這樣做的缺點是您的ID現在不是順序的。在我看來,應用程序不應該依賴這個,因爲它不是一個可靠的屬性。

您可以將所有這一切抽象爲單個過程調用。代碼的複雜性實際上並沒有那麼大。您基本上只是生成一個附加的隨機數並更改增量邏輯。

+0

是的,我完全同意我們目前的方案不能很好地擴展! 1.標識列將成爲一個問題,不僅僅是爲了轉換數據,而是針對不期待它的應用程序級邏輯。這需要我們在這裏更改很多代碼。 2.是!是!這看起來正是我們所需要的。問題是它只在SQL Server 2012中受支持,對吧? 3.我認爲這不會對我們有好處。消費者通常不需要大塊,並且還需要我們進行大規模的應用程序級別更改。 – Ron

+0

@Ron我已經添加了一個適用於您強加的(極端)設計限制的想法。我希望我已經解釋得很好。 – usr

0

一種方法是讓在一個聲明中增加計數器的值:

DECLARE @NextKey int 

UPDATE Counter 
SET @NextKey = NextKey + 1, 
    NextKey = @NextKey 
+0

這並不解決縮放問題,因爲對計數器表的訪問仍然是序列化的。 – usr

+0

@D Stanley - 我認爲這是一種更優雅的方式來編寫我的查詢,但不幸的是,它不能解決觸發器在父事務中運行的問題。由於數據很髒並且在事務中運行,它仍然會鎖定表/行。 – Ron