2

我有一种非常可疑的感觉,这个更新触发器正在更新目标上的所有行,而不仅仅是那些满足“更新(形状)”测试的行。性能很好,直到我添加了第二个操作。单个空间连接发生得更快,这不是空间索引问题,而且该数据集中只有几条记录。

ALTER TRIGGER   [dbo].[GRSM_WETLANDS_Point_GIS_tbl_locations_update]
ON  [dbo].[GRSM_WETLANDS_POINT]
after update  
AS   
BEGIN   
  SET NOCOUNT ON;  
  if UPDATE (shape)
update GRSM_WETLANDS_Point
set X_Coord =CASE WHEN u.shape.STDimension() = 2 THEN u.shape.STCentroid().STX ELSE u.shape.STEnvelope().STCentroid().STX END,
    Y_Coord =CASE WHEN u.shape.STDimension() = 2 THEN u.shape.STCentroid().STY ELSE u.shape.STEnvelope().STCentroid().STY END
    from inserted i 
inner join GRSM_WETLANDS_POint u on i.GIS_Location_ID = u.GIS_Location_ID;
--second spatial operation
update GRSM_WETLANDS_Point
set QuadName = grsm.dbo.USGS_24K_TOPOMAP_BOUNDARIES.name 

FROM GRSM_WETLANDS_POint i
inner join grsm.dbo.USGS_24K_TOPOMAP_BOUNDARIES  
on i.GIS_Location_ID = i.GIS_Location_ID  
WHERE  (USGS_24K_TOPOMAP_BOUNDARIES.Shape.STContains(i.SHAPE) = 1) ;

end

我的怀疑是对的吗?

更新:根据 Aaron 的建议...解决了所有行的火灾问题。

update GRSM_WETLANDS_Point
set QuadName = grsm.dbo.USGS_24K_TOPOMAP_BOUNDARIES.name 
FROM inserted i inner join GRSM_WETLANDS_POint u on i.GIS_Location_ID = u.GIS_Location_ID
left outer join  grsm.dbo.USGS_24K_TOPOMAP_BOUNDARIES  
on i.GIS_Location_ID = i.GIS_Location_ID  
WHERE  (USGS_24K_TOPOMAP_BOUNDARIES.Shape.STContains(i.SHAPE) = 1); 
4

2 回答 2

3

如果Shape不能为 NULL,查看它是否已更改的更好方法是检查inserted和中的值deleted是否不同。例如:

IF EXISTS
(
  SELECT 1 FROM inserted AS i
  INNER JOIN deleted AS d
  ON i.GIS_Location_ID = d.GIS_Location_ID
  WHERE i.Shape.STEquals(d.Shape) = 0
)
BEGIN
  ...
END

如果Shape可以为空,那么您只需在此处添加更多条件进行检查,例如

  WHERE 
  (
    (i.Shape IS NULL AND d.Shape IS NOT NULL
    OR (i.Shape IS NOT NULL AND d.Shape IS NULL)
    OR (i.Shape.STEquals(d.Shape) = 0)
  )

(您可能不在乎是否Shape已更新 NULL,我只是在说明如何测试这种情况。)

由于该操作可能发生在多行上,并且此条件将仅标识已发生至少一个此类更新(但不是所有行都满足条件),因此最好让您的操作在 WHERE 子句中包含类似的条件。事实上,我认为您可以在一个操作中执行两个更新,例如

ALTER TRIGGER [dbo].[GRSM_WETLANDS_Point_GIS_tbl_locations_update]
ON  [dbo].[GRSM_WETLANDS_POINT]
AFTER UPDATE
AS   
BEGIN   
  SET NOCOUNT ON; 

  UPDATE p SET 
    X_Coord = CASE WHEN i.shape.STDimension() = 2 
      THEN i.shape.STCentroid().STX 
      ELSE i.shape.STEnvelope().STCentroid().STX 
    END,
    Y_Coord = CASE WHEN i.shape.STDimension() = 2 
      THEN i.shape.STCentroid().STY 
      ELSE i.shape.STEnvelope().STCentroid().STY 
    END, 
    QuadName = COALESCE(b.name, p.QuadName)
  FROM 
    dbo.GRSM_WETLANDS_Point AS p
  INNER JOIN 
    inserted AS i
    ON i.GIS_Location_ID = p.GIS_Location_ID
  LEFT OUTER JOIN grsm.dbo.USGS_24K_TOPOMAP_BOUNDARIES AS b
    ON b.Shape.STContains(i.Shape) = 1
  WHERE EXISTS 
  (
    SELECT 1 FROM inserted AS i2
      INNER JOIN deleted AS d
      ON i2.GIS_Location_ID = d.GIS_Location_ID
      WHERE i2.GIS_Location_ID = i.GIS_Location_ID
      AND i2.Shape.STEquals(d.Shape) = 0
      -- ...and NULL handling if necessary
  );
END
GO

一般来说,您似乎在实现触发器时遇到了很多麻烦,并且对语法应该如何工作做出了很多猜测。您是否考虑过通过存储过程强制数据更新,您可以在其中控制所有这些业务逻辑,但消除伪表inserteddeleted伪表增加的复杂性?

于 2012-06-10T20:17:14.793 回答
2

如果 UPDATE (shape) 即使值没有改变也会触发,如果更新语句中存在该列,它将触发

而且您没有在第二次更新中加入 INSERTED

于 2012-06-10T19:44:16.057 回答