检索和更新存储过程中的第一行 - 由多个进程访问
Posted
技术标签:
【中文标题】检索和更新存储过程中的第一行 - 由多个进程访问【英文标题】:Retrieve and update the top row in a stored proc - accessed by multiple process 【发布时间】:2013-08-14 21:15:49 【问题描述】:我正在考虑创建一个可被多个进程访问的存储过程,并想知道在这两种解决方案之间,哪个更好还是有第三种解决方案?
目标是在status字段中找到最大值的记录。 status 字段包含十进制值,但定义为 varchar。一旦找到合适的记录,然后更新相同的记录(存储过程只能更新一条记录)。
存储的proc会以select语句的形式返回cusip。
解决方案:01
Declare @Cusiptable(Cusip varchar(100));
UPDATE cusiptbl
SET processingdate = GetDate() ,
Status = 'In Progress',
batchid = @batchid_given,
Output Inserted.Cusip into @Cusiptable
From
(
select top(1) Cusip from cusiptbl where batchid = -1
order by cast(status as decimal(18,4)) desc
) Seconds
where cusiptbl.cusip = Seconds.cusip
select Cusip from @Cusiptable
解决方案 02:
select top(1) @CusipToBeUpdated = Cusip from cusiptbl
with (UPDLOCK)
where batchid = -1
order by
(case when isnumeric(status) = 1 then
cast(status as decimal(18,7)) end)
desc
-- Update the status to given batchid and status as 'In Progress'
UPDATE cusiptbl
SET batchid = @batchid_given,
processingdate = GetDate() ,
Status = 'In Progress'
where cusiptbl.cusip= @CusipToBeUpdated
and batchid = -1
Select @CusipToBeUpdated Cusip
【问题讨论】:
【参考方案1】:在为非数字值评估 order by cast(status as decimal(18,4))
时,第一个查询将失败。
使用isnumeric(status) = 1
重写它以防止错误:
From
(
select top(1) Cusip from cusiptbl
where batchid = -1 AND isnumeric(status) = 1
order by cast(status as decimal(18,4)) desc
) Seconds
假设事务隔离级别为已提交读或更高,这两种解决方案都应该工作。 从 varchar 转换为 numeric 会阻止使用索引(如果有的话),如果您的表很大,那么您可以考虑向表中添加一个虚拟列,例如:
create table cusiptbl(
......
status varchar(50),
status_numeric as case when isnumeric(status) = 1 then
cast(status as decimal(18,7)) else null end
)
并在此虚拟列上创建索引:
create index num_status on cusiptbl( status_numeric )
或者可能是复合索引(因为您的查询使用 batchid=-1 条件过滤行,然后按状态对选定行进行排序):
create index num_status_batch on cusiptbl( batchid, status_numeric )
然后重写查询并使用其中的虚拟列,例如:
From
(
select top(1) Cusip from cusiptbl
where batchid = -1 and status_numeric is not null
order by status_numeric desc
) Seconds
【讨论】:
感谢您的宝贵时间。 如果我使用解决方案:02,我确实会遇到死锁问题。努力寻找替代解决方案。ISNUMERIC
确定字符串是否可以转换为 any 数字类型,因此对于 特定 类型的使用不可靠。例如,ISNUMERIC
将为 '.'
返回 1,但无法转换为 decimal
。不过还有其他方法,可以在here 和here 找到一些好的建议。以上是关于检索和更新存储过程中的第一行 - 由多个进程访问的主要内容,如果未能解决你的问题,请参考以下文章