ทริกเกอร์รวบรวมในแต่ละครั้งหรือไม่


22

เรากำลังแก้ไขปัญหาเซิร์ฟเวอร์ที่มีการใช้งาน CPU สูง หลังจากพบว่าคำค้นหาไม่ได้เป็นสาเหตุของปัญหาจริงๆเราเริ่มมองหาการรวบรวม

การตรวจสอบประสิทธิภาพแสดงน้อยกว่า 50 การคอมไพล์ / วินาทีและน้อยกว่า 15 การคอมไพล์ / วินาที

หลังจากใช้งานเซสชัน XE เพื่อค้นหาการรวบรวมเราจะเห็นการรวบรวมนับพันต่อวินาที

ระบบนี้ใช้ทริกเกอร์เพื่อตรวจสอบการเปลี่ยนแปลง การรวบรวมส่วนใหญ่เกิดจากทริกเกอร์ ทริกเกอร์การอ้างอิง sys.dm_tran_active_transactions

ความคิดแรกของเราคือการอ้างอิง DMV ในทริกเกอร์อาจทำให้คอมไพล์ในแต่ละครั้งหรืออาจเป็นเพียง DMV ที่เจาะจงนี้จะทำให้เกิดขึ้น ดังนั้นฉันจึงเริ่มทดสอบทฤษฎีนั้น มันจะรวบรวมในแต่ละครั้ง แต่ฉันไม่ได้ตรวจสอบว่ามีการทริกเกอร์รวบรวมในแต่ละครั้งจะถูกเรียกเมื่อมันไม่ได้อ้างอิง DMV และแทน hardcodes ค่า มันยังคงรวบรวมทุกครั้งที่มันถูกเรียก การปล่อยไกหยุดการรวบรวม

  1. เรากำลังใช้ sqlserver.query_pre_execution_showplan ในเซสชั่น XE เพื่อติดตามการคอมไพล์ ทำไมจึงมีความคลาดเคลื่อนระหว่างสิ่งนั้นกับตัวนับ PerfMon
  2. เป็นเรื่องปกติหรือไม่ที่คุณได้รับเหตุการณ์การคอมไพล์ทุกครั้งที่ทริกเกอร์รัน?

สคริปต์ Repro:

CREATE TABLE t1 (transaction_id int, Column2 varchar(100));
CREATE TABLE t2 (Column1 varchar(max), Column2 varchar(100));
GO

CREATE TRIGGER t2_ins
ON t2
AFTER INSERT
AS

INSERT INTO t1
SELECT (SELECT TOP 1 transaction_id FROM sys.dm_tran_active_transactions), Column2
FROM inserted;
GO

--Both of these show compilation events
INSERT INTO t2 VALUES ('row1', 'value1');
INSERT INTO t2 VALUES ('row2', 'value2');
GO

ALTER TRIGGER t2_ins
ON t2
AFTER INSERT
AS

INSERT INTO t1
SELECT 1000, Column2
FROM inserted;
GO

--Both of these show compilation events
INSERT INTO t2 VALUES ('row3', 'value3');
INSERT INTO t2 VALUES ('row4', 'value4');

DROP TRIGGER t2_ins;

--These do not show compilation events
INSERT INTO t2 VALUES ('row5', 'value5');
INSERT INTO t2 VALUES ('row6', 'value6');

DROP TABLE t1, t2;

คำตอบ:


20

เหตุการณ์ XE ที่ใช้อยู่นำคุณไปอย่างไม่ถูกต้องที่จะคิดว่าทริกเกอร์นั้นรวบรวมทุกการกระทำ มีเหตุการณ์เพิ่มเติมสองเหตุการณ์คือ query_pre_execution_showplan และ query_post_compilation_showplan ที่มีคำอธิบายที่คล้ายกัน แต่ต่างกันด้วยคำสำคัญหนึ่งคำ:

query_pre_execution_showplan

เกิดขึ้นหลังจากรวบรวมคำสั่ง SQL เหตุการณ์นี้กลับแสดง XML ของแผนแบบสอบถามโดยประมาณที่ถูกสร้างขึ้นเมื่อแบบสอบถามจะเพิ่มประสิทธิภาพ การใช้เหตุการณ์นี้อาจมีค่าใช้จ่ายด้านประสิทธิภาพที่สำคัญดังนั้นจึงควรใช้เมื่อแก้ไขปัญหาหรือตรวจสอบปัญหาเฉพาะช่วงเวลาสั้น ๆ เท่านั้น

query_post_compilation_showplan

เกิดขึ้นหลังจากรวบรวมคำสั่ง SQL เหตุการณ์นี้กลับแสดง XML ของแผนแบบสอบถามคาดว่าถูกสร้างขึ้นเมื่อแบบสอบถามจะรวบรวม การใช้เหตุการณ์นี้อาจมีค่าใช้จ่ายด้านประสิทธิภาพที่สำคัญดังนั้นจึงควรใช้เมื่อแก้ไขปัญหาหรือตรวจสอบปัญหาเฉพาะช่วงเวลาสั้น ๆ เท่านั้น

เหตุการณ์ไม่เหมือนกันในรายละเอียดและเกิดขึ้นในเวลาที่ต่างกันจากการทดสอบเพิ่มเติมโดยใช้ repro ของคุณ การใช้นิยามเซสชันเหตุการณ์ที่มีขนาดใหญ่ขึ้นเป็นเรื่องง่ายที่จะเห็นว่าการรวบรวมเกิดขึ้นจริงที่ไหน

ป้อนคำอธิบายรูปภาพที่นี่

ที่นี่คุณสามารถเห็นการคอมไพล์ครั้งแรกที่เกิดขึ้นสำหรับคำสั่งแทรกตามแผนที่เตรียมไว้ซึ่งถูกปรับพารามิเตอร์อัตโนมัติในกล่องสีเขียว ทริกเกอร์รวบรวมในกล่องสีแดงและแผนถูกแทรกลงในแคชตามที่แสดงโดยเหตุการณ์ sp_cache_insert จากนั้นในกล่องสีส้มการเรียกใช้งานทริกเกอร์จะได้รับการเข้าชมแคชและนำแผนทริกเกอร์สำหรับคำสั่ง INSERT ที่สองในแบทช์กลับมาใช้ใหม่ดังนั้นจึงไม่ได้รวบรวมทุกการดำเนินการของคำสั่ง INSERT และแผนจะนำกลับมาใช้ใหม่ สำหรับทริกเกอร์

หากเราเรียกใช้คำสั่ง INSERT สองรายการแยกกันอีกครั้งหลังจากการดำเนินการครั้งแรกทริกเกอร์จะไม่รวบรวมอีกครั้งดังที่แสดงในเหตุการณ์ด้านล่าง:

ป้อนคำอธิบายรูปภาพที่นี่

ที่นี่คำสั่งแรกพบกับการเข้าชมแคชสำหรับรุ่นที่ปรับพารามิเตอร์อัตโนมัติของคำสั่งในแคช แต่พลาดสำหรับชุด Adhoc ที่ถูกส่ง ทริกเกอร์ได้รับการเข้าชมแคชและจะไม่รวบรวมอีกครั้งตามที่แสดงในบล็อกสีแดงของเหตุการณ์ บล็อกสีเขียวของเหตุการณ์จะทำซ้ำลักษณะการทำงานนี้สำหรับคำสั่ง INSERT ที่สองที่เรียกใช้เป็นชุดแยกต่างหาก อย่างไรก็ตามในทุกกรณีคุณยังคงเห็นเหตุการณ์ query_pre_execution_showplan ซึ่งฉันสามารถระบุความแตกต่างในการปรับให้เหมาะสมกับการคอมไพล์ในคำอธิบายเหตุการณ์ แต่ทริกเกอร์ไม่ได้รวบรวมสำหรับการดำเนินการตามที่แสดงโดยชุดเหตุการณ์เหล่านี้


หากคุณดูที่ภาพหน้าจอแรกเหตุการณ์ sql_batch_statistics ที่ไม่ได้ใช้งานอยู่ในคอลเล็กชัน แต่จะเริ่มทำงานสำหรับการเรียกใช้งานชุดแรกของ sql เมื่อแคชถูกล้างและแผนแปรพารามิเตอร์อัตโนมัติสำหรับ INSERT นั้นไม่ได้อยู่ในแคชแผน หลังจากนั้นเหตุการณ์ uncached_sql_batch_statistics จะไม่เริ่มทำงานอีก
Jonathan Kehayias

query_post_compilation_showplan แสดงการรวบรวมทริกเกอร์เพียงเล็กน้อย แต่ไม่ใช่จำนวนมหาศาลที่เราเห็นในเหตุการณ์อื่น เราพบนักเก็ตที่น่าสนใจด้วย query_post_compilation_showplan ขอบคุณสำหรับข้อมูล Jonathan!
Tara Kizer

13

ไม่ทริกเกอร์จะไม่คอมไพล์ใหม่เสมอ คำสั่งแบบสอบถามอย่างง่าย แต่ไม่ได้รับแผนการของพวกเขาแคชและดังนั้นจึงมักจะคอมไพล์ใหม่

ทริกเกอร์จะได้รับการคอมไพล์ใหม่หากจำนวนของแถวในแทรกหรือลบการเปลี่ยนแปลงอย่างมีนัยสำคัญ ดูที่: https://technet.microsoft.com/en-us/library/ms181055.aspx

ฉันไม่ทราบว่าพวกเขามีเหมือนกันใน XEvents หรือไม่ แต่ใน SQL Trace การคอมไพล์ใหม่มีคลาสย่อยของเหตุการณ์ที่บอกคุณว่าเหตุใดจึงมีการคอมไพล์ใหม่ ที่อธิบายไว้ในลิงก์เดียวกันข้างต้น


1
เรากำลังดูการรวบรวมมากกว่าการคอมไพล์ เราจะตรวจสอบเซิร์ฟเวอร์ในวันพรุ่งนี้และตรวจสอบว่าเป็นเพราะคำสั่งแบบสอบถามอย่างง่ายหรือหากเป็นเพราะจำนวนแถว ขอบคุณ!
Tara Kizer
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.