我寫了一個查詢來自動增加新記錄的序列號,它在單個呼叫中作業正常。
insert into testTable (sequence_no)
case when exists (select sequence_no from testTable)
then (select top(1) sequence_no 1 from testTable order by sequence_no desc)
else '1'
end as sequence_no
然后我在上面添加一個執行緒注釋,回圈 100000 次,打開 2 個執行緒并同時運行它。
執行緒1:
declare @cnt INT =0;
while @cnt<100000
begin
insert into testTable (sequence_no, thread_no)
case when exists (select sequence_no from testTable)
then (select top(1) sequence_no 1 from testTable order by sequence_no desc)
else '1'
end as sequence_no, '1' as thread_no
SET @cnt = @cnt 1;
END;
執行緒2:
declare @cnt INT =0;
while @cnt<100000
begin
insert into testTable (sequence_no, thread_no)
case when exists (select sequence_no from testTable)
then (select top(1) sequence_no 1 from testTable order by sequence_no desc)
else '1'
end as sequence_no, '2' as thread_no
SET @cnt = @cnt 1;
END;
結果大約 70% 請求成功,其他失敗
違反 PRIMARY KEY 約束“sequence_no”。無法在物件“dbo.testTable”中插入重復鍵。
我認為如果我在每個請求上使用一個事務就可以解決,但結果是相似的,大約 70% 的成功,而其他的由于 PK 重復而失敗。
這是否意味著我的做法不利于序列號生成?
有人可以給我改進嗎?
uj5u.com熱心網友回復:
每個 RDBMS 系統通常都有自己的“自動編號”(通常用于 PrimaryKeys)設定。
MySql、Ms-Sql-Server、ORACLE(文章顯示了每種語法的 3 種不同的語法……僅在一個 url 上)
https://www.w3schools.com/sql/sql_autoincrement.asp
PostGres:
https://chartio.com/resources/tutorials/how-to-define-an-auto-increment-primary-key-in-postgresql/
您的問題帶有 (microsoft)sql-server 標記,因此我將其粘貼。
SQL Server 的語法 以下 SQL 陳述句將“PersonKey”列定義為“Person”表中的自增主鍵欄位:
CREATE TABLE dbo.Person ( PersonKey int IDENTITY(1,1) PRIMARY KEY, LastName varchar(255) NOT NULL, FirstName varchar(255) );
不要重新發明輪子。
因此,除非您(嘗試)在 < 2 秒內插入一百萬行......使用已經存在的內容。
意見。
您不應該關心每個主鍵是否完全按順序排列。又名,“差距”應該沒問題。
如果你認為你需要完美的測序,你需要問自己“為什么”。
主鍵必須是唯一的。有“順序”有助于索引。
但
訂購了 1,2,3,6,7,9,11。(4,5,8 不見了,但它們不見了真的很重要嗎?)
我要補充一點,自 2016 版以來,Sql Server 女士已經添加了“序列”(或者是 2014 年?)
https://docs.microsoft.com/en-us/sql/relational-databases/sequence-numbers/sequence-numbers?view=sql-server-2016
有理由選擇其中之一。
https://www.sqlshack.com/difference-between-identity-sequence-in-sql-server/
2 美分的解釋是序列可以提供一系列值。而且它不系結到單個表(就像身份一樣)。
但實際上,您最終會在值中有更多“間隙”......因為一旦請求序列,就永遠不會重新生成相同的值......即使 INSERT 的潛在行實際上并未使其成為插入行。
uj5u.com熱心網友回復:
問題 ( ) 中的第一個例子sequence_no 1是如何不去做!相反,SQL Server 有兩種方法可以做到這一點,并且都可以接受:
將該列定義為標識列,并從
INSERT完全省略它:insert into testTable (thread_no) VALUES ('1')創建一個Sequence,并使用序列中的值:
insert into testTAble(sequence_no, thread_no) VALUES (NEXT VALUE FOR testTableSequence, '1')
同樣,在任何情況下,您都不應嘗試使用TOP 1 sequence_no 1or MAX(sequence_no) 1。這在 SQL Server 中是錯誤的(實際上,在 MySql 中也是錯誤的)。
uj5u.com熱心網友回復:
對于并發訪問,如果你希望你的代碼沒有任何例外成功,必須在事務執行的時候用一個排他鎖來鎖定所有的表。所以你必須重寫你的代碼:
BEGIN TRANSACTION;
insert into testTable WITH (XLOCK, TABLOCK, HOLDLOCK) (sequence_no)
SELECT case when exists (select sequence_no from testTable)
then (select top(1) sequence_no 1 from testTable order by sequence_no desc)
else '1'
end as sequence_no;
COMMIT
但是,這對于并發訪問來說將是災難性的……鎖定所有表需要時間,引發爭用,產生死鎖!
這就是為什么 RDBMS 提供內部增量作為 SQL ISO 標準的一部分的 IDENTITY 或 SEQUENCES
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/491575.html
