2014-02-06 71 views
0

我在表上有一个SQL触发器,插入,更新和删除后会触发。MSSQL触发器 - 问题

我将所有受影响的记录插入单独的物理表中,其中的代码定义了更新的状态。以下代码片段是定义的触发器。

CREATE TRIGGER [dbo].[DATA_CACHE] 
    ON [dbo].[DATA_USAGE] 
for Insert,Update,Delete 
AS 
BEGIN 
    if(select COUNT(*) from inserted)>0 
    begin 
     if (select COUNT(*) from deleted)>0 
     BEGIN 
      --update 
      INSERT INTO CACHE_UPDATE_TABLE (CODE, ID, DATE, COUNT) 
      SELECT 2, ins.ID, ins.DATE, ins.COUNT 
      from inserted ins 
     END 
     else 
     begin 
      -- insert 
      INSERT INTO CACHE_UPDATE_TABLE (CODE, ID, DATE, COUNT) 
      SELECT 1, ins.ID, ins.DATE, ins.COUNT 
      from inserted ins 
     end 
    END 
    else 
    BEGIN 
     -- delete 
     INSERT INTO CACHE_UPDATE_TABLE (CODE, ID, DATE, COUNT) 
     SELECT 3, del.ID, del.DATE, del.COUNT 
     from deleted del 
    end 
END 
SELECT * FROM CACHE_UPDATE_TABLE 

正如你可以在上面看到触发了我误触发后添加一个额外的语句,从目标选择表中所有的值。这个语句是在定义的触发器之后,但是当我试图改变触发器时,通过右键点击触发器并选择修改,它也向我展示了触发器结束块之后的select语句。

这是否意味着,每次触发器被触发时,这个select语句都会执行?这是我的第一个问题(问题A) - 可能是一个愚蠢的问题,但我对此有点困惑。

我的第二个问题是(问题B)我遇到了CACHE_UPDATE_TABLE锁定问题,这可能是锁定的原因吗?还有一个SQL作业每运行一分钟检查CACHE_UPDATE_TABLE表,然后执行一些操作(链接服务器相关),并在完成后从CACHE_UPDATE_TABLE删除这些记录。锁定问题可能是因为这个?如果是这样,我该如何反击呢?

我的第三个问题是(问题C)这是使用触发器执行此操作的最佳方式,还是我可以以其他方式执行此操作?触发器是否正确定义?

- 任何帮助将不胜感激...谢谢。

+0

你有很多的问题,在那里这就是为什么你还没有收到任何答案。例如,我可以部分地回答A并完全回答C,但不是B. – OGHaza

回答

1

你已经得到了很多在那里不同的问题,这可能是为什么您没有收到任何答案,但我将我所能。 A)这实际上是一个非常有趣的问题。我会假设它什么都不会做 - 它会在你创建触发器时被执行,但不会成为触发器的一部分 - 但是我注意到之前有过奇怪的行为,所以我使用一个简单的存储过程进行了测试:

CREATE PROCEDURE dbo.test (@i INT) AS 
BEGIN 
    SELECT @i 
END; 
SELECT 'hi' 
GO 

执行存储过程导致SELECT 'hi'火还有SELECT @i。对于你的问题,我仍然没有答案,但是当你仅仅因为这个原因创建它时,我肯定会确保不要在触发器外面有任何杂散SQL。

我刚刚调查了这一点,显然存储过程的末尾是第一个GO在过程之后的任何地方(如果不使用SQL Server,它会自动添加到最后)。所以你可以在END之后定义你的整个过程 - 你仍然可以使用这些参数。

这似乎是因为BEGINEND不是存储过程定义的一个必要组成部分 - 它们实际上并不表示开始和存储过程的结束,他们只是一个无关的BEGIN...END块喜欢你可能会提出和IF声明。您可以在程序定义中尽可能多地使用BEGIN...END块,或者根本没有。

C)我肯定会改变你的触发器。通过组合3个触发器而不重复使用任何代码,您已经大幅复杂化了它。结合INSERT,UPDATEDELETE触发器的唯一原因是,您不必重复代码。你应该:

  • 有3个单独的触发器,每个触发器只包含相关的INSERT - 这样你可以删除所有的条件逻辑。
  • 将它们放在一起,但仅使用一些条件逻辑编制CODE并且只有1个INSERT语句。

我会忍不住去与3个独立的触发器,或者至少一个独立出来的删除触发器,然后在INSERT/UPDATE触发使用CASE del.ID IS NULL THEN 1 ELSE 2 ENDCODE。但是你可以用(未经测试),将它们组合起来:

INSERT INTO CACHE_UPDATE_TABLE (CODE, ID, DATE, COUNT) 
SELECT CASE WHEN del.ID IS NULL THEN 1 
      WHEN ins.ID IS NULL THEN 3 
      ELSE 2 END 
    ,ISNULL(ins.ID, del.ID) 
    ,ISNULL(ins.DATE, del.DATE) 
    ,ISNULL(ins.COUNT, del.COUNT) 
FROM deleted del 
FULL OUTER JOIN inserted ins ON del.ID = ins.ID 
+0

感谢您的回复。加入触发器似乎仍然很昂贵。在我的触发器中,我只有两个条件,每次都会检查并插入。就性能而言,我不认为这会很昂贵。我可能是错的,我会测试一下。 但是,你的程序反应的方式非常奇怪,在END语句之后,无论你添加什么,它似乎都会被执行。 –

+0

在这些情况下,这两者都不会很昂贵,但是'IF'语句阻止了好的查询计划被缓存,所以我敢打赌'JOIN'会表现得更好 - 只有知道的方法才是基准测试。无疑,最好的性能来自3个独立的触发器,它们都会缓存理想的执行计划。 – OGHaza

+0

编辑我的答案,多一点关于A的信息 – OGHaza

0

只是删除

SELECT * FROM CACHE_UPDATE_TABLE 
+0

Dude,我已经将其删除了......我想知道为什么它在触发器外部执行。 –