从临时表锁定 - SQL 2008 R2

时间:2014-07-18 13:44:22

标签: sql sql-server sql-server-2008 stored-procedures locking

我刚刚在我们的实时环境中实现了一个新数据库,该数据库由我们的两个事务数据库中的服务代理提供信息。当消息进入新数据库时,我们有一系列存储过程来操作每个特定用户的提要。

我还有另一组存储过程,用户而不是车辆重新操作数据,我们的维护屏幕使用这些存储过程来确保我们可以更改用户对数据的可见性。

下面的存储过程一直保持锁定我现在已经修改了这个sp来首先更新一个临时表然后只对主数据库进行一次更新,但这没有帮助的情况,我也修改了所以我可以更新较小的批次,如果失败,请继续重试,直到成功为止。这在我们的开发环境中100%工作,但在实时它保持锁定。服务经纪人的吞吐量不足以记录失败次数,因此我认为我将自己锁定在这个sp中?

我已经包含了---'此更新KEEPS LOCKING'在失败的时候。

可能导致此锁定行为的原因是什么?

USE [Isight]

GO / ** 对象:StoredProcedure [dbo]。[UserVisibilityForVehicles]脚本日期:07/18/2014 14:43:04 ** / SET ANSI_NULLS ON 走 SET QUOTED_IDENTIFIER ON GO

ALTER PROCEDURE [dbo]。[UserVisibilityForVehicles]      - 在此处添加存储过程的参数 @Username VARCHAR(50)  随着重建 如 开始      - 添加SET NOCOUNT ON以防止出现额外的结果集      - 干扰SELECT语句。     SET NOCOUNT ON;

PRINT 'UserVisibilityForVehicles Started'

-- Now Start to check security for user.

IF EXISTS ( SELECT ID FROM dbo.SecurityTable WHERE userid = @Username AND Deleted = 0)
BEGIN


        CREATE TABLE #VehicleToUsers(ID BIGINT, NewRecord BIT DEFAULT(0))
        CREATE CLUSTERED INDEX IDX_VehicleToUsers ON #VehicleToUsers(ID)
        CREATE NonCLUSTERED INDEX IDX_NewRecord ON #VehicleToUsers(ID)

        INSERT INTO #VehicleToUsers
                ( ID )
        (
            SELECT Distinct Veh.[ID]
            FROM [iSight].[dbo].[Vehicle] Veh WITH (NOLOCK) 
            INNER JOIN SecurityTable WITH (NOLOCK) ON  Veh.[System] = SecurityTable.[System]
            WHERE SecurityType = 1  AND UserID = @Username AND SecurityTable.deleted = 0 
        )

        INSERT INTO #VehicleToUsers
                ( ID )
        (
            SELECT DISTINCT Veh.[ID]
            FROM [iSight].[dbo].[Vehicle] Veh WITH (NOLOCK) 
            INNER JOIN SecurityTable WITH (NOLOCK) ON Veh.[System] = SecurityTable.[System] AND Veh.CurrentSite = SecurityTable.[Site]
            WHERE SecurityType = 2 AND UserID = @Username AND SecurityTable.deleted = 0 
        )



                    BEGIN
                        PRINT 'UserVisibilityForVehicles: ' + @Username
                        INSERT INTO #VehicleToUsers
                                    ( ID )
                            (
                        SELECT  DISTINCT   Vehicle.ID
                        FROM         Manufacturer WITH (NOLOCK) INNER JOIN
                                              ManufacturerAgreementSubcustomer WITH (NOLOCK) ON Manufacturer.ID = ManufacturerAgreementSubcustomer.ManufacturerID INNER JOIN
                                              ManufacturerMake WITH (NOLOCK) ON Manufacturer.ID = ManufacturerMake.ManufacturerID INNER JOIN
                                              Vehicle WITH (NOLOCK) ON ManufacturerMake.Make = Vehicle.Make AND ManufacturerAgreementSubcustomer.Agreement = Vehicle.CurrentAgreement INNER JOIN
                                              SecurityTable WITH (NOLOCK) ON Manufacturer.ManufacturerGroupID = SecurityTable.ManufacturerGroupID AND Vehicle.System = SecurityTable.System
                        WHERE     (SecurityTable.SecurityType = 3)  AND (SecurityTable.UserID = @Username) AND ManufacturerMake.Deleted = 0 AND ManufacturerAgreementSubcustomer.Deleted = 0 AND SecurityTable.deleted = 0 
                            )

                            INSERT INTO #VehicleToUsers
                                    ( ID )
                            (
                        SELECT DISTINCT Vehicle.ID
                        FROM         Manufacturer WITH (NOLOCK) INNER JOIN
                                              ManufacturerAgreementSubcustomer WITH (NOLOCK) ON Manufacturer.ID = ManufacturerAgreementSubcustomer.ManufacturerID INNER JOIN
                                              ManufacturerMake WITH (NOLOCK) ON Manufacturer.ID = ManufacturerMake.ManufacturerID INNER JOIN
                                              Vehicle WITH (NOLOCK) ON ManufacturerMake.Make = Vehicle.Make AND ManufacturerAgreementSubcustomer.Agreement = Vehicle.CurrentAgreement INNER JOIN
                                              SecurityTable WITH (NOLOCK) ON Vehicle.System = SecurityTable.System AND Manufacturer.ID = SecurityTable.ManufacturerID
                        WHERE     (SecurityTable.SecurityType = 4) AND (SecurityTable.UserID = @Username) AND ManufacturerMake.Deleted = 0 AND ManufacturerAgreementSubcustomer.Deleted = 0 AND SecurityTable.deleted = 0 
                            )

                                INSERT INTO #VehicleToUsers
                                    ( ID )
                            (
                                SELECT DISTINCT Vehicle.ID
                                FROM         Manufacturer WITH (NOLOCK) INNER JOIN
                                                      ManufacturerAgreementSubcustomer WITH (NOLOCK) ON Manufacturer.ID = ManufacturerAgreementSubcustomer.ManufacturerID INNER JOIN
                                                      ManufacturerMake WITH (NOLOCK) ON Manufacturer.ID = ManufacturerMake.ManufacturerID INNER JOIN
                                                      Vehicle WITH (NOLOCK) ON ManufacturerMake.Make = Vehicle.Make AND ManufacturerAgreementSubcustomer.Agreement = Vehicle.CurrentAgreement INNER JOIN
                                                      SecurityTable WITH (NOLOCK) ON Vehicle.System = SecurityTable.System AND Manufacturer.ID = SecurityTable.ManufacturerID AND 
                                                      ManufacturerAgreementSubcustomer.ID = SecurityTable.ManufacturerAgreementSub INNER JOIN
                                                      ManufacturerUserAgreementSubcustomer WITH (NOLOCK) ON 
                                                      ManufacturerAgreementSubcustomer.ID = ManufacturerUserAgreementSubcustomer.ManufacturerAgreementSubcustomerID AND 
                                                      SecurityTable.ManufacturerID = ManufacturerUserAgreementSubcustomer.ManufacturerID AND 
                                                      SecurityTable.UserID = ManufacturerUserAgreementSubcustomer.UserName
                                WHERE     (SecurityTable.SecurityType = 5) AND (SecurityTable.UserID = @Username) AND (ManufacturerMake.Deleted = 0) AND 
                                                      (ManufacturerAgreementSubcustomer.Deleted = 0) AND (ManufacturerUserAgreementSubcustomer.Deleted = 0) AND SecurityTable.deleted = 0 


                            )


                                    INSERT INTO #VehicleToUsers
                                    ( ID )
                            (
                                SELECT DISTINCT Vehicle.ID
                                FROM         Manufacturer WITH (NOLOCK) INNER JOIN
                                                      ManufacturerAgreementSubcustomer WITH (NOLOCK) ON Manufacturer.ID = ManufacturerAgreementSubcustomer.ManufacturerID INNER JOIN
                                                      ManufacturerMake WITH (NOLOCK) ON Manufacturer.ID = ManufacturerMake.ManufacturerID INNER JOIN
                                                      Vehicle WITH (NOLOCK) ON ManufacturerMake.Make = Vehicle.Make AND ManufacturerAgreementSubcustomer.Agreement = Vehicle.CurrentAgreement AND 
                                                      ManufacturerAgreementSubcustomer.Subcustomer = Vehicle.CurrentSubCustomer INNER JOIN
                                                      SecurityTable WITH (NOLOCK) ON Vehicle.System = SecurityTable.System AND Manufacturer.ID = SecurityTable.ManufacturerID AND 
                                                      ManufacturerAgreementSubcustomer.ID = SecurityTable.ManufacturerAgreementSub INNER JOIN
                                                      ManufacturerUserAgreementSubcustomer WITH (NOLOCK) ON 
                                                      ManufacturerAgreementSubcustomer.ID = ManufacturerUserAgreementSubcustomer.ManufacturerAgreementSubcustomerID AND 
                                                      SecurityTable.UserID = ManufacturerUserAgreementSubcustomer.UserName AND 
                                                      SecurityTable.ManufacturerID = ManufacturerUserAgreementSubcustomer.ManufacturerID
                                WHERE     (SecurityTable.SecurityType = 6) AND (SecurityTable.UserID = @Username) AND (ManufacturerMake.Deleted = 0) AND 
                                                      (ManufacturerAgreementSubcustomer.Deleted = 0) AND (ManufacturerUserAgreementSubcustomer.Deleted = 0) AND SecurityTable.deleted = 0 
                            )


                    END

        CREATE TABLE #VehicleToUserCopy(ID BIGINT, vehicleTableID BIGINT, Deleted BIT DEFAULT(1), UpdatedAt DATETIME DEFAULT (GETDATE()), UpdatedBy VARCHAR(50) DEFAULT('UserVisibilityForVehicles-Update'), NextToUpdate BIT DEFAULT(0))

        CREATE CLUSTERED INDEX idx_ID ON #VehicleToUserCopy(ID)
        CREATE NONCLUSTERED INDEX idx_VehicleTableID ON #VehicleToUserCopy(vehicleTableID)
        CREATE NONCLUSTERED INDEX idx_NextToUpdate ON #VehicleToUserCopy(NextToUpdate)
        INSERT INTO #VehicleToUserCopy
                ( ID ,
                  vehicleTableID ,
                  Deleted
                )
        (
        SELECT ID, vehicleTableID, Deleted
        FROM dbo.VehicleToUser WITH (nolock)
        WHERE Username = @Username

        )


        PRINT 'Starting to do updates'
        --Not required as default set to 1
        ----UPDATE VehicleToUser
        ----SET DELETED = 1
        ----,UpdatedAt = GETDATE()
        ----,UpdatedBy = 'UserVisibilityForVehicles'
        ----FROM dbo.VehicleToUser WITH (NOLOCK)
        ----LEFT JOIN #VehicleToUsers AS UsersVehicles ON VehicleToUser.VehicleTableID = UsersVehicles.ID
        ----WHERE UserName = @Username AND UsersVehicles.ID IS null

        PRINT 'Starting to do updates - Set Deleted = 0'




        SET LOCK_TIMEOUT 1000 -- set to  second
        DECLARE @Tries tinyint


        UPDATE #VehicleToUserCopy
        SET Deleted = 0
        FROM #VehicleToUserCopy AS VehicleToUserCopy
        inner JOIN #VehicleToUsers AS UsersVehicles ON VehicleToUserCopy.VehicleTableID = UsersVehicles.ID




        INSERT INTO VehicleToUser(UserName, VehicleTableID, DELETED, UpdatedAt, UpdatedBy)
        (
            SELECT DISTINCT @Username, TempVehicle.ID, 0 , GETDATE(), 'UserVisibilityForVehicles-Insert'
            FROM #VehicleToUsers AS TempVehicle
            LEFT JOIN (
                        SELECT VehicleTableID
                        FROM #VehicleToUserCopy WITH (NOLOCK)
                      ) AS [VehicleToUser] ON TempVehicle.ID = [VehicleToUser].VehicleTableID
            WHERE [VehicleToUser].VehicleTableID IS null

        )

        DECLARE @ID bigint

        SELECT @ID = ID FROM #VehicleToUserCopy
        WHILE @@rowcount > 0 
            BEGIN

                    SET ROWCOUNT 1000
                    SELECT @Tries = 1
                    WHILE @Tries <= 3

                          BEGIN

                         BEGIN TRANSACTION

                         BEGIN TRY

                                UPDATE #VehicleToUserCopy SET NextToUpdate = 1


                                 ---'THIS UPDATE KEEPS LOCKING'
                                UPDATE dbo.VehicleToUser
                                SET Deleted = VehicleToUserCopy.Deleted
                                , UpdatedAt = GETDATE()
                                , UpdatedBy = VehicleToUserCopy.UpdatedBy
                                FROM VehicleToUser
                                inner JOIN #VehicleToUserCopy  AS VehicleToUserCopy ON VehicleToUser.ID = VehicleToUserCopy.ID
                                WHERE VehicleToUserCopy.NextToUpdate = 1            

                                PRINT 'WORKED'
                                DELETE FROM #VehicleToUserCopy WHERE NextToUpdate = 1   
                                COMMIT    

                          -- therefore we can leave our loop
                          BREAK

                         END TRY

                         BEGIN CATCH

                                ROLLBACK --always rollback 


                            PRINT 'Rolled Back '
                          -- Now check for Blocking errors 1222 or Deadlocks 1205 and if its a deadlock wait for a while to see if that helps
                             SELECT ERROR_MESSAGE()
                              IF ERROR_NUMBER() = 1205 OR ERROR_NUMBER() = 1222

                                BEGIN

                                     -- if its a deadlock wait 2 seconds then try again
                                   IF ERROR_NUMBER() = 1205
                                     BEGIN  -- wait 2 seconds to see if that helps the deadlock

                                            WAITFOR DELAY '00:00:02'
                                     END   

                                   -- no need to wait for anything for BLOCKING ERRORS as our LOCK_TIMEOUT is going to wait for half a second anyway
                                   -- and if it hasn't finished by then (500ms x 3 attempts = 1.5 seconds) there is no point waiting any longer

                                END      


                                 SELECT @Tries = @Tries + 1  -- increment and try again for 3 goes

                          -- we carry on until we reach our limit i.e 3 attempts
                          CONTINUE    

                           END CATCH

                          END



                SELECT @ID = ID FROM #VehicleToUserCopy 
            End


        SET ROWCOUNT 0


        DROP TABLE #VehicleToUsers


END
ELSE

BEGIN
        DELETE FROM dbo.VehicleToUser WHERE username = @Username
        DELETE FROM dbo.VehicleToUser_UserCurrentImageCount WHERE username = @Username
        DELETE FROM dbo.VehicleToUser_UsersCurrentVehicles WHERE username = @Username

End

1 个答案:

答案 0 :(得分:0)

尝试稍微更改您的更新。在使用这样的更新并更新基表时,我看到了一些不一致的结果。您应该更新别名。

UPDATE v
SET Deleted = VCopy.Deleted
, UpdatedAt = GETDATE()
, UpdatedBy = VCopy.UpdatedBy
FROM VehicleToUser v
inner JOIN #VehicleToUserCopy  AS VCopy ON v.ID = VCopy.ID
WHERE VCopy.NextToUpdate = 1