มีวิธีการป้องกันไม่ให้ Scalar UDFs ในคอลัมน์ที่คำนวณได้จากการยับยั้งความเท่าเทียมกันหรือไม่?


29

มีการเขียนมากมายเกี่ยวกับภัยของ Scalar UDFใน SQL Server การค้นหาทั่วไปจะส่งคืนผลลัพธ์จำนวนมาก

มีสถานที่บางแห่งที่ Scalar UDF เป็นตัวเลือกเท่านั้น

เป็นตัวอย่าง: เมื่อจัดการกับ XML: XQuery ไม่สามารถใช้เป็นข้อกำหนดคอลัมน์ที่คำนวณได้ ทางเลือกหนึ่งที่มีการบันทึกโดย Microsoft คือการใช้Scalar UDFเพื่อแค็ปซูล XQuery ของคุณใน Scalar UDF จากนั้นใช้ในคอลัมน์ที่คำนวณ

สิ่งนี้มีเอฟเฟกต์ต่าง ๆ และวิธีแก้ปัญหาบางอย่าง

  • ดำเนินการทีละแถวเมื่อมีการสอบถามตาราง
  • บังคับให้คิวรีทั้งหมดกับตารางทำงานแบบอนุกรม

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

มีวิธีที่รู้จักกันในการทำเช่นนั้น?

คำตอบ:


31

ใช่ถ้าคุณ:

  • ใช้ SQL Server 2014 หรือใหม่กว่า; และ
  • สามารถเรียกใช้คิวรีที่มีค่าสถานะการสืบค้นกลับ 176ใช้งานอยู่ และ
  • คอลัมน์ที่คำนวณคือ PERSISTED

โดยเฉพาะอย่างน้อยต้องมีเวอร์ชันต่อไปนี้:

  • การปรับปรุงที่สะสม 2 สำหรับ SQL Server 2016 SP1
  • การปรับปรุง 4 สำหรับ SQL Server 2016 RTM
  • 6 การปรับปรุงที่สะสมสำหรับ SQL Server 2014 SP2

แต่เพื่อหลีกเลี่ยงข้อผิดพลาด (อ้างอิงสำหรับปี 2014และสำหรับปี 2016 และ 2017 ) มีการแนะนำในการแก้ไขเหล่านั้นให้ใช้แทน:

การตั้งค่าสถานะการสืบค้นกลับมีผลบังคับใช้เป็น–Tตัวเลือกการเริ่มต้นใช้งานได้ทั้งแบบโกลบอลและขอบเขตการใช้DBCC TRACEONและต่อการสืบค้นด้วยOPTION (QUERYTRACEON)หรือคำแนะนำแผน

การติดตามสถานะ 176 ป้องกันการขยายคอลัมน์ที่คำนวณแล้วยังคงอยู่

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

ในฐานะที่เป็นผลข้างเคียงที่โชคร้ายหากหนึ่งในคอลัมน์ที่โหลด (คำนวณ) ใช้ฟังก์ชันที่ผู้ใช้กำหนดแบบสเกลาร์การปรากฏตัวของมันจะปิดการทำงานแบบขนานสำหรับการสืบค้นทั้งหมดแม้ว่าจะไม่ได้ใช้คอลัมน์ที่คำนวณแล้วก็ตาม

การติดตามค่าสถานะ 176 ช่วยด้วยสิ่งนี้หากคอลัมน์ยังคงอยู่โดยไม่โหลดข้อกำหนด (เนื่องจากการขยายจะถูกข้าม) ด้วยวิธีนี้ฟังก์ชั่นที่ผู้ใช้กำหนดแบบสเกลาร์จะไม่ปรากฏในแผนผังคิวรีการรวบรวม

ข้อเสียเปรียบหลักของแฟล็กการติดตาม 176 (นอกเหนือจากการจัดทำเอกสารเพียงเล็กน้อยเท่านั้น) คือมันยังป้องกันการจับคู่นิพจน์เคียวรีกับคอลัมน์ที่คำนวณได้: ถ้าเคียวรีมีนิพจน์ที่ตรงกับคอลัมน์ที่คำนวณแล้ว 176 แฟล็กการติดตาม การอ้างอิงไปยังคอลัมน์ที่คำนวณ

สำหรับรายละเอียดเพิ่มเติมโปรดดูบทความ SQLPerformance.com ของฉันถูกต้องคอลัมน์ยืนกราน Computed

เนื่องจากคำถามกล่าวถึง XML ซึ่งเป็นทางเลือกหนึ่งในการส่งเสริมค่าโดยใช้คอลัมน์ที่คำนวณและฟังก์ชั่นสเกลาร์คุณสามารถดูได้โดยใช้ดัชนี Selective XML ดังที่คุณเขียนไว้ในดัชนี XML ที่เลือก: ไม่แย่เลย


10

นอกเหนือจากการที่ยอดเยี่ยม @ พอลใช่ # 1 , มีจริงใช่ # 2 ว่า:

  • ทำงานได้ไกลเท่า SQL Server 2005
  • ไม่ต้องการตั้งค่าสถานะการติดตาม
  • ไม่ได้ต้องการให้คอลัมน์คำนวณเป็นPERSISTEDและ
  • (เนื่องจากไม่ต้องการแฟล็กการติดตาม 176) ไม่ป้องกันการจับคู่นิพจน์เคียวรีกับคอลัมน์ที่คำนวณ

ข้อเสียเปรียบเท่านั้น (เท่าที่ฉันสามารถบอกได้) คือ:

  • ไม่ทำงานบนฐานข้อมูล Azure SQL (อย่างน้อยยังไม่ถึงแม้ว่ามันจะทำงานบน Amazon RDS SQL Server เช่นเดียวกับ SQL Server บน Linux) และ
  • อยู่นอกเขตความสบายของ DBA เล็กน้อย

และตัวเลือกนี้คือ: SQLCLR

ถูกตัอง. แง่มุมหนึ่งที่ยอดเยี่ยมของ SQLCLR Scalar UDFs คือถ้าพวกเขาไม่ทำการเข้าถึงข้อมูลใด ๆ (ทั้งผู้ใช้และระบบ) พวกเขาจะไม่ห้ามการขนาน และนั่นไม่ได้เป็นเพียงแค่ทฤษฎีหรือการตลาด ในขณะที่ฉันไม่มีเวลา (ในขณะนี้) เพื่อทำการเขียนอย่างละเอียด แต่ฉันได้ทดสอบและพิสูจน์แล้ว

ฉันใช้การตั้งค่าเริ่มต้นจากโพสต์บล็อกต่อไปนี้ (หวังว่า OP ไม่ถือว่านี่เป็นแหล่งที่ไม่น่าเชื่อถือ🙃):

กางเกงยีนส์ Bad Idea: คำแนะนำดัชนีหลายรายการ

และทำการทดสอบต่อไปนี้:

  1. เรียกใช้คิวรีเริ่มต้นตามที่เป็น allel Parallelism (ตามที่คาดไว้)
  2. เพิ่มคอลัมน์ที่คำนวณแบบไม่คงที่ที่กำหนดเป็น([c2] * [c3])allel Parallelism (ตามที่คาดไว้)
  3. ลบคอลัมน์ที่คำนวณแล้วและเพิ่มคอลัมน์ที่คำนวณแล้วที่ยังไม่ยืนยันซึ่งอ้างอิง T-SQL Scalar UDF (สร้างด้วยSCHEMABINDING) ที่กำหนดเป็นRETURN (@First * @Second);as NO Parallelism (ตามที่คาดไว้)
  4. ลบคอลัมน์ที่คำนวณโดย T-SQL UDF และเพิ่มคอลัมน์ที่คำนวณแล้วแบบไม่ยืนยันที่อ้างอิง SQLCLR Scalar UDF (ลองทั้งคู่IsDeterministic = trueและ= false) กำหนดเป็นreturn SqlInt32.Multiply(First, Second);defined Parallelism (woo hoo !!)

ดังนั้นในขณะที่ SQLCLR จะไม่ทำงานสำหรับทุกคน แต่ก็มีข้อได้เปรียบสำหรับคน / สถานการณ์ / สภาพแวดล้อมที่เหมาะสม และเมื่อมันเกี่ยวข้องกับคำถามเฉพาะนี้ - ตัวอย่างที่ให้มาเกี่ยวกับการใช้ XQuery - มันจะทำงานบางอย่างสำหรับสิ่งนั้น (และขึ้นอยู่กับสิ่งที่ทำเฉพาะมันอาจจะเร็วขึ้นเล็กน้อย little)

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