【问题标题】:Deadlock on stored procedure存储过程死锁
【发布时间】:2013-09-21 17:19:40
【问题描述】:

我在 SQL Server 中有一个存储过程。当我从 Delphi 执行它时,我收到一条死锁消息!

事务(进程 ID 60)因锁定而死锁 |通用等待对象资源与另一个进程并已被选为死锁受害者

为了解决这种情况,我应该在下面的查询中进行哪些更改。我的存储过程没有参数。

ALTER PROCEDURE [dbo].[RepairStocks] 
AS
BEGIN
   SET NOCOUNT ON;

   drop table [dbo].[stocksss]

   select  
       Barkod, 
       sum(kolicina) as Kolicina, 
       Max(Kategorija) as Kategorija,
       Max(Artikal) as Artikal, 
       Max(Opis) as Opis, 
       Max(N_cena) as N_cena,
       Max(N_cena) * sum(kolicina) as N_Iznos, 
       Max(P_cena) as P_cena, 
       Max(P_Cena) * sum(kolicina) as P_Iznos, 
       Max(datum) as datum, 
       Max(Golemina) as Golemina
    into [dbo].[stocksss]
    from [dbo].[Stocks]
    group by Barkod

    drop table [dbo].[Stocks];

    select *
    into [dbo].[Stocks]
    from [dbo].[stocksss]   

END

任何帮助都非常感谢......

编辑我的查询后

下面的查询可以在 SQL Server 上运行,但是当我从 Delphi 执行它时,我再次收到死锁消息。这是我的查询的样子:

ALTER PROCEDURE [dbo].[RepairStocks] 

AS
BEGIN

SET NOCOUNT ON;

SET TRANSACTION ISOLATION LEVEL SERIALIZABLE

BEGIN TRAN

select  
Barkod, 
sum(kolicina) as Kolicina, 
Max(Kategorija) as Kategorija,
Max(Artikal) as Artikal, 
Max(Opis) as Opis, 
Max(N_cena) as N_cena,
Max(N_cena) * sum(kolicina) as N_Iznos, 
Max(P_cena) as P_cena, 
Max(P_Cena) * sum(kolicina) as P_Iznos, 
Max(datum) as datum, 
Max(Golemina) as Golemina


into #tmp_stocks
from [dbo].[Stocks]
group by Barkod
--------------------------------
;
DROP TABLE [dbo].[Stocks]
;
--------------------------------


select *
into [dbo].[Stocks]
from #tmp_stocks with (nolock)
;
drop table #tmp_stocks
;

COMMIT TRAN

END

Delphi 中,我使用以下代码执行命令:

RepairStocks.Close;
RepairStocks.SQL.Clear;
RepairStocks.SQL.Add('EXEC [dbo].[RepairStocks]');
RepairStocks.ExecSQL;

【问题讨论】:

  • 尝试使用with (nolock) 提示,即...from [dbo].[Stocks] with (nolock)。确保 Barkod 已编入索引。使用本地临时表和LEVEL SNAPSHOT 的单个事务(如答案中所建议)。
  • 您使用的是什么组件?塔多查询? tsqlquery?

标签: sql sql-server tsql delphi


【解决方案1】:

你应该把它包装在一个可序列化的事务中

SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
BEGIN TRAN
     ...
COMMIT TRAN

此外,您可以在表上使用truncate 而不是drop 来清空它,并且您可以使用本地临时表 (#Stocksss) 或表变量 (@Stocksss) 而不是一个用户表

【讨论】:

  • 我尝试使用 SET TRANSACTION ISOLATION LEVEL SERIALIZABLE BEGIN TRAN ... COMMIT TRAN 我还使用了临时表 (#tmp_Stocks) 它在 SQL Management Studio 中运行良好。当我在 Delphi 上执行它时,使用不同的 ID 再次出现死锁错误
【解决方案2】:

也许这不是最好的方法,但它对我有用,我得到了我应该得到的结果。 另外,当我在 Delphi 中执行此操作时,我没有收到任何错误

@podiluska - 您的建议在 SQL Server Management Studio 中有效

ALTER PROCEDURE [dbo].[RepairStocks]
AS
BEGIN

begin tran

delete from stocksss


--insert from Stocks to Stocksss
INSERT INTO stocksss
select Barkod, 
sum(kolicina) as Kolicina, 
Max(Kategorija) as Kategorija,
Max(Artikal) as Artikal, 
Max(Opis) as Opis, 
Max(N_cena) as N_cena,
Max(N_cena) * sum(kolicina) as N_Iznos, 
Max(P_cena) as P_cena, 
Max(P_Cena) * sum(kolicina) as P_Iznos, 
Max(datum) as datum, 
Max(Golemina) as Golemina
from [dbo].[Stocks]
group by Barkod
;

----------------------------------------------------------

delete from Stocks

insert into Stocks
select * from stocksss
;

Commit Tran

END

谢谢!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-11-24
    • 2011-10-22
    • 1970-01-01
    • 1970-01-01
    • 2012-07-05
    • 1970-01-01
    • 2014-11-27
    相关资源
    最近更新 更多