SQL利用Function創(chuàng)建長整形的唯一ID示例代碼
前言
在設(shè)計表的時候考慮主鍵的數(shù)據(jù)類型是長整形還是字符串,最簡單的方式當(dāng)然是newid(),但這也有個問題,就是主鍵長度過長(36個字),數(shù)據(jù)量一多,必然會影響數(shù)據(jù)庫操作的效率,而且大大增加了數(shù)據(jù)文件和索引文件所占用的空間。而且,newid返回的字符串是隨機(jī)的,查詢結(jié)果不能保證按保存順序返回。這對于有順序要求的系統(tǒng)來說,需要額外增加順序列來進(jìn)行排序,這也導(dǎo)致查詢語句更加復(fù)雜。這也是主要放棄newid作為主鍵的主要原因。因此考慮用長整形來作數(shù)據(jù)表主鍵的數(shù)據(jù)類型。
實現(xiàn)方法
一開始在C#等面向?qū)ο裾Z言中編寫一個獲取PK的方法,那是很順序就完成了。
接著是SQL中,如果要用腳本導(dǎo)入數(shù)據(jù),那就要提供一個SQL的方法來獲取PK。
最初設(shè)計PK的組成:時間(yyMMddHHmmssmsS) + '4位隨機(jī)數(shù)' ,于是卡卡很快完成dbo.pk()
Create function dbo.pk() returns bigint as begin declare @pk as bigint,@fix bigint,@idx int,@ts as datetime set @ts = GETDATE() set @pk = convert(bigint,convert(varchar(6),@ts,12) + replace(convert(varchar(12),@ts,114),':',''))*10000 select @idx = A*10000 from vRand return (@pk + @idx) end go
然后來獲取一個10000PK測試:
declare @tab as table(pk bigint) declare @i as integer set @i =0 while(@i<10000) begin insert @tab select dbo.pk() set @i = @i+1 end select pk,count(1) cnt from @tab group by pk having COUNT(1)>1
oh my god!竟然有30多個重復(fù)的。
可見這個方法,做為獲取單個PK,那問題不大,但在做批量保存的時候,可能會發(fā)生主鍵沖突。
因此再設(shè)計一個支持批量保存的。
既然4位隨機(jī)數(shù)不能保證毫秒級的唯一,那就只能用有序數(shù)了,把PK的組成改為:時間(yyMMddHHmmssmsS) + '4位有序數(shù)'
再考慮到年份只是2位數(shù),跟面向?qū)ο裰械腜K組成有機(jī)會在202x年之后存在沖突,因此增加一個標(biāo)識 ‘1'+yy作為年以延長千年蟲問題,雖然還是有機(jī)會發(fā)生沖突,但那也是幾百年以后的事情了。
但是為了保持效率和沖突的概率,還是將PK改為:'1'+時間(yyMMddHHmmssms) + '4位有序數(shù)'.
接下來又是一頓卡卡卡,dbo.pks(@count)已出:
CREATE function dbo.pks(@count as int) returns @pks table(pk bigint,id int) as begin declare @pk as bigint,@fix bigint,@idx int,@ts as datetime,@lop int,@i int set @ts = GETDATE() set @pk = convert(bigint,'1'+convert(varchar(6),@ts,12) + replace(convert(varchar(11),@ts,114),':',''))*10000 set @idx =0 set @lop = CEILING(@count/10000.0) set @i = 1 while(@lop >0) begin set @pk = @pk + 10000 set @idx = 0 while(@idx<10000 and @idx<@count) begin insert @pks(pk,id) values(@pk+@idx,@idx+ @i) set @idx = @idx +1 end set @lop = @lop -1 set @i = @i+10000 end return end go
批量測試一下
select * from dbo.pks(500000)
正常返回500000行,沒有一行重復(fù)!
在返回的結(jié)果列中,ID是從1開始編號的,這也保持與SQL的Row_number保持一致,方便SQL編程引用。
OK,到這里用利用SQL function獲取PK就搞定了!
總結(jié)
以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,如果有疑問大家可以留言交流,謝謝大家對腳本之家的支持。
相關(guān)文章
關(guān)系型數(shù)據(jù)庫的設(shè)計規(guī)則詳解
大家好,本篇文章主要講的是關(guān)系型數(shù)據(jù)庫的設(shè)計規(guī)則詳解,感興趣的同學(xué)趕快來看一看吧,對你有幫助的話記得收藏一下,方便下次瀏覽2021-12-12使用SQL語句查詢MySQL,SQLServer,Oracle所有數(shù)據(jù)庫名和表名,字段名
本文例出了使用SQL語句查詢MySQL,SQLServer,Oracle所有數(shù)據(jù)庫名和表名的SQL語句,有需要的可以參考下2018-03-03使用Navicat連接opengauss數(shù)據(jù)庫完整步驟(詳細(xì)圖文)
Navicat是一套快速、可靠并價格相當(dāng)便宜的數(shù)據(jù)庫管理工具,專為簡化數(shù)據(jù)庫的管理及降低系統(tǒng)管理成本而設(shè),下面這篇文章主要給大家介紹了關(guān)于使用Navicat連接opengauss數(shù)據(jù)庫的完整步驟,需要的朋友可以參考下2024-02-02DBCC SHRINKDATABASEMS SQL數(shù)據(jù)庫日志壓縮方法
DBCC SHRINKDATABASEMS SQL數(shù)據(jù)庫日志壓縮方法...2007-07-07只有兩個字段用一個sql語句查詢出某個學(xué)生的姓名、成績以及在表中的排名
這篇文章主要介紹了只有兩個字段用一個sql語句查詢出某個學(xué)生的姓名、成績以及在表中的排名,需要的朋友可以參考下2014-08-08達(dá)夢數(shù)據(jù)庫如何設(shè)置自增主鍵的方法及注意事項
這篇文章主要介紹了達(dá)夢數(shù)據(jù)庫如何設(shè)置自增主鍵的方法及注意事項的相關(guān)資料,在達(dá)夢數(shù)據(jù)庫中實現(xiàn)自增字段通常需要使用序列(sequence)和觸發(fā)器(trigger),需要的朋友可以參考下2024-09-09面向云服務(wù)的GaussDB全密態(tài)數(shù)據(jù)庫現(xiàn)狀及問題小結(jié)
全密態(tài)數(shù)據(jù)庫,顧名思義與大家所理解的流數(shù)據(jù)庫、圖數(shù)據(jù)庫一樣,就是專門處理密文數(shù)據(jù)的數(shù)據(jù)庫系統(tǒng),這篇文章主要介紹了面向云服務(wù)的GaussDB全密態(tài)數(shù)據(jù)庫,未來GaussDB會將該能力逐步開源到openGauss,與社區(qū)共同推進(jìn)和完善全密態(tài)數(shù)據(jù)庫解決方案,一起打造數(shù)據(jù)庫安全生態(tài)2024-02-02