2013-04-25 143 views
2

我有一个使用T/SQL过程更新的表DB.DATA_FEED。对于不同的数据,每分钟执行下面的过程100次。UPDATE和SELECT之间的冲突

ALTER PROCEDURE [DB].[UPDATE_DATA_FEED] 
    @P_MARKET_DATE varchar(max), 
    @P_CURR1 int, 
    @P_CURR2 int, 
    @P_PERIOD float(53), 
    @P_MID float(53) 
AS 

    BEGIN 

     BEGIN TRY 

     UPDATE DB.DATA_FEED 
      SET 
       MID = @P_MID, 
       MARKET_DATE = convert(datetime,@P_MARKET_DATE, 103) 
      WHERE 
       cast(MARKET_DATE as date) = 
       cast(convert(datetime,@P_MARKET_DATE, 103) as date) AND 
      CURR1 = @P_CURR1 AND 
      CURR2 = @P_CURR2 AND 
      PERIOD = @P_PERIOD 

     IF @@TRANCOUNT > 0 
      COMMIT WORK 

     END TRY 

     BEGIN CATCH 

     --error code 

     END CATCH 

    END 

END 

当用户使用该应用程序时,他们也根据下面的SQL从该表读取数据。可能这个选择可以在一分钟内运行数千次。 (问号被解析器替换为相应的日期/数字)

DECLARE @MYDATE AS DATE; 
SET @MYDATE='?' 
SELECT * 
FROM DB.DATA_FEED 
WHERE MARKET_DATE>[email protected] AND MARKET_DATE<DATEADD(D,1,@MYDATE) 
AND CURR1 = ? 
AND CURR2 = ? 
AND PERIOD = ? 

ORDER BY PERIOD 

我有时,虽然很少,有一个数据库锁。

使用从http://sqlserverplanet.com/troubleshooting/blocking-processes-lead-blocker的脚本,我看到它是SPID = 58。然后我做了DECLARE @SPID INT; SET @SPID = 58; DBCC INPUTBUFFER(@SPID)查找原来是我的select语句的SQL脚本。

我的SQL代码有问题吗?我能做些什么来防止将来发生这种锁?

感谢

+1

您是否考虑过使用读取已提交的快照来运行您的SELECT? – 2013-04-25 13:02:05

+0

我不知道这件事......你是在暗示我'ALTER DATABASE DB SET READ_COMMITTED_SNAPSHOT ON'或者是按查询查询的级别。 – gordon613 2013-04-25 13:25:56

+1

那么它必须在数据库级别启用,然后明确设置特定的查询(数据库级别设置才有可能)。当然,你应该对你的总体工作量进行测试,我并不是说只是把它打开。如果脏读是可以接受的(通过选择运行的频率,这是很有可能的),你也可以考虑读取未提交。 – 2013-04-25 13:35:17

回答

0

读者在作家,所以当有人写读者优先必须等待写入完成。有两个Table Hints你可以尝试一个是NOLOCK,它读取未定义的行(脏读),另一个是READPAST(只读取已在最后一次提交时提交的信息)。在这两种情况下,读者都不会阻止表格,因为不会让作者死锁。

作家可以阻止其他作者,但如果我理解正确,每次执行只写一次,这样读者就可以插入写入,减少死锁。

希望它有帮助。