ตรวจจับการเปลี่ยนแปลงในตาราง SQL Server


13

ในแอปพลิเคชันของฉันด้วยฐานข้อมูลที่รันบน SQL Server 2012 ฉันมีงาน (ภารกิจตามกำหนดเวลา) ที่ดำเนินการแบบสอบถามที่มีราคาแพงเป็นระยะและเขียนผลลัพธ์ลงในตารางที่แอปพลิเคชันสามารถสอบถามได้ในภายหลัง

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

ฉันมีความคิดต่อไปนี้:

  • เขียนการประทับเวลาที่มีการเปลี่ยนแปลงครั้งล่าสุดอย่างชัดเจนการตั้งค่าสถานะ "ต้องเป็นข้อความค้นหา" หรือสิ่งนี้ในตารางติดตามทุกครั้งที่ฉันเปลี่ยนบางสิ่งในตารางต้นฉบับ
  • ใช้ทริกเกอร์ในการทำเช่นเดียวกัน

อย่างไรก็ตามฉันอยากจะรู้ว่ามีวิธีที่มีน้ำหนักเบาในการตรวจสอบการเปลี่ยนแปลงในตารางโดยที่ฉันไม่ได้ติดตามการเขียนอย่างชัดเจนหรือไม่ ยกตัวอย่างเช่นฉันจะได้รับ "ปัจจุบัน" ROWVERSIONของตารางหรืออะไรแบบนั้น?

คำตอบ:


14

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

ดังนั้นคุณจะต้องควั่นเพื่อจัดการมันผ่านรหัสที่กำหนด นั่นหมายถึงทริกเกอร์เนื่องจากทางเลือกอื่น (การตรวจจับจากบันทึกการทำงาน) เป็นสิทธิพิเศษที่สงวนไว้สำหรับการจำลองแบบของทรานแซคชันเท่านั้น (หรือCDC alter-ego) โปรดทราบว่าหากคุณพยายามติดตามผ่านคอลัมน์ 'อัปเดตครั้งล่าสุดที่' คุณจะต้องเผชิญกับปัญหาการทำให้เป็นอนุกรมที่กล่าวถึงข้างต้น หากการอัปเดตพร้อมกันเป็นสิ่งสำคัญคุณจะต้องใช้กลไกคิว (ทริกเกอร์ใช้ INSERT แล้วกระบวนการจะรวมค่าที่แทรกไว้เพื่อกำหนด 'อัปเดตครั้งล่าสุดเมื่อ') อย่าพยายามที่จะโกงกับบางส่วนวิธีการแก้ปัญหา 'ฉลาด' เหมือนด้อมที่ตัวตนในปัจจุบันหรือมองขึ้นไปsys.dm_db_index_usage_stats และยังมีคอลัมน์ 'updated_at' ต่อเรกคอร์ดเช่นเดียวกับเวลาประทับของ Rails

มีทางเลือกใด 'เบา' หรือไม่? ที่จริงมีหนึ่ง แต่มันเป็นเรื่องยากที่จะบอกว่ามันจะทำงานให้คุณและเป็นเรื่องยากที่จะได้รับมันขวา: การแจ้งเตือนแบบสอบถาม Query Notification จะทำเช่นนั้นโดยจะตั้งค่าการแจ้งเตือนหากมีข้อมูลใดเปลี่ยนแปลงและคุณต้องรีเฟรชคิวรีของคุณ แม้ว่า devs ส่วนใหญ่จะคุ้นเคยกับการแปลงชาติเป็น. Net เป็น SqlDependency เท่านั้น Query Notification สามารถใช้เป็นกลไกที่ยืนยาวและยืนยาวเพื่อตรวจจับการเปลี่ยนแปลงข้อมูล เมื่อเปรียบเทียบกับการติดตามการเปลี่ยนแปลงที่แท้จริงจะมีน้ำหนักเบามากและความหมายของมันใกล้เคียงกับความต้องการของคุณมากขึ้น (บางสิ่งมีอะไรเปลี่ยนแปลงดังนั้นคุณต้องเรียกใช้แบบสอบถามอีกครั้ง)

แต่ในท้ายที่สุดในสถานที่ของคุณฉันจะพิจารณาสมมติฐานของฉันและกลับไปที่กระดานวาดภาพ บางทีคุณสามารถใช้บันทึกการจัดส่งหรือการจำลองแบบเพื่อตั้งค่าฐานข้อมูลการรายงานบนเซิร์ฟเวอร์อื่น สิ่งที่ฉันอ่านระหว่างบรรทัดคือคุณต้องการ ETL ไปป์ไลน์ที่เหมาะสมและคลังข้อมูลการวิเคราะห์ ...


ดังนั้นทำไมไมโครซอฟท์จะรบกวนการสร้าง sys.dm_db_index_usage_stats หากข้อมูลนั้นไม่สามารถเชื่อถือได้
Craig Efrein

มันไม่ได้เป็น DMV ออกแบบมาสำหรับการติดตามการเปลี่ยนแปลง มีความน่าเชื่อถือมากสำหรับวัตถุประสงค์ที่ต้องการซึ่งเป็นการปรับประสิทธิภาพ
Remus Rusanu

8

ดูเหมือนว่าฉันจะไปเล่นเกมสองปีแล้วที่นี่ แต่จริงๆแล้วมันมีวิธีการทำสิ่งที่คุณต้องการอย่างจริงจัง

มีกลไก SQL Server สองตัวที่สามารถช่วยคุณได้ ทางออกที่ดีที่สุดของคุณอาจเป็นลูกผสมของทั้งสอง

การติดตามการเปลี่ยนแปลง SQL Server มีความสามารถในการวางตารางเฉพาะภายใต้การเฝ้าดู, บันทึกเฉพาะแถวที่มีการเปลี่ยนแปลง (โดยค่าคีย์หลักของพวกเขา), และชนิดของการเปลี่ยนแปลงที่เป็น (แทรก, อัพเดต, หรือลบ) เมื่อคุณตั้งค่าการตรวจจับการเปลี่ยนแปลงในชุดของตารางแบบสอบถามแบบ Lightweight สามารถบอกคุณได้ว่ามีการเปลี่ยนแปลงใด ๆ กับตารางตั้งแต่ครั้งสุดท้ายที่คุณตรวจสอบหรือไม่ ค่าใช้จ่ายอยู่ที่ประมาณเดียวกับการบำรุงรักษาดัชนีง่ายเพิ่มเติม

Rowversion / การประทับเวลา นี่คือคอลัมน์ varbinary ขนาด 8 ไบต์ (castable to BigInt) ที่เพิ่มขึ้นฐานข้อมูลกว้างเมื่อใดก็ตามที่แถวที่มีหนึ่งถูกแทรกหรือถูกปรับปรุง (มันไม่ได้ช่วยในการลบ) หากคุณจัดทำดัชนีคอลัมน์เหล่านี้คุณสามารถบอกได้อย่างง่ายดายว่าข้อมูลแถวมีการเปลี่ยนแปลงโดยการเปรียบเทียบ MAX (การประทับเวลา) กับค่าของมันตั้งแต่ครั้งล่าสุดที่ประเมิน เนื่องจากค่าเพิ่มขึ้นแบบ monotonically สิ่งนี้จะช่วยให้คุณมีข้อบ่งชี้ที่น่าเชื่อถือว่าข้อมูลมีการเปลี่ยนแปลงหากค่าใหม่นั้นใหญ่กว่าครั้งสุดท้ายที่คุณตรวจสอบ


7

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

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

ทางเลือกที่เบาเพื่อจับเปลี่ยนข้อมูลการติดตามการเปลี่ยนแปลง มันจะไม่บอกคุณว่ามีการเปลี่ยนแปลงค่าเพียงแค่ว่าแถวมีการเปลี่ยนแปลงตั้งแต่มันถูกสอบถามครั้งสุดท้าย ฟังก์ชั่นในตัวช่วยในการเรียกค้นค่าที่เปลี่ยนแปลงและการจัดการการติดตาม เราประสบความสำเร็จในการใช้ CT ในการประมวลผลประมาณ 100,000 การเปลี่ยนแปลงต่อวันในตารางแถวละ 100,000,000

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

ในบริบทของคำถามของ OP นั้น QN จะมีความได้เปรียบในการตั้งค่าใช้จ่ายต่ำและค่าใช้จ่ายในการดำเนินการน้อย มันอาจเป็นความพยายามที่สำคัญในการสร้างและรักษาระบบการสมัครรับข่าวสารทางข้อความที่เข้มงวด เนื่องจากตารางข้อมูลมีขนาดใหญ่จึงมีแนวโน้มที่จะมีการเปลี่ยนแปลงบ่อยครั้งหมายความว่าการแจ้งเตือนมีแนวโน้มที่จะเริ่มทำงานในรอบการประมวลผลส่วนใหญ่ เนื่องจากไม่มีข้อบ่งชี้ว่าการประมวลผลส่วนเพิ่มที่เปลี่ยนแปลงของ deltas จะไม่สามารถทำได้เช่นเดียวกับ CT หรือ CDC ค่าใช้จ่ายเนื่องจากการเรียกที่ผิดเป็นเรื่องน่าเบื่อ แต่แม้ในกรณีที่เลวร้ายที่สุดแบบสอบถามราคาแพงก็ไม่จำเป็นต้องเรียกใช้บ่อยกว่าที่เป็นอยู่ในปัจจุบัน


3

SqlTableDependency

SqlTableDependency เป็นส่วนประกอบการใช้งานระดับสูงในการเข้าถึงการแจ้งเตือนที่มีค่าบันทึกตารางในฐานข้อมูล SQL Server

SqlTableDependency เป็นส่วนประกอบ C # ทั่วไปที่ใช้รับการแจ้งเตือนเมื่อเนื้อหาของตารางฐานข้อมูลที่ระบุเปลี่ยนไป

ความแตกต่างกับ. NET SqlDepenency คืออะไร?

โดยทั่วไปความแตกต่างที่สำคัญคือ SqlTableDependency ส่งเหตุการณ์ที่มีค่าสำหรับบันทึกที่แทรกเปลี่ยนแปลงหรือลบรวมถึงการดำเนินการ DML (แทรก / ลบ / ปรับปรุง) ที่ดำเนินการบนตาราง: SqlDepenency ไม่ได้บอกว่าข้อมูลถูกเปลี่ยนแปลงใน ตารางฐานข้อมูลพวกเขาบอกว่ามีอะไรบางอย่างเปลี่ยนไป

มีลักษณะที่โครงการ GitHub


1

หากการอัปเดตที่คุณคาดว่าจะส่งผลกระทบต่อดัชนี (และถ้าทำได้ ) คุณสามารถใช้ตารางระบบsys.dm_db_index_usage_statsเพื่อตรวจหาการอัปเดตล่าสุดไปยังดัชนีในตารางที่เป็นปัญหา คุณต้องการใช้last_user_updateสนาม

ตัวอย่างเช่นหากต้องการรับตารางที่อัปเดตล่าสุด:

select
    object_name(object_id) as OBJ_NAME, *
from
    sys.dm_db_index_usage_stats
where
    database_id = db_id(db_name())
order by
    dm_db_index_usage_stats.last_user_update desc

หรือหากต้องการตรวจสอบว่ามีการเปลี่ยนแปลงตารางเฉพาะตั้งแต่วันที่ระบุหรือไม่:

select
    case when count(distinct object_id) > 0 then 1 else 0 end as IS_CHANGED
from
    sys.dm_db_index_usage_stats
where
    database_id = db_id(db_name())
    and object_id = object_id('MY_TABLE_NAME')
    and last_user_update > '2016-02-18'

ความคิดเห็นของคุณเกี่ยวกับรีมัสเป็นอย่างไร "อย่าพยายามโกงโซลูชัน 'ฉลาด' บางอย่างเช่นการแอบดูตัวตนปัจจุบันหรือค้นหา sys.dm_db_index_usage_stats" (ดูความคิดเห็นของเขาที่ด้านล่างคำตอบของเขา)
Fabian Schmied

1
@FabianSchmied ที่น่าสนใจ - ฉันไม่เห็นว่าเมื่อฉันเพิ่มคำตอบของฉันฉันไม่สามารถหาสิ่งที่มีอำนาจนอกเหนือจากคำตอบของ Remus อื่นเพื่อระบุว่ามันไม่น่าเชื่อถือสำหรับกรณีการใช้งานนี้; หน้า MS สำหรับdm_db_index_operational_statsปัญหาการแสดง (เคลียร์เป็นล้างแคชข้อมูลเมตา) dm_db_index_usage_statsแต่ไม่ได้สำหรับ ปัญหาเดียวที่ฉันพบคือเมื่อสร้างดัชนีใหม่การรีสตาร์ทเซิร์ฟเวอร์และการปลดฐานข้อมูลจะล้างสถิติการใช้งานและดูเหมือนว่าจะไม่ได้นำไปใช้ที่นี่ จะมีความสนใจที่จะเห็นข้อมูลที่พิสูจน์ได้เกี่ยวกับเรื่องนี้
Geoff
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.