当数据库负载很重时,max(column_name) 返回相同的值
max(column_name) is returning same value whne the load is heavy on database
下面的查询不断被命中,记录被插入 table "TRANSACTION_MAIN"
但是 @confrm
比 max(TRN_CNFRM_NBR)
多的数字对于几个事务,只有当数据库服务器上的负载过高时才会看到此行为。对此有任何见解,为什么会观察到这种行为,幕后可能发生了什么?
BEGIN TRANSACTION
DECLARE @Confrm as int;
SET @Confrm = (SELECT isnull
(MAX(CONVERT(int, TRN_CNFRM_NBR)),0)
FROM TRANSACTION_MAIN WHERE
TRN_UC_LOC = @1) + 1;
DECLARE @TMID as int;
INSERT INTO TRANSACTION_MAIN(
TRN_CNFRM_NBR
,TRN_UC_LOC
,TRN_STAT_ANID
,TRN_SRC_ANID
,PRSN_ANID
,TRN_DT
,TRN_ACTL_AMT
,TRN_MTHD
,TRN_IP_ADDR
,DSCT_CD
,TRN_PAID_AMT
,CSHR_ANID
,INVDEPTEQUIP_ANID
,TRN_CMNT
,CPN_DSCT_TOTAL
)
VALUES(@Confrm,@1,@2,@3,@4,@5,@6,@7,@8,@9,@10,@11,@12,@13,@14);
SET @TMID = @@IDENTITY;");
COMMIT TRANSACTION
你加错了1。
查询应该是这样的:
SET @Confrm = (
SELECT ISNULL(MAX(CONVERT(INT, TRN_CNFRM_NBR)), 0) + 1 -- you should add 1 here.
FROM TRANSACTION_MAIN
WHERE TRN_UC_LOC = @1
);
嗯,这不安全,所以它不起作用也就不足为奇了。
最终结果有几个贡献者。首先,最大值的同时 selects 当然会 return 相同的值,因为尚未插入 "new" 行。其次,根据事务隔离级别,select 看不到已插入但尚未提交的行。
作为快速修复,简单地将事务隔离级别设置得更高应该会有所帮助。这当然会降低你的吞吐量并增加死锁的风险,但至少它是正确的。或者,如果您使用的 SQL 服务器足够高,请使用序列。或者线程安全的 CLR 代码。
如果您使用的是旧的 SQL 服务器并且无法处理更高的事务隔离,您可以尝试使用您自己的序列来实现它,其中递增序列是一个原子操作。 Microsoft SQL Oracle 的服务器迁移助手中有一个很好的示例。
下面的查询不断被命中,记录被插入 table "TRANSACTION_MAIN"
但是 @confrm
比 max(TRN_CNFRM_NBR)
多的数字对于几个事务,只有当数据库服务器上的负载过高时才会看到此行为。对此有任何见解,为什么会观察到这种行为,幕后可能发生了什么?
BEGIN TRANSACTION
DECLARE @Confrm as int;
SET @Confrm = (SELECT isnull
(MAX(CONVERT(int, TRN_CNFRM_NBR)),0)
FROM TRANSACTION_MAIN WHERE
TRN_UC_LOC = @1) + 1;
DECLARE @TMID as int;
INSERT INTO TRANSACTION_MAIN(
TRN_CNFRM_NBR
,TRN_UC_LOC
,TRN_STAT_ANID
,TRN_SRC_ANID
,PRSN_ANID
,TRN_DT
,TRN_ACTL_AMT
,TRN_MTHD
,TRN_IP_ADDR
,DSCT_CD
,TRN_PAID_AMT
,CSHR_ANID
,INVDEPTEQUIP_ANID
,TRN_CMNT
,CPN_DSCT_TOTAL
)
VALUES(@Confrm,@1,@2,@3,@4,@5,@6,@7,@8,@9,@10,@11,@12,@13,@14);
SET @TMID = @@IDENTITY;");
COMMIT TRANSACTION
你加错了1。 查询应该是这样的:
SET @Confrm = (
SELECT ISNULL(MAX(CONVERT(INT, TRN_CNFRM_NBR)), 0) + 1 -- you should add 1 here.
FROM TRANSACTION_MAIN
WHERE TRN_UC_LOC = @1
);
嗯,这不安全,所以它不起作用也就不足为奇了。
最终结果有几个贡献者。首先,最大值的同时 selects 当然会 return 相同的值,因为尚未插入 "new" 行。其次,根据事务隔离级别,select 看不到已插入但尚未提交的行。
作为快速修复,简单地将事务隔离级别设置得更高应该会有所帮助。这当然会降低你的吞吐量并增加死锁的风险,但至少它是正确的。或者,如果您使用的 SQL 服务器足够高,请使用序列。或者线程安全的 CLR 代码。
如果您使用的是旧的 SQL 服务器并且无法处理更高的事务隔离,您可以尝试使用您自己的序列来实现它,其中递增序列是一个原子操作。 Microsoft SQL Oracle 的服务器迁移助手中有一个很好的示例。