我正在使用基于 MS SQL Server 的 ERP 系统。它有一个装运提交流程,该流程使用 99 个临时表来执行其工作。这项工作需要是原子的——这一切都需要发生或不应该发生。这个特殊的存储过程会影响数据库中最大的表。编写程序的方式不能很好地扩展。在下午提交大量发货的所有大型客户中,SQL Server 的运行速度显着放缓。当没有负载时,这个过程需要 <1 秒。当许多用户 (15-30) 提交发货时,该过程需要 > 1 分钟。
我有兴趣重写该过程以在负载下提高性能。
所有临时表都有索引和/或聚集索引。
我一直在对过程中使用的永久表周围的索引进行性能调整。
我正在寻找一种更好的架构,它可以保持整个流程的原子性,同时让它更好地扩展。似乎有些临时表将只保存少量记录(< 100),而有些将保存大量记录(> 10,000 但<100,000)(我还没有完成工作来根据经验确定这一点这点)。我看到的替代方案如下:
- 将一些临时表移动到表变量中以将数据保存在内存中
- 将部分过程移到从 SQL 调用的基于 CLR 的过程中(也许某些逻辑在过程代码中的执行速度比在 t-sql 中更快)
请让我知道更具体的信息,这将有助于推动这个问题。
附加信息(约翰·普特曼——2013 年 7 月 9 日)
我跟踪执行以查看在此过程的运行中启动和提交的 user_transactions——在处理 SP 时启动和提交了多个事务——大多数都嵌套在调用堆栈中的 SP 中。调用堆栈最多嵌套 9 级(包括触发器时)。大约有 27 个不同的事务被启动和提交。事务不是嵌套的。系统使用逻辑锁表来防止其他用户(进程)在执行存储过程时编辑与“发货”记录相关的记录。
这是存储的主存储过程的片段,以感受代码的味道(注意一些错误记录代码已被删除):
DELETE #tciTransToCommit
FROM #tciTransToCommit WITH (NOLOCK)
JOIN tsoPendShipment ps WITH (NOLOCK) ON #tciTransToCommit.TranKey = ps.ShipKey
WHERE ps.TranType NOT IN (@TRANTYPE_SHIPMENT,
@TRANTYPE_SHIPMENT_TRNSFR,
@TRANTYPE_CUSTOMER_RETURN,
@TRANTYPE_SHIPMENT_DROP_SHIP)
OPTION (KEEPFIXED PLAN)
-- Make sure transactions are still in tsoPendShipment
DELETE #tciTransToCommit
FROM #tciTransToCommit WITH (NOLOCK)
LEFT OUTER JOIN tsoPendShipment ps WITH (NOLOCK) ON #tciTransToCommit.TranKey = ps.ShipKey
WHERE ps.ShipKey IS NULL
OPTION (KEEPFIXED PLAN)
IF NOT EXISTS (SELECT 1 FROM #tciTransToCommit)
BEGIN
-- Nothing to process. Exit with a success.
SET @oRetVal = @kSuccess
GOTO EarlyExit
END
-- Update the PreCommitBatchKey if it is not set.
UPDATE tmp
SET PreCommitBatchKey = o.ShipmentHiddenBatchKey
FROM #tciTransToCommit tmp WITH (NOLOCK)
JOIN tsoOptions o WITH (NOLOCK) ON tmp.CompanyID = o.CompanyID
WHERE tmp.TranType IN (@TRANTYPE_SHIPMENT,
@TRANTYPE_SHIPMENT_TRNSFR,
@TRANTYPE_CUSTOMER_RETURN,
@TRANTYPE_SHIPMENT_DROP_SHIP)
AND tmp.PreCommitBatchKey = 0
OPTION (KEEPFIXED PLAN)
-- Thow away any previously used disposable batches. Use a new disposable batch every time. This is done so that
-- this procedure can properly dispose of the batch without having to rely on the caller to dispose of any batches
-- used during validations.
UPDATE tmp
SET
DispoBatchKey = NULL
FROM
#tciTransToCommit tmp WITH (NOLOCK)
OPTION (KEEPFIXED PLAN)
-- Make sure the rows in #tciTransToCommit are unique rows.
INSERT @UniqueTransToCommit (CompanyID, TranType, PostDate, InvcDate, TranKey, PreCommitBatchKey, DispoBatchKey, CommitStatus)
SELECT DISTINCT CompanyID, TranType, PostDate, InvcDate, TranKey, PreCommitBatchKey, DispoBatchKey, CommitStatus
FROM #tciTransToCommit WITH (NOLOCK)
OPTION (KEEPFIXED PLAN)
TRUNCATE TABLE #tciTransToCommit
INSERT #tciTransToCommit (CompanyID, TranType, PostDate, InvcDate, TranKey, PreCommitBatchKey, DispoBatchKey, CommitStatus)
SELECT CompanyID, TranType, PostDate, InvcDate, TranKey, PreCommitBatchKey, DispoBatchKey, CommitStatus
FROM @UniqueTransToCommit
OPTION (KEEPFIXED PLAN)
---------------------------------------------------------------------------------
-- Create the disposable batches based on the records found in #tciTransToCommit.
-- Note that a new disposable batch will be generated for each run.
---------------------------------------------------------------------------------
-- Reset RetVal to zero.
SELECT @lRetVal = 0
EXEC spciCreateInvtCommitDisposableBatch @lRetVal OUTPUT
IF @lRetVal <> @kSuccess
GOTO ErrorOccurred
---------------------------------------------------------------------------
-- Use one SessionID for all disposable batches we are about to commit to
-- assist in reporting.
---------------------------------------------------------------------------
IF COALESCE(@oSessionID, 0) <> 0
BEGIN
-- Use the SessionID passed in.
SELECT @lSessionID = @oSessionID
END
ELSE
BEGIN
-- Select the BatchKey of the first disposable batch to act as the SessionID for all batches being processed.
SELECT @lSessionID = MIN(DispoBatchKey) FROM #tciTransToCommit WITH (NOLOCK)
SELECT @oSessionID = @lSessionID
END
-- Clear the error tables and the logical lock table. Only clear the errors if they are for an existing batch.
-- Credit card processing may have already populated errors that we don't want to clear -- the batch log won't
-- exist for this session ID
DELETE tciErrorLog
FROM tciErrorLog
JOIN tciBatchLog
ON tciErrorLog.SessionID = tciBatchLog.BatchKey
WHERE SessionID = @lSessionID
OPTION (KEEPFIXED PLAN)
TRUNCATE TABLE #tciErrorLogExt
-----------------------------------------------------------------------------
-- Logical lock cleanup.
-----------------------------------------------------------------------------
EXEC spsmLogicalLockCleanup
@LOCKTYPE_SO_BATCH_RECOVERY
,@lRetVal
,1
IF @lRecTimeFlag = 1
BEGIN
SELECT GETDATE() - @lProcTime 'CreateDispoBatch'
SELECT @lProcTime = GETDATE()
END
-- The following section needs a clean #LogicalLocks temp table. The locks that were inserted above have be set aside in another temp table
-- and they will be deleted manually.
TRUNCATE TABLE #LogicalLocks
-- Do not create a logical lock when we are only validating the data.
IF @iOptValidateOnly = 0
BEGIN
-- ------------------------------------------------------
-- Create Logical Locks against the selected transaction:
-- ------------------------------------------------------
-- Place a logical lock on the transactions found in #tciTransToCommit so other
-- processes trying to commit the same transactions will get an exclusive lock error.
-- Only attempt to lock records that will be processed.
INSERT #LogicalLocks
(LogicalLockType,
UserKey,
LockType,
LogicalLockID)
SELECT
1,
TranKey,
@LOCK_MODE_EXCLUSIVE,
'SOCommitTrnxs: ' + CONVERT(VARCHAR(10), TranType) + ': ' + CONVERT(VARCHAR(10), TranKey)
FROM #tciTransToCommit WITH (NOLOCK)
WHERE CommitStatus IN (@COMMIT_STATUS_DEFAULT, @PRE_COMMIT_STATUS_SUCCESS, @COMMIT_STATUS_WARNINGS_EXISTS)
OPTION (KEEPFIXED PLAN)
-- Get the users login time
SELECT @SPIDLoginTime = login_time FROM master..sysprocesses WITH (NOLOCK) WHERE spid = @@SPID
-- If the Credit Card module is activated, it is possible that logical locks were created
-- during authorization. Do not re-create the same locks if this SP is called by the same
-- connection where the lock type (shared/exclusive) matches. Do this by updating the
-- LogicalLockKey and setting the Status column to 1. The locking SP will skip these records
-- because it thinks locks have already been creatd. Use the SPID and login time
-- to tell if this SP is called by the same connection.
UPDATE #LogicalLocks
SET LogicalLockKey = ll.LogicalLockKey,
[Status] = 1 -- Lock created. In this case already created.
FROM #LogicalLocks
JOIN tsmLogicalLock ll WITH (NOLOCK)
ON #LogicalLocks.LogicalLockID = ll.LogicalLockID
AND #LogicalLocks.LogicalLockType = ll.LogicalLockType
AND #LogicalLocks.LockType = ll.LockType
AND ll.SPID = @@SPID AND ll.LoginTime = @SPIDLoginTime
EXEC spsmLogicalLockAddMultiple @lRetVal OUTPUT, @lLocksCreated OUTPUT, @lLocksRejected OUTPUT, @CLEANUP_LOCKS_FIRST
IF (@lRetVal NOT IN (1,2))
BEGIN
--------------------------------------------------------------------------
-- At least one logical lock could not be obtained for the transactions to
-- be comitted. Log an error message and exit with success so that this
-- can be reported back to the user. Do not worry about @lLocksRejected
-- here. The next code block will report individual locks back to the
-- user.
--------------------------------------------------------------------------
-- At least one logical lock could not be obtained for the transactions.
INSERT #tciError
(EntryNo, BatchKey, StringNo,
StringData1, StringData2, StringData3,
ErrorType, Severity, TranType,
TranKey, InvtTranKey)
VALUES(
NULL,@lSessionID, 250981,
'', '', '',
2, @FATAL_ERR, NULL,
NULL, NULL)
EXEC spciLogErrors @lSessionID, @lRetVal OUTPUT, @lSessionID
SELECT @oRetVal = @kSuccess
GOTO EarlyExit
END
-- See if the locks were successfully placed for the transactions.
SELECT 1 FROM #LogicalLocks tmpll WITH (NOLOCK) JOIN #tciTransToCommit tmp ON tmpll.UserKey = tmp.TranKey WHERE tmpll.Status <> 1 OPTION (KEEPFIXED PLAN)
IF @@ROWCOUNT <> 0
BEGIN
-- Tran {0}: User {1} currently has a lock against this transaction.
INSERT #tciError
(EntryNo, BatchKey, StringNo,
StringData1, StringData2, StringData3,
ErrorType, Severity, TranType,
TranKey, InvtTranKey)
SELECT
NULL, tmp.DispoBatchKey, 100524,
ps.TranID, ll.ActualUserID, '',
2, @FATAL_ERR, tmp.TranType,
tmp.TranKey, NULL
FROM tsmLogicalLock ll WITH (NOLOCK)
JOIN #LogicalLocks tmpll WITH (NOLOCK) ON ll.LogicalLockID = tmpll.LogicalLockID AND ll.LogicalLockType = tmpll.LogicalLockType
JOIN #tciTransToCommit tmp WITH (NOLOCK) ON tmpll.UserKey = tmp.TranKey
JOIN tsoPendShipment ps WITH (NOLOCK) ON tmp.TranKey = ps.ShipKey
WHERE tmpll.Status = 102 -- Exclusive lock not created due to existing locks.
OPTION (KEEPFIXED PLAN)
-- Tran {0}: User {1} currently has a lock against this transaction.
INSERT #tciError
(EntryNo, BatchKey, StringNo,
StringData1, StringData2, StringData3,
ErrorType, Severity, TranType,
TranKey, InvtTranKey)
SELECT
NULL, tmp.DispoBatchKey, 100524,
ps.TranID, ll.ActualUserID, '',
2, @FATAL_ERR, tmp.TranType,
tmp.TranKey, NULL
FROM tsmLogicalLock ll WITH (NOLOCK)
JOIN #LogicalLocks tmpll WITH (NOLOCK) ON ll.LogicalLockID = tmpll.LogicalLockID AND ll.LogicalLockType = tmpll.LogicalLockType
JOIN #tciTransToCommit tmp WITH (NOLOCK) ON tmpll.UserKey = tmp.TranKey
JOIN tsoPendShipment ps WITH (NOLOCK) ON tmp.TranKey = ps.ShipKey
WHERE tmpll.Status NOT IN (1, 102) -- NOT(Locked Successfully, Exclusive lock not created due to existing locks)
OPTION (KEEPFIXED PLAN)
-- Mark those transactions which locks could not be created. This will exclude
-- them from the list of transactions to be processed.
UPDATE tmp
SET CommitStatus = @COMMIT_STATUS_TRAN_LOCKED
FROM #tciTransToCommit tmp WITH (NOLOCK)
JOIN #LogicalLocks ll WITH (NOLOCK) ON tmp.TranKey = ll.UserKey
WHERE ll.Status <> 1 -- Not Locked Successfully
OPTION (KEEPFIXED PLAN)
...Error logging code removed....
---------------------------------------------------------------------------
-- Create a list of batches to be committed. Each row in @UniqueBatchType
-- will require a call to the SO Posting Routines. This table drives the
-- WHILE loops within the routine. Included the @PRE_COMMIT_STATUS_SUCCESS
-- and @COMMIT_STATUS_WARNINGS_EXISTS statuses since this routine may have
-- been called a 2nd time.
---------------------------------------------------------------------------
INSERT @UniqueBatchType (CompanyID, BatchType, DispoBatchKey)
SELECT DISTINCT tmp.CompanyID, bl.BatchType, tmp.DispoBatchKey
FROM #tciTransToCommit tmp WITH (NOLOCK)
JOIN tciBatchLog bl WITH (NOLOCK) ON tmp.DispoBatchKey = bl.BatchKey
WHERE bl.PostStatus = 0 AND bl.Status = 4 -- Post status is Opened and Balanced.
AND tmp.CommitStatus IN (@COMMIT_STATUS_DEFAULT, @PRE_COMMIT_STATUS_SUCCESS, @COMMIT_STATUS_WARNINGS_EXISTS)
OPTION (KEEPFIXED PLAN)
IF @@ERROR <> 0
GOTO ErrorOccurred
---------------------------------------------------------------------------
-- Check if there is anything to process. Reasons why @UniqueBatchType
-- could be empty:
-- > Could not create a Logical Lock on ALL of the transactions.
-- > Being called a 2nd time but ALL of the transactions have at least
-- one fatal error.
---------------------------------------------------------------------------
SELECT 1 FROM @UniqueBatchType
IF @@ROWCOUNT = 0
BEGIN
--R--
SELECT @oRetVal = @kSuccess
GOTO EarlyExit
END
-----------------------------------------------------
-- Create logical locks against the disposable batch.
-----------------------------------------------------
INSERT #LogicalLocks
(LogicalLockType,
UserKey,
LockType,
LogicalLockID,
LockCleanupParam1,
LockCleanupParam2,
LockCleanupParam3)
SELECT
@LOCKTYPE_SO_BATCH_RECOVERY,
DispoBatchKey,
@LOCK_MODE_EXCLUSIVE,
'DISPOBATCHKEY: ' + CONVERT(VARCHAR(10), DispoBatchKey),
DispoBatchKey,
@oSessionID,
CompanyID
FROM @UniqueBatchType
WHERE BatchType IN (@BATCH_TYPE_SHIPMENTS, @BATCH_TYPE_RETURNS) AND COALESCE(DispoBatchKey, 0) <> 0
EXEC spsmLogicalLockAddMultiple @lRetVal OUTPUT, @lLocksCreated OUTPUT, @lLocksRejected OUTPUT, @DO_NOT_CLEANUP_LOCKS_FIRST
IF @lRetVal NOT IN (1,2)
GOTO ErrorOccurred
-- See if the locks were successfully placed for the Disposable Batch(es).
SELECT 1 FROM #LogicalLocks tmpll WITH (NOLOCK) JOIN @UniqueBatchType tmp ON tmpll.UserKey = tmp.DispoBatchKey WHERE tmpll.Status <> 1 OPTION (KEEPFIXED PLAN)
IF @@ROWCOUNT <> 0
BEGIN
-- {0}{1} Unable to Lock the Batch.
INSERT #tciError
(EntryNo, BatchKey, StringNo,
StringData1, StringData2, StringData3,
ErrorType, Severity, TranType,
TranKey, InvtTranKey)
SELECT
NULL, tmp.DispoBatchKey, 150656,
'', '', '',
2, @FATAL_ERR, NULL,
NULL, NULL
FROM tsmLogicalLock ll WITH (NOLOCK)
JOIN #LogicalLocks tmpll WITH (NOLOCK) ON ll.LogicalLockID = tmpll.LogicalLockID AND ll.LogicalLockType = tmpll.LogicalLockType
JOIN @UniqueBatchType tmp ON tmpll.UserKey = tmp.DispoBatchKey
WHERE tmpll.Status NOT IN (1, 102) -- NOT(Locked Successfully, Exclusive lock not created due to existing locks)
OPTION (KEEPFIXED PLAN)
-- If we could not create a logical lock against the disposable batch, do not continue.
IF @@ROWCOUNT <> 0
BEGIN
EXEC spciLogErrors @lSessionID, @lRetVal OUTPUT, @lSessionID
GOTO ErrorOccurred
END
END
-- -------------------------
-- Start Pre-Commit Routine:
-- -------------------------
-- The spsmLogicalLockRemoveMultiple does an inner join to tsmLogicalLock on the LogicalLockKey
-- to delete the lock. I want to set the logical lock keys to a negative number so we can control
-- which locks to remove. They will be set to a positive before the call to remove the locks.
UPDATE #LogicalLocks
SET LogicalLockKey = ABS(LogicalLockKey) * -1
FROM #LogicalLocks WITH (NOLOCK)
JOIN #tciTransToCommit tmp WITH (NOLOCK) ON #LogicalLocks.UserKey = tmp.TranKey
WHERE #LogicalLocks.Status = 1 -- Locked Successfully
OPTION (KEEPFIXED PLAN)
IF @lRecTimeFlag = 1
BEGIN
SELECT GETDATE() - @lProcTime 'LogicalLocks'
SELECT @lProcTime = GETDATE()
END
IF @lDebugFlag = 1
SELECT '#tciTransToCommit Before Pre-Commit', * FROM #tciTransToCommit WITH (NOLOCK)
SELECT @lBatchCount = MIN(BatchCount) FROM @UniqueBatchType
TRUNCATE TABLE #tglPostingDetlTran
TRUNCATE TABLE #tglPostingRpt
TRUNCATE TABLE #timPostingHolding
TRUNCATE TABLE #tarAPIValidHolding
TRUNCATE TABLE #tarAPIPendInvcHolding
TRUNCATE TABLE #tarAPIPendInvcAmtsHolding
TRUNCATE TABLE #tarAPIInvcDetlHolding
TRUNCATE TABLE #tarAPICmntOnlyHolding
TRUNCATE TABLE #tarSalesCommHolding
TRUNCATE TABLE #tciSTaxCodeTranHolding
TRUNCATE TABLE #tciSTaxTranHolding
IF COALESCE(@lBatchCount, 0) > 0
BEGIN
-- Loop through @UniqueBatchType and call the commit disposable batch routines.
WHILE @lBatchCount IS NOT NULL
BEGIN
SELECT @lCompanyID = CompanyID, @lDispoBatchKey = DispoBatchKey, @lBatchType = BatchType
FROM @UniqueBatchType WHERE BatchCount = @lBatchCount
-- Assign the transactions to be committed to the disposable batch.
UPDATE ps
SET BatchKey = tmp.DispoBatchKey,
UpdateDate = GETDATE(), UpdateUserID = @lLoginName
FROM tsoPendShipment ps WITH (NOLOCK)
JOIN #tciTransToCommit tmp WITH (NOLOCK) ON ps.ShipKey = tmp.TranKey
JOIN @UniqueBatchType bt ON tmp.DispoBatchKey = bt.DispoBatchKey
WHERE tmp.CommitStatus IN (@COMMIT_STATUS_DEFAULT,
@PRE_COMMIT_STATUS_SUCCESS,
@COMMIT_STATUS_WARNINGS_EXISTS)
AND bt.DispoBatchKey = @lDispoBatchKey
OPTION (KEEPFIXED PLAN)
IF @@ERROR <> 0
GOTO ErrorOccurred
-- Reset RetVal to zero.
SELECT @lPreCommitRetVal = 0
-- Call the routine to pre-commit the batches. This is basically the old SO pre-posting routines.
EXEC spsoPreCommitDisposableBatch @lSessionID, @lDispoBatchKey, @iOptValidateOnly, @iOptSkipValidation, @lPreCommitRetVal OUTPUT
-- Store off the records in #timPosting into #timPostingHolding for the current BatchKey.
-- We will reload #timPosting before calling spsoCommitDisposableBatch.
-- This must happen before checking @lPreCommitRetVal because UndoEverything relies on
-- #timPostingHolding being populated.
INSERT #timPostingHolding
SELECT DISTINCT * FROM #timPosting p WITH (NOLOCK)
WHERE p.BatchKey = @lDispoBatchKey
AND NOT EXISTS (SELECT 1 FROM #timPostingHolding hold WITH (NOLOCK)
WHERE (p.InvtTranKey IS NOT NULL AND p.InvtTranKey = hold.InvtTranKey) )
OPTION (KEEPFIXED PLAN)
IF @lPreCommitRetVal <> @kSuccess
...Error logging code removed....
-- Store off the records in tglPosting into #tglPostingRpt for the current BatchKey.
-- We will always use the #tglPostingRpt table to report the GL Register.
INSERT #tglPostingRpt (
AcctRefKey, BatchKey, CurrID, ExtCmnt, GLAcctKey, JrnlKey, JrnlNo, NatCurrBegBal, PostAmt, PostAmtHC,
PostCmnt, PostDate, PostQty, SourceModuleNo, Summarize, TranDate, TranKey, TranNo, TranType)
SELECT
AcctRefKey, BatchKey, CurrID, ExtCmnt, GLAcctKey, JrnlKey, JrnlNo, NatCurrBegBal, PostAmt, PostAmtHC,
PostCmnt, PostDate, PostQty, SourceModuleNo, Summarize, TranDate, TranKey, TranNo, TranType
FROM tglPosting WITH (NOLOCK) WHERE BatchKey = @lDispoBatchKey
OPTION (KEEPFIXED PLAN)
IF @@ROWCOUNT > 0
BEGIN
INSERT #tglPostingDetlTran (PostingDetlTranKey, TranType)
SELECT DISTINCT sl.InvtTranKey, s.TranType
FROM #tciTransToCommit tmp WITH (NOLOCK)
JOIN tsoPendShipment s WITH (NOLOCK) ON tmp.TranKey = s.ShipKey
JOIN tsoShipLine sl WITH (NOLOCK) ON s.ShipKey = sl.ShipKey
JOIN #tglPostingRPT gl WITH (NOLOCK) ON sl.InvtTranKey = gl.TranKey AND s.TranType = gl.TranType
WHERE tmp.CommitStatus IN (@COMMIT_STATUS_WARNINGS_EXISTS, @PRE_COMMIT_STATUS_SUCCESS)
AND tmp.TranType IN (@TRANTYPE_SHIPMENT, @TRANTYPE_SHIPMENT_TRNSFR, @TRANTYPE_CUSTOMER_RETURN)
AND gl.BatchKey = @lDispoBatchKey
OPTION (KEEPFIXED PLAN)
EXEC spglSummarizeBatchlessTglPosting @lCompanyID, @lDispoBatchKey, @lRetVal OUTPUT, 1 -- Indicate to use temp table (#tglPostingRPT)
END
INSERT #tarAPIValidHolding (AcctRefUsage,AcuityUserID,ApplyToInvcKey,BatchID,BatchKey,BatchOvrdSales,BatchOvrdSegKey,BatchOvrdSegVal,BatchType,BillToAddrKey,BillToAddrLine1,BillToAddrLine2,BillToAddrLine3,BillToAddrLine4,BillToAddrLine5,BillToAddrName,BillToCity,BillToCountry,BillToCustAddrKey,BillToPostalCode,BillToState,CheckCredit,ClassOvrdSales,ClassOvrdSegKey,ClassOvrdSegVal,CommPlanKey,CompanyID,ContactKey,CreateGL,CurrExchRate,CurrExchSchdKey,CurrID,CustAddrKey,CustClassKey,CustID,CustKey,CustPONo,CustSalesAcctKey,DocCurrID,DownPmtCustPmtKey,FOBKey,HomeCurrID,HomeRoundAmt,ImportLogKey,InclTradeDiscInSls,InputTranNo,InvcCommPlanKey,InvcFormKey,InvcKey,LastRetVal,LockID,LogSuccessful,NextEntryNo,NextSeqNo,PmtTermsKey,PriceListKey,PrimarySperKey,Printed,PrintInvcs,ReasonCodeKey,RecordNumber,ReferenceID,RoundCost,RoundDocAmt,RoundPrice,RoundQty,SameNoRangeForMemo,SeqNo,ShipAmt,ShipMethKey,ShipToAddrKey,ShipToAddrLine1,ShipToAddrLine2,ShipToAddrLine3,ShipToAddrLine4,ShipToAddrLine5,ShipToAddrName,ShipToCity,ShipToCountry,ShipToCustAddrKey,ShipToPostalCode,ShipToState,ShipZoneKey,SourceModule,Spid,STaxSchdKey,TrackSTaxOnSales,TradeDiscPct,TranCmnt,TranDate,TranID,TranNo,TranStatus,TranType,UniqueID,UseMultCurr,UseSper,DispoBatchKey)
SELECT AcctRefUsage,AcuityUserID,ApplyToInvcKey,BatchID,BatchKey,BatchOvrdSales,BatchOvrdSegKey,BatchOvrdSegVal,BatchType,BillToAddrKey,BillToAddrLine1,BillToAddrLine2,BillToAddrLine3,BillToAddrLine4,BillToAddrLine5,BillToAddrName,BillToCity,BillToCountry,BillToCustAddrKey,BillToPostalCode,BillToState,CheckCredit,ClassOvrdSales,ClassOvrdSegKey,ClassOvrdSegVal,CommPlanKey,CompanyID,ContactKey,CreateGL,CurrExchRate,CurrExchSchdKey,CurrID,CustAddrKey,CustClassKey,CustID,CustKey,CustPONo,CustSalesAcctKey,DocCurrID,DownPmtCustPmtKey,FOBKey,HomeCurrID,HomeRoundAmt,ImportLogKey,InclTradeDiscInSls,InputTranNo,InvcCommPlanKey,InvcFormKey,InvcKey,LastRetVal,LockID,LogSuccessful,NextEntryNo,NextSeqNo,PmtTermsKey,PriceListKey,PrimarySperKey,Printed,PrintInvcs,ReasonCodeKey,RecordNumber,ReferenceID,RoundCost,RoundDocAmt,RoundPrice,RoundQty,SameNoRangeForMemo,SeqNo,ShipAmt,ShipMethKey,ShipToAddrKey,ShipToAddrLine1,ShipToAddrLine2,ShipToAddrLine3,ShipToAddrLine4,ShipToAddrLine5,ShipToAddrName,ShipToCity,ShipToCountry,ShipToCustAddrKey,ShipToPostalCode,ShipToState,ShipZoneKey,SourceModule,Spid,STaxSchdKey,TrackSTaxOnSales,TradeDiscPct,TranCmnt,TranDate,TranID,TranNo,TranStatus,TranType,UniqueID,UseMultCurr,UseSper,@lDispoBatchKey
FROM #tarAPIValid WITH (NOLOCK)
OPTION (KEEPFIXED PLAN)
INSERT #tarAPIPendInvcHolding (ApplyToInvcKey,BillToAddrKey,BillToAddrLine1,BillToAddrLine2,BillToAddrLine3,BillToAddrLine4,BillToAddrLine5,BillToAddrName,BillToCity,BillToCopyKey,BillToCountry,BillToCustAddrKey,BillToPostalCode,BillToState,CommPlanKey,ConfirmToCntctKey,CurrExchRate,CurrExchSchdKey,CurrID,CustClassKey,CustKey,CustPONo,...<whole bunch more fields..>)
SELECT ApplyToInvcKey,BillToAddrKey,BillToAddrLine1,BillToAddrLine2,BillToAddrLine3,BillToAddrLine4,BillToAddrLine5,BillToAddrName,BillToCity,BillToCopyKey,BillToCountry,BillToCustAddrKey,BillToPostalCode,BillToState,CommPlanKey,ConfirmToCntctKey,CurrExchRate,CurrExchSchdKey,CurrID,CustClassKey,CustKey,CustPONo,...<whole bunch more fields..>
FROM #tarAPIPendInvc WITH (NOLOCK)
OPTION (KEEPFIXED PLAN)
INSERT #tarAPIPendInvcAmtsHolding (ActCommAmt,CalcCommAmt,CostOfSales,CreditHold,DigitsNC,DiscAmt,DiscDate,DocumentNo,DueDate,InvcKey,SalesAmt,SalesAmtHC,SeqNo,ShipAmt,ShipAmtHC,STaxAmt,STaxAmtHC,STaxTranKey,TradeDiscAmt,TradeDiscAmtHC,TranAmt,TranAmtHC,DispoBatchKey)
SELECT ActCommAmt,CalcCommAmt,CostOfSales,CreditHold,DigitsNC,DiscAmt,DiscDate,DocumentNo,DueDate,InvcKey,SalesAmt,SalesAmtHC,SeqNo,ShipAmt,ShipAmtHC,STaxAmt,STaxAmtHC,STaxTranKey,TradeDiscAmt,TradeDiscAmtHC,TranAmt,TranAmtHC,@lDispoBatchKey
FROM #tarAPIPendInvcAmts WITH (NOLOCK)
OPTION (KEEPFIXED PLAN)
INSERT #tarAPIInvcDetlHolding (AcctRefKey,ActCommAmt,BTOComponent,CalcComm,CalcCommAmt,CmntOnly,CommBase,CommClassKey,CommPlanKey,Description,DetailKey,DetailNo,DocumentNo,...<whole bunch more fields..>)
SELECT AcctRefKey,ActCommAmt,BTOComponent,CalcComm,CalcCommAmt,CmntOnly,CommBase,CommClassKey,CommPlanKey,Description,DetailKey,DetailNo,DocumentNo,...<whole bunch more fields..>
FROM #tarAPIInvcDetl WITH (NOLOCK)
OPTION (KEEPFIXED PLAN)
INSERT #tarAPICmntOnlyHolding (AcctRefKey,ActCommAmt,BTOComponent,CalcComm,CalcCommAmt,CmntOnly,CommBase,CommClassKey,CommPlanKey,Description,DetailKey,DetailNo,DocumentNo,...<whole bunch more fields..>)
SELECT AcctRefKey,ActCommAmt,BTOComponent,CalcComm,CalcCommAmt,CmntOnly,CommBase,CommClassKey,CommPlanKey,Description,DetailKey,DetailNo,DocumentNo,...<whole bunch more fields..>
FROM #tarAPICmntOnly WITH (NOLOCK)
OPTION (KEEPFIXED PLAN)
INSERT #tarSalesCommHolding (ActCommAmt,BatchKey,CalcCommAmt,CommPaidAmt,CommType,DocumentNo,EditCommAmt,OvrdUserID,SalesCommKey,Selected,SperKey,Status,SubjCOS,SubjSales,DispoBatchKey)
SELECT ActCommAmt,BatchKey,CalcCommAmt,CommPaidAmt,CommType,DocumentNo,EditCommAmt,OvrdUserID,SalesCommKey,Selected,SperKey,Status,SubjCOS,SubjSales,@lDispoBatchKey
FROM #tarSalesComm WITH (NOLOCK)
OPTION (KEEPFIXED PLAN)
INSERT #tciSTaxCodeTranHolding (ActNonRecoverAmt,ActSTaxAmt,ActUseTaxAmt,CalcNonRecoverAmt,CalcSTaxAmt,CalcUseTaxAmt,ExmptAmt,STaxCodeKey,STaxExmptNo,STaxTranKey,SubjFreightAmt,SubjSales,SubjSTaxAmt,DispoBatchKey)
SELECT ActNonRecoverAmt,ActSTaxAmt,ActUseTaxAmt,CalcNonRecoverAmt,CalcSTaxAmt,CalcUseTaxAmt,ExmptAmt,STaxCodeKey,STaxExmptNo,STaxTranKey,SubjFreightAmt,SubjSales,SubjSTaxAmt,@lDispoBatchKey
FROM #tciSTaxCodeTran WITH (NOLOCK)
OPTION (KEEPFIXED PLAN)
INSERT #tciSTaxTranHolding (STaxTranKey, STaxSchdKey, NeedInsert, DispoBatchKey)
SELECT STaxTranKey, STaxSchdKey, NeedInsert,@lDispoBatchKey
FROM #tciSTaxTran WITH (NOLOCK)
OPTION (KEEPFIXED PLAN)
-- Set CommitStatus to indicate preprocess completed successfully.
UPDATE #tciTransToCommit
SET CommitStatus = @PRE_COMMIT_STATUS_SUCCESS
WHERE DispoBatchKey = @lDispoBatchKey
OPTION (KEEPFIXED PLAN)