2010-04-09 3 views
0

심각한 성능 문제가 있습니다.SQL Server 2008 삽입 후 업데이트 실행, 원래 테이블 잠금 잠금

나는 (이 문제와 관련이있는) 데이터베이스와 2 개의 테이블을 가지고있다.

1 표에는 일부 전역 정보가 포함 된 문자열이 들어 있습니다. 두 번째 테이블에는 각 개별 단어 아래로 스트립 된 문자열이 들어 있습니다. 따라서 문자열은 두 번째 테이블에서 단어별로 색인 된 것과 같습니다.

두 번째 테이블의 데이터 유효성은 첫 번째 테이블의 데이터 유효성보다 덜 중요합니다.

첫 번째 테이블이 1 * 10^6 레코드처럼 커질 수 있고 첫 번째 테이블의 평균 길이가 1 문자열 인 경우 두 번째 테이블이 1 * 10^7 레코드처럼 커질 수 있으므로 읽을 때 nolock을 사용합니다. 두 번째로는 새로운 레코드를 잠그지 않고 삽입 할 수 있습니다 (두 테이블에서 많은 읽기가 예상 됨).

MERGE 문의 첫 번째 테이블에 행을 추가하고 업데이트하는 스크립트가 있습니다. 평균적으로 병합 된 데이터는 한 번에 20 문자열이며 스크립트는 5 초마다 실행됩니다.

첫 번째 테이블에서 나는 새로 삽입 또는 업데이트 된 데이터를 가져 와서 두 번째 테이블에서 데이터가 인덱싱되는지 확인하는 저장 프로 시저를 호출하는 삽입 또는 업데이트에서 호출되는 트리거를 가지고 있습니다. (이것은 상당한 시간이 걸립니다).

문제는 트리거가 불일치 할 때 첫 번째 테이블 읽기가 몇 밀리 초 안에 발생한다는 것입니다. 그러나 트리거를 활성화하고 업데이트가 진행되는 동안 첫 번째 테이블을 읽으려고하면 불행하게도 우리 웹 서버는 10 초 후에 제한 시간을 제공합니다 (어쨌든 긴 시간입니다).

트리거를 실행할 때 트리거가 완료 될 때까지 첫 번째 테이블은 (부분적으로) 잠금 상태로 유지됩니다.

내가 옳다면이 주변에 쉬운 방법이있을 것이라고 생각합니까? 사전에

감사합니다!

는 요청으로 :

ALTER TRIGGER [dbo].[OnFeedItemsChanged] 
    ON [dbo].[FeedItems] 
    AFTER INSERT,UPDATE 
AS 
BEGIN 
    -- SET NOCOUNT ON added to prevent extra result sets from 
    -- interfering with SELECT statements. 
    SET NOCOUNT ON; 

    DECLARE @id int; 
    SELECT @id = ID FROM INSERTED; 
    IF @id IS NOT NULL 
    BEGIN 
     DECLARE @title nvarchar(MAX); 
     SELECT @title = Title FROM INSERTED; 
     DECLARE @description nvarchar(MAX); 
     SELECT @description = [Description] FROM INSERTED; 

     SELECT @title = dbo.RemoveNonAlphaCharacters(@title) 
     SELECT @description = dbo.RemoveNonAlphaCharacters(@description) 

     -- Insert statements for trigger here 
     EXEC dbo.usp_index_itemstring @id, @title; 
     EXEC dbo.usp_index_itemstring @id, @description; 
    END 
END 

FeedItems 테이블이 쿼리에 의해 채워집니다

MERGE INTO FeedItems i 
USING @newitems d ON i.Service = d.Service AND i.GUID = d.GUID 
WHEN matched THEN UPDATE 
    SET i.Title = d.Title, 
     i.Description = d.Description, 
     i.Uri = d.Uri, 
     i.Readers = d.Readers 
WHEN NOT matched THEN INSERT 
    (Service, Title, Uri, GUID, Description, Readers) 
    VALUES 
    (d.Service, d.Title, d.Uri, d.GUID, d.Description, d.Readers); 

의 sproc : IndexItemStrings 실제로 자신의 시간이 걸립니까이 시저를 실행, 두 번째 테이블을 채우는된다. 문제는이 트리거를 실행하는 동안입니다.

USE [ICI] 
GO 

/****** Object: Table [dbo].[FeedItems] Script Date: 04/09/2010 15:03:31 ******/ 
SET ANSI_NULLS ON 
GO 

SET QUOTED_IDENTIFIER ON 
GO 

CREATE TABLE [dbo].[FeedItems](
    [ID] [int] IDENTITY(1,1) NOT NULL, 
    [Service] [int] NOT NULL, 
    [Title] [nvarchar](max) NULL, 
    [Uri] [nvarchar](max) NULL, 
    [Description] [nvarchar](max) NULL, 
    [GUID] [nvarchar](255) NULL, 
    [Inserted] [smalldatetime] NOT NULL, 
    [Readers] [int] NOT NULL, 
CONSTRAINT [PK_FeedItems] 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 [PRIMARY] 

GO 

ALTER TABLE [dbo].[FeedItems] WITH CHECK ADD CONSTRAINT [FK_FeedItems_FeedServices] FOREIGN KEY([Service]) 
REFERENCES [dbo].[FeedServices] ([ID]) 
ON DELETE CASCADE 
GO 

ALTER TABLE [dbo].[FeedItems] CHECK CONSTRAINT [FK_FeedItems_FeedServices] 
GO 

ALTER TABLE [dbo].[FeedItems] ADD CONSTRAINT [DF_FeedItems_Inserted] DEFAULT (getdate()) FOR [Inserted] 
GO 

두 번째 테이블 :

USE [ICI] 
GO 

/****** Object: Table [dbo].[FeedItemPhrases] Script Date: 04/09/2010 15:04:47 ******/ 
SET ANSI_NULLS ON 
GO 

SET QUOTED_IDENTIFIER ON 
GO 

CREATE TABLE [dbo].[FeedItemPhrases](
    [FeedItem] [int] NOT NULL, 
    [Phrase] [int] NOT NULL, 
    [Count] [smallint] NOT NULL, 
CONSTRAINT [PK_FeedItemPhrases] PRIMARY KEY CLUSTERED 
(
    [FeedItem] ASC, 
    [Phrase] ASC 
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] 
) ON [PRIMARY] 

GO 

ALTER TABLE [dbo].[FeedItemPhrases] WITH CHECK ADD CONSTRAINT [FK_FeedItemPhrases_FeedItems] FOREIGN KEY([FeedItem]) 
REFERENCES [dbo].[FeedItems] ([ID]) 
ON UPDATE CASCADE 
ON DELETE CASCADE 
GO 

ALTER TABLE [dbo].[FeedItemPhrases] CHECK CONSTRAINT [FK_FeedItemPhrases_FeedItems] 
GO 

ALTER TABLE [dbo].[FeedItemPhrases] WITH CHECK ADD CONSTRAINT [FK_FeedItemPhrases_Phrases] FOREIGN KEY([Phrase]) 
REFERENCES [dbo].[Phrases] ([ID]) 
ON UPDATE CASCADE 
ON DELETE CASCADE 
GO 

ALTER TABLE [dbo].[FeedItemPhrases] CHECK CONSTRAINT [FK_FeedItemPhrases_Phrases] 
GO 

그리고 더 :

FeedItems 테이블에 적용되는 쿼리는 대부분 (두 번째 테이블을 사용하지 말아 심지어 쿼리)

먼저 테이블 밖으로 타이밍

ALTER PROCEDURE [dbo].[usp_index_itemstring] 
    -- Add the parameters for the stored procedure here 
    @item int, 
    @text nvarchar(MAX) 
AS 
BEGIN 
    -- SET NOCOUNT ON added to prevent extra result sets from 
    -- interfering with SELECT statements. 
    SET NOCOUNT ON; 

    -- DECLARE a table containing all words within the text 
    DECLARE @tempPhrases TABLE 
    ( 
     [Index] int, 
     [Phrase] NVARCHAR(256) 
    ); 

    -- extract each word from text and store it in the temp table 
    WITH Pieces(pn, start, [stop]) AS 
    ( 
     SELECT 1, 1, CHARINDEX(' ', @text) 
     UNION ALL 
     SELECT pn + 1, CAST([stop] + 1 AS INT), CHARINDEX(' ', @text, [stop] + 1) 
     FROM Pieces 
     WHERE [stop] > 0 
    ) 
    INSERT INTO @tempPhrases 
    SELECT pn, SUBSTRING(@text, start, CASE WHEN [stop] > 0 THEN [stop]-start ELSE LEN(@text) END) AS s 
    FROM Pieces 
    OPTION (MAXRECURSION 0);  

    WITH CombinedPhrases ([Phrase]) AS 
    (
     -- SELECT ALL 2-WORD COMBINATIONS 
     SELECT w1.[Phrase] + ' ' + w2.[Phrase] 
     FROM @tempPhrases w1 
     JOIN @tempPhrases w2 ON w1.[Index] + 1 = w2.[Index] 
     UNION ALL -- SELECT ALL 3-WORD COMBINATIONS 
     SELECT w1.[Phrase] + ' ' + w2.[Phrase] + ' ' + w3.[Phrase] 
     FROM @tempPhrases w1 
     JOIN @tempPhrases w2 ON w1.[Index] + 1 = w2.[Index] 
     JOIN @tempPhrases w3 ON w1.[Index] + 2 = w3.[Index] 
     UNION ALL -- SELECT ALL 4-WORD COMBINATIONS 
     SELECT w1.[Phrase] + ' ' + w2.[Phrase] + ' ' + w3.[Phrase] + ' ' + w4.[Phrase] 
     FROM @tempPhrases w1 
     JOIN @tempPhrases w2 ON w1.[Index] + 1 = w2.[Index] 
     JOIN @tempPhrases w3 ON w1.[Index] + 2 = w3.[Index] 
     JOIN @tempPhrases w4 ON w1.[Index] + 3 = w4.[Index] 
    ) 

    -- ONLY INSERT THE NEW PHRASES IN THE Phrase TABLE  
    INSERT INTO @tempPhrases 
    SELECT 0, [Phrase] FROM CombinedPhrases 

    -- DELETE PHRASES WHICH ARE EXCLUDED 
    DELETE FROM @tempPhrases 
    WHERE [Phrase] IN 
    (
     SELECT [Text] FROM Phrases p 
     JOIN ExcludedPhrases ex 
     ON ex.ID = p.ID 
    ); 

    MERGE INTO Phrases p 
    USING 
    (
     SELECT DISTINCT Phrase FROM @tempPhrases 
    ) t 
    ON p.[Text] = t.Phrase 
    WHEN NOT MATCHED THEN 
     INSERT VALUES (t.Phrase); 


    -- Finally create relations between the phrases and feeditem, 
    MERGE INTO FeedItemPhrases p 
    USING 
    (
     SELECT @item as [Item], MIN(p.[ID]) as Phrase, COUNT(t.[Phrase]) as [Count] 
     FROM Phrases p WITH (NOLOCK) 
     JOIN @tempPhrases t ON p.[Text] = t.[Phrase] 
     GROUP BY t.[Phrase] 
    ) t 
    ON p.FeedItem = t.Item 
    AND p.Phrase = t.Phrase 
    WHEN MATCHED THEN 
     UPDATE SET p.[Count] = t.[Count] 
    WHEN NOT MATCHED THEN 
     INSERT VALUES (t.[Item], t.Phrase, t.[Count]); 
END 

이상 :

ALTER Function [dbo].[RemoveNonAlphaCharacters](@Temp NVarChar(max)) 
Returns NVarChar(max) 
AS 
Begin 
    SELECT @Temp = REPLACE (@Temp, '%20', ' '); 

    While PatIndex('%[^a-z ]%', @Temp) > 0 
     Set @Temp = Stuff(@Temp, PatIndex('%[^a-z ]%', @Temp), 1, '') 
    Return @TEmp 
End 
+0

테이블 정의와 트리거를 게시하면 느리게 트리거가 잠금/차단됩니다. 이 정보가 없으면 많은 도움을주기가 불가능합니다. –

+0

트리거의 모든 처리가'dbo.RemoveNonAlphaCharacters()'와'dbo.usp_index_itemstring()'에서 이루어집니다. –

답변

1

나는 인터넷을 둘러 보았고, 자물쇠를 주장하지 않고 방아쇠를 당길 수있는 방법을 찾지 못했습니다. 따라서 저장 프로 시저를 통해 삽입을 선택합니다. 저장 프로 시저는 이전에 트리거에서 찾은 논리를 차례로 수행합니다. 이를 통해 실제 데이터가 삽입되고 삽입 잠금이 해제 된 후 트랜잭션에서 트리거 내용을 실행할 수있었습니다.

희망이 도움이됩니다.