【问题标题】:Locking From Temp Table - SQL 2008 R2从临时表锁定 - SQL 2008 R2
【发布时间】:2014-09-09 16:20:39
【问题描述】:

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

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

下面的存储过程一直锁定我现在已经修改了这个 sp 以首先更新一个临时表,然后只对主数据库进行一次更新,但这并没有帮助这种情况,我也进行了修改,以便我可以更新较小的批次,如果失败,请继续重试,直到成功。这在我们的开发环境中 100% 有效,但在实时状态下它会一直锁定。 servicebrokers 的吞吐量不足以记录失败的数量,因此我相信我将自己锁定在这个 sp 中?

我在故障点添加了 ---“此更新保持锁定”。

什么可能导致这种锁定行为?

USE [Isight]

去 /** 对象:StoredProcedure [dbo].[UserVisibilityForVehicles] 脚本日期:07/18/2014 14:43:04 **/ 设置 ANSI_NULLS ON 走 设置 QUOTED_IDENTIFIER ON 去吧

改变程序 [dbo].[UserVisibilityForVehicles] -- 这里添加存储过程的参数 @用户名 VARCHAR(50) 重新编译 作为 开始 -- 添加了 SET NOCOUNT ON 以防止额外的结果集 -- 干扰 SELECT 语句。 设置无计数;

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

【问题讨论】:

  • 我建议你不要再用 NOLOCK 提示乱扔你的数据库。您是否可以接受重复和/或丢失的数据?

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


【解决方案1】:

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

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            

【讨论】:

    猜你喜欢
    • 2016-03-20
    • 1970-01-01
    • 1970-01-01
    • 2016-01-26
    • 1970-01-01
    • 2014-11-21
    • 2014-09-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多