Please start any new threads on our new
site at https://forums.sqlteam.com. We've got lots of great SQL Server
experts to answer whatever question you can come up with.
| Author |
Topic |
|
halexic
Starting Member
8 Posts |
Posted - 2007-11-14 : 04:45:14
|
Hello,I am having deadlock problem when I have a lot of visitors on my website at the same time. I am using NetTiers templates to generate C#classes for accessing DB layer and problem is in my custom Store Procedure.I have Article table and ArticleLanguage table. One record from Article (Id, Position, StatusId) table is thesame for all languages and in ArticleLanguage (Id, LanguageId, ArticleId, Name) tableI have only article names for every language.I then physically created ArticleListing "ghost" table thathave all fields from these two tables and this listing table is usedfor displaying articles in grid and this table is filled with mycustom Store Procedure. It must not be created in memory (temporary table)because NetTiers must generate Entity for it (I got TList collection).And there I have a SQL problem, because in my Store Procedure first command isDELETE FROM ArticleListing (I also tried this trick with GUID,it didn't help me much - you will see in script bellow) and then I doINSERT FROM Article INTO ArticleListing... and thenUPDATE ArticleListing FROM ArticleLanguage...When there is a lot of users they call this store procedure andDeadLocks occured very often - I suppose because of deleting andinserting into this "ghost" table... I am sending you a scripts inorder to know exactly what I am doing and please help me with adviceis it possible to change Store Procedure to avoid deadlock?CREATE TABLE dbo.Article( Id int IDENTITY(1,1) NOT NULL, Position int NULL, StatusId int NULL CONSTRAINT PK_Article PRIMARY KEY CLUSTERED ( Id ASC)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON PRIMARY) ON PRIMARYCREATE TABLE dbo.ArticleLanguage( Id int IDENTITY(1,1) NOT NULL, LanguageId int NULL, ArticleId int NULL, Name varchar(100) NULL CONSTRAINT PK_ArticleLanguage PRIMARY KEY CLUSTERED ( Id ASC)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON PRIMARY) ON PRIMARYGOSET ANSI_PADDING OFFGOALTER TABLE dbo.ArticleLanguage WITH CHECK ADD CONSTRAINT FK_ArticleLanguage_Article FOREIGN KEY(ArticleId)REFERENCES dbo.Article (Id)GOALTER TABLE dbo.ArticleLanguage CHECK CONSTRAINT FK_ArticleLanguage_ArticleCREATE TABLE dbo.ArticleListing( Id int IDENTITY(1,1) NOT NULL, TransactionGuid varchar(40) NULL, TransactionDate datetime NULL CONSTRAINT DF_ArticleListing_TransactionDate DEFAULT (getdate()), LanguageId int NULL, ArticleId int NULL, ArticleLanguageId int NULL, Name varchar(100) NULL, Position int NULL, StatusId int NULL CONSTRAINT PK_ArticleListing PRIMARY KEY CLUSTERED ( Id ASC)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON PRIMARY) ON PRIMARYGOSET ANSI_NULLS ONGOSET QUOTED_IDENTIFIER ONGO-- =============================================-- Description: Returns Article and ArticleLanguage listing in one table-- =============================================CREATE PROCEDURE dbo._ArticleListing_GetListing( @LanguageId int, @ArticleId int = null, @StatusId int = null)ASBEGIN --Delete old records DELETE FROM ArticleListing WHERE TransactionDate < DATEADD(minute, -2, GETDATE()) --Create new GUID for this transaction DECLARE @TransactionGuid varchar(40) SET @TransactionGuid = NEWID() --Insert from Article INSERT INTO ArticleListing ( TransactionGuid, ArticleId, Position, StatusId ) SELECT @TransactionGuid, Id, Position, StatusId FROM Article WHERE (@ArticleId IS NULL OR Id = @ArticleId) AND (@StatusId IS NULL OR StatusId = @StatusId) --Update from ArticleLanguage UPDATE ArticleListing SET ArticleListing.LanguageId = ArticleLanguage.LanguageId, ArticleListing.ArticleLanguageId = ArticleLanguage.Id, ArticleListing.Name = ArticleLanguage.Name FROM ArticleLanguage LEFT JOIN ArticleListing ON ArticleListing.ArticleId = ArticleLanguage.ArticleId WHERE TransactionGuid = @TransactionGuid AND ArticleListing.ArticleId = ArticleLanguage.ArticleId AND ArticleLanguage.LanguageId = @LanguageId AND (@ArticleLanguageId IS NULL OR ArticleLanguage.Id = @ArticleLanguageId) --Delete not valid recordsDELETE FROM ArticleListing WHERE TransactionGuid = @TransactionGuid AND (LanguageId IS NULL OR ArticleLanguageId IS NULL) SELECT Id, TransactionGuid, TransactionDate, LanguageId, ArticleId, ArticleLanguageId, Name, Position, StatusId FROM ArticleListing WHERE TransactionGuid = @TransactionGuid ORDER BY PositionEND and exception...Message: Transaction (Process ID 166) was deadlocked on lock resources with another process and has been chosen as the deadlock victim. Rerun the transaction.StackTrace: at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection) atSystem.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection) atSystem.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj) at System.Data.SqlClient.TdsParser.Run(RunBehaviorrunBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObjectstateObj) at System.Data.SqlClient.SqlDataReader.ConsumeMetaData() at System.Data.SqlClient.SqlDataReader.get_MetaData() atSystem.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds, RunBehavior runBehavior, String resetOptionsString) atSystem.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean async) atSystem.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method, DbAsyncResult result) atSystem.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method) atSystem.Data.SqlClient.SqlCommand.ExecuteReader(CommandBehavior behavior, String method) atSystem.Data.SqlClient.SqlCommand.ExecuteDbDataReader(CommandBehavior behavior) atSystem.Data.Common.DbCommand.ExecuteReader(CommandBehavior behavior) atMicrosoft.Practices.EnterpriseLibrary.Data.Database.DoExecuteReader(DbCommand command, CommandBehavior cmdBehavior) atMicrosoft.Practices.EnterpriseLibrary.Data.Database.ExecuteReader(DbCommand command) at MyProject.Data.Utility.ExecuteReader(Database database, DbCommand dbCommand) atMyProject.Data.SqlClient.SqlArticleListingProviderBase.GetListing(TransactionManager transactionManager, Int32 start, Int32 pageLength, Nullable`1 languageId, Nullable`1 articleId, Nullable`1 statusId) atMyProject.Data.Bases.ArticleListingProviderBaseCore.GetListing(Nullable`1 languageId, Nullable`1 articleId, Nullable`1 statusId) atUserControls_ArticleGrid.Page_Load(Object sender, EventArgs e) at System.Web.Util.CalliHelper.EventArgFunctionCaller(IntPtr fp, Object o, Object t, EventArgs e) atSystem.Web.Util.CalliEventHandlerDelegateProxy.Callback(Object sender, EventArgs e) at System.Web.UI.Control.OnLoad(EventArgs e) at System.Web.UI.Control.LoadRecursive() atSystem.Web.UI.Control.LoadRecursive() at System.Web.UI.Control.LoadRecursive() at System.Web.UI.Control.LoadRecursive() at System.Web.UI.Control.LoadRecursive() atSystem.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) |
|
|
SwePeso
Patron Saint of Lost Yaks
30421 Posts |
Posted - 2007-11-14 : 05:35:02
|
I think you should rewrite your SP like this, since you are using SQL Server 2005.CREATE PROCEDURE dbo.usp_ArticleListing_GetListing( @LanguageID INT, @ArticleID INT = NULL, @StatusID INT = NULL)ASSET NOCOUNT ON--Delete old recordsDELETEFROM ArticleListingWHERE TransactionDate < DATEADD(MINUTE, -2, CURRENT_TIMESTAMP)-- Create new GUID for this transactionDECLARE @TransactionGuid UNIQUEIDENTIFIERSET @TransactionGuid = NEWID()--Insert from ArticleINSERT ArticleListing ( TransactionGuid, ArticleId, Position, StatusId, LanguageId, ArticleLanguageId, [Name] )OUTPUT INSERTED.Id, INSERTED.TransactionGuid, INSERTED.TransactionDate, INSERTED.LanguageId, INSERTED.ArticleId, INSERTED.ArticleLanguageId, INSERTED.[Name], INSERTED.Position, INSERTED.StatusIdSELECT @TransactionGuid, a.Id, a.Position, a.StatusId al.LanguageId, al.Id, al.NameFROM Article AS aINNER JOIN ArticleLanguage AS al ON al.ArticleId = a.IdWHERE (a.Id = @ArticleId OR @ArticleId IS NULL) AND (a.StatusId = @StatusId OR @StatusId IS NULL) AND al.LanguageId = @LanguageId AND (al.Id = @ArticleLanguageId OR @ArticleLanguageId IS NULL)ORDER BY a.Position E 12°55'05.25"N 56°04'39.16" |
 |
|
|
halexic
Starting Member
8 Posts |
Posted - 2007-11-14 : 11:14:44
|
| Can you please tell me if it is 100% multithread safe and what is doing that trick when compared to my version of StoreProcedure?Thanks in advanceAlex |
 |
|
|
SwePeso
Patron Saint of Lost Yaks
30421 Posts |
Posted - 2007-11-14 : 11:31:00
|
Huh? This is just the SP you call from your application.My suggestion:DELETE / INSERT with "cloning output". 2 operations.Your originalDELETE / INSERT / UPDATE / DELETE /SELECT. 5 operations. E 12°55'05.25"N 56°04'39.16" |
 |
|
|
|
|
|
|
|