0

MS SQL Server ベースの ERP システムを使用しています。99 個の一時テーブルを使用して作業を実行する出荷コミット プロセスがあります。作業はアトミックである必要があります。すべてが発生する必要があるか、まったく発生しない必要があります。この特定のストアド プロシージャは、データベース内の最大のテーブルに影響します。プロシージャーの記述方法は、うまく拡張できません。午後に大量の出荷をコミットしているすべての大規模なクライアント全体で、SQL Server は大幅に減速しています。負荷がかかっていない場合、このプロセスにかかる時間は 1 秒未満です。多くのユーザー (15 ~ 30 人) が出荷をコミットしている場合、プロセスには 1 分以上かかります。

プロセスを書き直して、負荷がかかった状態でのパフォーマンスを向上させることに興味があります。

すべての一時テーブルには、インデックスやクラスター化されたインデックスがあります。

手順で使用される永続テーブルの周りのインデックスを使用して、パフォーマンス チューニングに取り組んできました。

私は、プロセス全体をアトミックに保ちながら、スケーリングを向上させる、より優れたアーキテクチャを探しています。一部の一時テーブルには少数のレコード (< 100) しか保持されないようですが、一部のテーブルには多数のレコード (>10,000 で <100,000) が保持されるようです (これを経験的に判断する作業は行っていません)。この点)。私が見る代替案は次のとおりです。

  • 一部の一時テーブルをテーブル変数に移動して、データをメモリに保持します
  • プロセスの一部を SQL から呼び出される CLR ベースのプロシージャに移動します (ロジックの一部は、t-sql よりも手続き型コードの方が高速に実行される可能性があります)。

この質問を進めるのに役立つ、より具体的な情報を教えてください。

追加情報 (John Puttman -- 2013 年 7 月 9 日)

この proc の実行中に開始およびコミットされた 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)
4

1 に答える 1

1

「アトミック」が必要な場合は、TRANS (BEGIN TRAN、COMMIT TRAN) が必要です。

BEGIN TRAN ステートメントの前に、すべての「シュレッディング」または「解析」を #temp テーブルに実行します。

つまり、BEGIN TRAN を呼び出す前に、すべてのドミノをセットアップする必要があります。別名、BEGIN TRAN/COMMIT TRAN 内のすべては、可能な限りスリムにする必要があります。

Tran 内の Insert/Update/(Merge/Upsert)/Delete ステートメントの順序を見てください。それらが理にかなっていることを確認してください....特に、頻繁に呼び出される別のストアドプロシージャでブロッキングの問題 (デッドロックの問題) を引き起こす可能性があるものに注意してください。

.........

グーグル

SQL Server 一時データベースのベスト プラクティス

これがスターターです:

http://msdn.microsoft.com/en-us/library/ms175527(v=sql.105).aspx

.......

@variable テーブルを使用して "実験" することはできますが、それは成功するか失敗するかの命題です。

于 2013-07-09T17:45:13.007 に答える