sqlserver 主键生成策略的问题
想问问各位大侠 你们用sqlserver的时候 是怎么生成主键的
我这里的话 表的主键是用存储过程生成 一般是
日期+6位号 比如今天的生成应该是121023000001 ,121023000002 ,121023000003 等,到了明天就是 121024000001,121024000002等
每个表都是这样通过一个存储过程来生成主键,但是随着并发量的增加 程序就会出现 阻塞、死锁等问题。
有时候还会丢数据 这个是非常大单的。
现在有没有什么好的其他办法。
我能想到的 1 换数据库 sql2000 升级到 sql2005或 2008
2 换新的服务器 我这个是IBM 3650 志强2.2G 8G内存
3 根本上换这个主键生成的策略
因为生成主键的时候 是要锁表的,一旦并发,就问题来了。如果改成系统自动获取主键不知道行不行,是不是就没有 阻塞、死锁 这些问题了。
现在头都大了 麻烦各位高手指点迷津!谢谢!
[最优解释]
通过升级版本来完全避免死锁等问题是不现实的,由于关系数据库需要保证数据一致性,所以等待甚至阻塞是无法避免的。
主键上的日期部分可以通过convert/cast对getdate来转换得到。后面那些自增的标识,可以通过存储过程里面的IDENT_CURRENT/SCOPE_IDENTITY函数来获取最大,然后加1.
http://blog.csdn.net/dba_huangzj/article/details/7685162
[其他解释]
end
update CreateID set CreateID=@CreateID where TableName = @TableName
end
if @@ERROR<>0
begin
ROLLBACK TRANSACTION
set @CreateID=''
RETURN
end
commit TRANSACTION
select @CreateID as CreateID
end
GO
楼上的高手 帮我看看我这个生成主键的存储过程有什么问题吗?
[其他解释]
第一个问题,没有注释,第二个问题,貌似太复杂了,事务太多的话容易阻塞,可以考虑把整个操作放到一个事务里面去
[其他解释]
引用水哥的
-->Title:得到普通流水编号的函数
-->Author:wufeng4552
-->Date :2009-10-20
if object_id('tb','U')is not null drop table tb
if exists(select * from dbo.sysobjects where id=object_id(N'[dbo].[f_GetBH]')and xtype in(N'FN', N'IF', N'TF'))
drop function [dbo].[f_GetBH]
GO
create function f_GetBH()
returns varchar(8)
as
begin
return(select right(1000001+isnull(right(max(BH),6),0),6) from tb with (xlock,paglock) )
end
go
--建表
create table tb(BH varchar(8) primary key default dbo.f_GetBH(),ID int)
insert tb(ID) select 1
insert tb(ID) select 2
insert tb(ID) select 3
delete tb where id=2
insert tb(ID) select 4
select * from tb
/*
BH ID
-------- -----------
000001 1
000003 3
000004 4
*/
-->Title:得到日期编号的函数
-->Author:wufeng4552
-->Date :2009-10-20
if object_id('tb','U')is not null drop table tb
if exists(select * from dbo.sysobjects where id=object_id(N'[dbo].[f_GetRQBH]')and xtype in(N'FN', N'IF', N'TF'))
drop function [dbo].[f_GetRQBH]
GO
create function f_GetRQBH()
returns varchar(10)
as
begin
declare @dt varchar(6)
select @dt=convert(varchar(6),getdate(),12)
return
(select @dt+right(1000001+isnull(right(max(BH),3),0),3) from tb with (xlock,paglock) where bh like @dt +'%')
end
go
--建表
create table tb(BH varchar(10) primary key default dbo.f_GetRQBH(),ID int)
insert tb(ID) select 1
insert tb(ID) select 2
insert tb(ID) select 3
delete tb where id=2
insert tb(ID) select 4
select * from tb
/*
BH ID
---------- -----------
091020001 1
091020003 3
091020004 4
*/
-->Title:使用编号表生成流水号
-->Author:wufeng4552
-->Date :2009-10-20
IF OBJECT_ID('TB_NO','U')IS NOT NULL DROP TABLE TB_NO
GO
CREATE TABLE tb_NO(
Name char(2) PRIMARY KEY, --编号种类的名称
Head nvarchar(10) NOT NULL DEFAULT '', --编号的前缀
CurrentNo int NOT NULL DEFAULT 0, --当前编号
BHLen int NOT NULL DEFAULT 6, --编号数字部分长度
DESCRIPTION NVARCHAR(50)) --编号种类说明
INSERT tb_NO SELECT 'CG','CG',1,4,N'采购订单'
UNION ALL SELECT 'CJ','CJ',1,4,N'采购进货'
UNION ALL SELECT 'JC','JC',1,4,N'进仓单'
UNION ALL SELECT 'ZC','ZC',1,4,N'转仓单'
UNION ALL SELECT 'CC','CC',1,4,N'出仓单'
GO
IF OBJECT_ID('P_NEXTBH','P')IS NOT NULL DROP PROC P_NEXTBH
GO
CREATE PROC p_NextBH
@Name char(2), --编号种类
@BH nvarchar(20) OUTPUT --新编号
AS
BEGIN TRAN
UPDATE tb_NO WITH(ROWLOCK) SET
@BH=convert(char(8),getdate(),112)+RIGHT(POWER(10,BHLen)+CurrentNo,BHLen),
CurrentNo=CurrentNo+1
WHERE Name=@Name
COMMIT TRAN
GO
--获取 CJ 的新编号
DECLARE @bh char(11)
EXEC p_NextBH 'jc',@bh OUT
SELECT @bh
/*
------
CJ0001
*/
s
CREATE PROCEDURE CreateID
@TableName varchar(50) --输入参数 表的名 我的每个表通过这个获得主键
AS
begin
declare @LastID varchar(50)
declare @CreateID varchar(12)
SET LOCK_TIMEOUT 3600
begin TRANSACTION
select @LastID = CreateID from CreateID with (rowlock) where TableName = @TableName --获取CreateID表中 当前表的最新值
if @@ERROR<>0 --如果异常 回滚
begin
ROLLBACK TRANSACTION
set @CreateID=''
RETURN
end -- 回滚结束
set @CreateID =convert(char(6),getdate(),12)+'000001' --获得当前表的第一条记录
if @LastID is null --如果是新表 则生成createid表一条新的记录
begin
set @CreateID=convert(char(6),getdate(),12)+'000001'
insert CreateID (TableName,CreateID) values( @TableName,@CreateID)
end -- 生成新记录结束
else
begin -- 如果不是新当天第一条记录 则原记录 + 1
if left(@LastID,6) = convert(char(6),getdate(),12)
begin
set @CreateID=convert(char(6),getdate(),12)+replace(str(substring(@LastID,7,6) + 1,6),' ','0')
end
update CreateID set CreateID=@CreateID where TableName = @TableName --更新表的当前记录
end
if @@ERROR<>0
begin
ROLLBACK TRANSACTION
set @CreateID=''
RETURN
end
commit TRANSACTION
select @CreateID as CreateID -- 输出给程序调用
--种子表 num_tb
if object_id('num_tb') is not null
drop table num_tb
go
create table num_tb(d datetime,id int)
insert num_tb select getdate(),1
if object_id('tb') is not null
drop table tb
go
create table tb(id varchar(20),name varchar(10))
create clustered index idx_clu_tb on tb(id)
go
create trigger tri_tb on tb
INSTEAD OF INSERT
as
begin
set nocount on
declare @i int,@id varchar(20),@j int
select @i=count(*) from inserted
begin tran
update num_tb with(TABLOCKX) set
id=(case when convert(char(8),d,112)=convert(char(8),getdate(),112)
then id+@i else @i end),
@j=(case when convert(char(8),d,112)=convert(char(8),getdate(),112) then id else 0 end),
d=getdate()
commit tran
select * into #t from inserted
update #t set id=convert(varchar(8),getdate(),112)+right('00000'+rtrim(@j),5),@j=@j+1
insert tb select * from #t
end
go
--插入记录测试
insert into tb(name) values('张三')
insert into tb(name) values('李四')
select * from tb
/*
id name
-------------------- ----------
2010012700002 张三
2010012700003 李四
*/
insert into tb select '2010012700003','王五'
/*
id name
-------------------- ----------
2010012700002 张三
2010012700003 李四
2010012700004 王五
*/