การเข้าใจปัญหาทริกเกอร์แทรกใน SQL Server 2005
เมื่อทำงานกับ SQL Server 2005 คุณอาจจะพบสถานการณ์ที่ทริกเกอร์ของคุณแทรกเรคอร์ดเพียงเรคอร์ดเดียวในตารางเป้าหมายแม้ว่าการทำธุรกรรมแทรกหลักจะสร้างเรคอร์ดหลายเรคอร์ด นี่อาจเป็นเรื่องที่น่าผิดหวังโดยเฉพาะอย่างยิ่งเมื่อคุณใช้การตั้งค่าย่อยเพื่อแทรกข้อมูลลงในตารางหลัก ในโพสต์นี้เราจะไปผ่านปัญหาทั่วไปและวิธีแก้ไขในรายละเอียด
อธิบายปัญหา
ลองนึกภาพว่าคุณมีตารางชื่อ tblMenuItems
และเมื่อแทรกเรคอร์ดใหม่ลงไป คุณต้องการให้ทริกเกอร์ tblMenuItemInsertSecurity
แทรกเรคอร์ดลงในตารางอีกตาราง (tblRestrictedMenuItems
) โดยอัตโนมัติ ทริกเกอร์ดูเหมือนว่าจะทำงานได้ดีในกรณีที่มีการแทรกเรคอร์ดเดียว แต่ไม่ทำงานตามที่คาดหวังเมื่อมีการแทรกเรคอร์ดหลายเรคอร์ดในคราวเดียวโดยใช้การตั้งค่าย่อย
นี่คือคำสั่งแทรก
INSERT INTO [tblMenuItems] ([ID], [MenuID], [SortOrder], [ItemReference], [MenuReference], [ConcurrencyID])
SELECT [ID], [MenuID], [SortOrder], [ItemReference], [MenuReference], [ConcurrencyID]
FROM [IVEEtblMenuItems]
รหัสทริกเกอร์ตัวอย่าง
CREATE TRIGGER [dbo].[tblMenuItemInsertSecurity] ON [dbo].[tblMenuItems]
FOR INSERT
AS
BEGIN
DECLARE @iRoleID int
DECLARE @iMenuItemID int
SELECT @iMenuItemID = [ID] FROM Inserted
DECLARE tblUserRoles CURSOR FASTFORWARD FOR SELECT [ID] FROM tblUserRoles
OPEN tblUserRoles
FETCH NEXT FROM tblUserRoles INTO @iRoleID
WHILE (@@FetchStatus = 0)
BEGIN
INSERT INTO tblRestrictedMenuItems(
[RoleID],
[MenuItemID],
[RestrictLevel])
VALUES(
@iRoleID,
@iMenuItemID,
1)
FETCH NEXT FROM tblUserRoles INTO @iRoleID
END
CLOSE tblUserRoles
DEALLOCATE tblUserRoles
END
การเข้าใจว่าทำไมทริกเกอร์ถึงล้มเหลว
สาเหตุหลักที่ทริกเกอร์ของคุณไม่แทรกเรคอร์ดหลายเรคอร์ดคือการใช้งานตารางเสมือน Inserted
เมื่อตัวกระตุ้นทำงาน ตาราง Inserted
จะประกอบด้วยแถวทั้งหมดที่กำลังจะถูกแทรก แต่ตรรกะของทริกเกอร์ของคุณกลับประมวลผลเฉพาะแถวแรกเท่านั้น
แนวคิดสำคัญที่ต้องเข้าใจ
-
ทริกเกอร์และแถว: ใน SQL Server ทริกเกอร์จะทำงานเพียงครั้งเดียวสำหรับการกระทำการกระตุ้นต่อแต่ละชนิด (แทรก, อัปเดต, ลบ) และสามารถจัดการกับหลายแถวในเวลาเดียวกันได้
-
ตารางเสมือน Inserted: ตารางนี้ช่วยให้เข้าถึงเรคอร์ดที่กำลังจะถูกแทรก และมีแถวทั้งหมดไม่ใช่แค่แถวแรก
วิธีแก้ไข: ปรับปรุงตรรกะของทริกเกอร์
เพื่อจัดการการแทรกสำหรับหลายเรคอร์ดได้อย่างมีประสิทธิภาพ คุณสามารถปรับโครงสร้างทริกเกอร์ของคุณได้สองวิธี: ใช้ลูปกับตัวชี้หรือลดการใช้ลูปโดยใช้การดำเนินการที่มีชุดข้อมูลซึ่งมีประสิทธิภาพมากกว่า
1. ปรับโครงสร้างด้วยตัวชี้
สามารถทำการวนรอบผ่านตารางเสมือน Inserted
โดยใช้ตัวชี้ แต่ควรระวังว่าการใช้วิธีนี้อาจทำให้เกิดปัญหาด้านประสิทธิภาพเมื่อทำงานกับชุดข้อมูลขนาดใหญ่
นี่คือเวอร์ชันที่ปรับปรุงของทริกเกอร์ของคุณโดยใช้ตัวชี้:
CREATE TRIGGER [dbo].[tblMenuItemInsertSecurity] ON [dbo].[tblMenuItems]
FOR INSERT
AS
BEGIN
DECLARE @iRoleID int
DECLARE @iMenuItemID int
DECLARE tblUserRoles CURSOR FASTFORWARD FOR SELECT [ID] FROM tblUserRoles
OPEN tblUserRoles
FETCH NEXT FROM tblUserRoles INTO @iRoleID
-- วนรอบผ่านแต่ละแถวในตาราง Inserted
DECLARE tblInserted CURSOR FOR SELECT [ID] FROM Inserted
OPEN tblInserted
FETCH NEXT FROM tblInserted INTO @iMenuItemID
WHILE @@FETCH_STATUS = 0
BEGIN
WHILE (@@FetchStatus = 0)
BEGIN
INSERT INTO tblRestrictedMenuItems(
[RoleID],
[MenuItemID],
[RestrictLevel])
VALUES(
@iRoleID,
@iMenuItemID,
1)
FETCH NEXT FROM tblUserRoles INTO @iRoleID
END
FETCH NEXT FROM tblInserted INTO @iMenuItemID
END
CLOSE tblInserted
DEALLOCATE tblInserted
CLOSE tblUserRoles
DEALLOCATE tblUserRoles
END
2. ใช้การดำเนินการตามชุดข้อมูล (แนะนำ)
วิธีนี้มีประสิทธิภาพมากกว่าและช่วยหลีกเลี่ยงการวนรอบที่ไม่จำเป็น
ลองเปลี่ยนตรรกะเพื่อเชื่อมโยงโดยตรงกับตาราง Inserted
:
CREATE TRIGGER [dbo].[tblMenuItemInsertSecurity] ON [dbo].[tblMenuItems]
FOR INSERT
AS
BEGIN
INSERT INTO tblRestrictedMenuItems ([RoleID], [MenuItemID], [RestrictLevel])
SELECT u.[ID], i.[ID], 1
FROM tblUserRoles u
JOIN Inserted i ON <condition if needed>
END
รหัสนี้ช่วยให้มั่นใจว่ามีการแทรกเรคอร์ดที่เหมาะสมจำนวนมากในตาราง tblRestrictedMenuItems
สำหรับแต่ละแถวในตาราง Inserted
สรุป
โดยการเข้าใจพฤติกรรมของทริกเกอร์และการใช้งานตารางเสมือน Inserted
อย่างถูกต้อง คุณสามารถมั่นใจได้ว่าทริกเกอร์ของ SQL Server 2005 ของคุณทำงานได้อย่างมีประสิทธิภาพเมื่อมีการแทรกเรคอร์ดหลายรายการ เลือกระหว่างวิธีการวนรอบหรือชุดข้อมูลตามบริบทเฉพาะของคุณเพื่อประสิทธิภาพสูงสุด
หากคุณทำตามขั้นตอนที่กล่าวไว้ข้างต้นเพื่อปรับปรุงทริกเกอร์ คุณน่าจะเริ่มเห็นพฤติกรรมที่ต้องการ และมีการแทรกเรคอร์ดหลายเรคอร์ดลงในตารางเป้าหมายของคุณเมื่อทำการแทรกหลายรายการในตารางหลัก