2010-04-09 43 views
0

我有一个严重的性能问题。SQL Server 2008插入后运行触发器,更新锁定原始表

我有一个数据库(与此问题有关),2个表。

1表包含具有某些全局信息的字符串。第二个表格包含剥离到每个单词的字符串。所以这个字符串就像在第二个表中逐个索引一样。

第二个表中的数据的有效性不如第一个表中的数据的有效性那么重要。

由于第一个表可以像1 * 10^6记录一样增长,而第二个表对于1个字符串具有平均10个单词的平均值可以像1 * 10^7记录一样增长,所以我使用nolock来读取第二个这使我可以自由地插入新记录而不锁定它(期望在两个表上有很多读取)。

我有一个脚本,不断向MERGE语句中的第一个表添加和更新行。平均来说,合并的数据每次像20个字符串,脚本每5秒钟运行一次。

在第一个表上,我有一个触发器,它在Insert或Update上被调用,它接受新插入或更新的数据,并调用一个存储过程来确保数据在第二个表中被索引。 (这需要一些相当长的时间)。

问题是,当触发器disbaled时,读取第一个表发生在几个毫秒。但是,启用触发器时,如果在更新时尝试读取第一个表,您的运气不好,我们的Web服务器会在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); 

的存储过程:IndexItemStrings被填充的第二个表,执行该进程内确实需要他的时间。问题在于执行此触发器时。适用于FeedItems表的查询大多超时(甚至谁不使用第二个表的查询)

第一个表:

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 

多:

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

发表表格定义和触发器,你缓慢的触发器锁定/阻止你。如果没有这些信息,就不可能提供很多帮助 – 2010-04-09 12:43:25

+0

触发器中的所有处理都在'dbo.RemoveNonAlphaCharacters()'和'dbo.usp_index_itemstring()'中完成,您是否也可以发布该代码? – 2010-04-09 13:57:59

回答

1

我在互联网上四处张望,我找不到任何方式使得触发器没有声称锁。因此我选择通过存储过程来执行插入操作,然后执行之前在触发器中找到的逻辑。这使我可以在插入实际数据并解除插入锁定后执行事务中触发器的内容。

希望这会有所帮助!

相关问题