2011-02-05 58 views
1

在努力避免自動序列號等在這個特定的數據庫或那樣的原因,我想知道,如果任何人都可以看到任何問題與此:此INSERT是否可能導致任何鎖定/併發問題?

INSERT INTO user (label, username, password, user_id) 
SELECT 'Test', 'test', 'test', COALESCE(MAX(user_id)+1, 1) FROM user; 

我使用PostgreSQL(也嘗試作爲數據庫不可知論儘可​​能)..

編輯: 有兩個原因,我想要做到這一點。

  • 保持對任何特定的RDBMS低依賴性。
  • 如果數據批量更新到中央數據庫,則無需擔心更新序列。

插入性能不是問題,因爲只需要這些表就可以設置表。

EDIT 2: 我與玩的想法是,數據庫中的每個表都有人產生SITECODE作爲關鍵的一部分,所以我們始終有一個複合鍵。這有效地對SiteCode上的數據進行分區,並允許從特定站點獲取數據並將其放在其他地方(顯然在同一數據庫結構中)。例如,這將允許將各種操作站點備份到一箇中央數據庫上,但也允許該中央數據庫具有使用它的操作站點。 我仍然可以使用序列,但它似乎凌亂。實際的INSERT會看起來更象這樣:

INSERT INTO user (sitecode, label, username, password, user_id) 
SELECT 'SITE001', 'Test', 'test', 'test', COALESCE(MAX(user_id)+1, 1) 
FROM user 
WHERE sitecode='SITE001'; 

如果是有道理的.. 我以前做過類似的東西,它工作得很好,但是在這種情況下,中央數據庫是從未操作(這是更多的是集中查看數據/分析的方式),所以它不需要生成ID。

編輯-3: 我開始覺得這是簡單的永遠只允許中央數據庫是主動的,或僅備份只,從而完全避免了問題,並允許更簡單設計。

哦,回到繪圖板!

+1

無關的說明:您正在數據庫中存儲明文密碼? – Tomalak 2011-02-05 11:01:28

+0

只有在短期內,至少我現在的擔心。 – Mark 2011-02-05 11:06:14

+1

如果因某種原因不喜歡序列,則可以使用UUID – 2011-02-05 11:31:26

回答

1

你的目標是一個很好的目標。避免使用IDENTITY和AUTOINCREMENT列意味着避免整個管理問題。這裏只是one example的衆多。

  • 然而,在所以大多數響應者不會欣賞它,流行的(而不是技術)響應「始終堅持的一切舉動的Id AUTOINCREMENT列」。

  • 下一個序列號很好,所有供應商都對其進行了優化。

  • 只要這段代碼在一個事務中,它應該是這樣的,兩個用戶將不是得到相同的MAX()+1值。編碼事務時需要理解一個稱爲隔離級別的概念。

  • 充分利用user_id,併到一個更有意義的關鍵遠如ShortNameStateUserNo,甚至更好(前者傳播爭,後者避免了接下來的順序完全競爭的,相關的高容量系統)。

  • 什麼MVCC承諾,它實際提供什麼,是兩個不同的東西。只需瀏覽網頁或搜索即可查看PostcreSQL/MVCC的數百個問題。在計算機領域,物理定律是適用的,沒有任何東西是免費的。 MVCC存儲所有觸摸行的私人副本,並在交易的末尾解決衝突,導致更多的回滾。鑑於2PL塊在開始交易,並等待,沒有海量存儲的副本。

    • 大多數人MVCC的實際經驗不推薦用於高爭,高容量系統。

第一個示例碼塊是好的。

根據註釋,此項不再適用:第二個示例代碼塊有問題。 「SITE001」不是複合鍵,它是複合柱。不要這樣做,將「SITE」和「001」分成兩列。如果「SITE」是一個固定的重複值,它可以被消除。

2

是的,我可以看到一個巨大的問題。 不要這樣做。

多個連接可以同時獲得確切的相同ID。我將添加「負載下」,但它甚至不需要 - 只需要兩個查詢之間正確的時間。

爲了避免它,你可以使用交易或鎖定具體到每一個DB機制或隔離級別,但一旦我們到達那個階段,你還不如用特定於DBMS的序列/識別/自動編號等

編輯

question edit2,沒有理由擔心在user_ID的差距,所以你必須在所有站點一個序列。如果差距都OK,有些選項

  • 保證使用UPDATE語句,如(SQL Server中)

更新tblsitesequenceno設置@nextnum = nextnum = nextnum + 1

多個來電對此聲明各自保證獲得唯一編號。

  • 使用產生的身份/順序/自動編號(DB特定)的單個表

如果你不能在所有的有差距,可以考慮使用一個交易機制,而你正在運行,這將限制訪問max()查詢。要麼是使用動態SQL使用單個序列的相同技術進行操作的(具有標識列/具有自動編號的表的序列/表)。

+0

好點,忘了+1 ;-) – Mark 2011-02-05 11:34:55

2

有幾個要點:

  • Postgres使用多版本併發控制(MVCC),以便讀者從來沒有在作家等,反之亦然。但是,每次寫入時都會發生序列化。如果您打算將大量數據加載到系統中,請查看COPY命令。它比運行大量的INSERT報表要快得多。
  • 如果user_id列中有索引,MAX(user_id)可以用索引來回答,並且可能是。但實際的問題是,如果兩個交易在同一時間開始,他們將看到相同的值MAX(user_id)。它引導我到下一點:
  • 處理數字,如user_id's的規範方式是使用SEQUENCE's。這些本質上是一個你可以從中繪製下一個用戶標識的地方。如果您真的擔心生成下一個序號的性能,可以爲每個線程生成一批批次,然後僅在耗盡時請求新批次(有時稱爲HiLo序列)。
  • 您可能希望將user_id打包得越來越好,但我認爲您應該嘗試擺脫這一點。原因是,刪除user_id無論如何都會創建一個洞。所以如果序列沒有嚴格增加,我不會太擔心。
0

不同的用戶可以擁有相同的user_id,併發SELECT語句將看到相同的MAX(user_id)。

如果你不想使用序列,你必須使用一個額外的表中的單個記錄每一次你需要一個新的唯一ID時更新此單記錄:

CREATE TABLE my_sequence(id INT); 

BEGIN; 
UPDATE my_sequence SET id = COALESCE(id, 0) + 1; 
INSERT INTO 
    user (label, username, password, user_id) 
SELECT 'Test', 'test', 'test', id FROM my_sequence; 
COMMIT; 
0

我同意maksymko,但不是因爲我不喜歡序列或自動增加數字,因爲他們有自己的位置。如果你需要一個值在整個「各種操作站點」是唯一的,即不僅在單個數據庫實例的範圍內,全局唯一標識符是一個健壯,簡單的解決方案。

2

通過一切手段使用序列來生成唯一的數字。它們速度快,交易安全可靠。

「序列生成器」的任何自寫實現對於多用戶環境來說都是不可擴展的(因爲您需要進行大量鎖定)或者根本不正確。

如果您確實需要獨立於DBMS,那麼請創建一個抽象層,使用支持它們的那些DBMS的序列(Posgres,Oracle,Firebird,DB2,Ingres,Informix,...)和一個自寫的生成器那些不。

試圖創建一個比獨立於DBMS的系統,只是意味着如果不利用每個DBMS的優勢,它將在所有系統上運行同樣緩慢。

相關問題