ผลของการแทนที่ดัชนีด้วยดัชนีที่กรองแล้ว (ไม่ใช่ค่า null) คืออะไร?


10

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

ตอนนี้ฉันมีคำถามสองข้อเกี่ยวกับเรื่องนี้:

A) ข้อเสียของการใช้ดัชนีที่ถูกกรองในแบบนี้คืออะไร? ฉันจะสมมติว่ามันจะปรับปรุงประสิทธิภาพเท่านั้น แต่มีความเสี่ยงด้านประสิทธิภาพหรือไม่?

B) เราได้รับข้อผิดพลาด ( 'ไม่สามารถวางดัชนี XYZ ได้เนื่องจากไม่มีอยู่หรือคุณไม่ได้รับอนุญาต' ) ในการทำดัชนีหล่นและสร้างดัชนีใหม่แม้ว่าจะได้รับการตรวจสอบแล้วก็ตามทุกอย่างเป็นไปตามที่คาดไว้ สิ่งนี้จะเกิดขึ้นได้อย่างไร?

ขอบคุณสำหรับความช่วยเหลือใด ๆ !

แก้ไข:เพื่อตอบสนองต่อ @Thomas Kejser

สวัสดีและขอบคุณ แต่ปรากฎว่านี่เป็นหายนะ ในเวลานั้นเราไม่เข้าใจหลายสิ่งเช่น:

  1. ระหว่างการสืบค้น SQLOS จัดทำแผนดัชนีก่อนที่จะพิจารณาว่าไม่สามารถใช้ค่า NULL สำหรับการเข้าร่วมคอลัมน์ตาราง IE คุณจำเป็นต้องมีตัวกรองคำสั่งย่อย WHERE ที่เหมาะสมสำหรับดัชนีแต่ละตัวกรองที่ใช้ในแบบสอบถามมิฉะนั้นดัชนีจะไม่ถูกใช้เลย
  2. การวางและสร้างดัชนีและอัปเดตสถิติของพวกเขาซ้ำซ้อนอีกครั้งหลังจากนั้นอาจยังไม่เพียงพอที่จะสร้างแผนที่อัปเดตซึ่งเราคิดว่าพวกเขาจะทำ มันปรากฏขึ้นในบางกรณีเพียงปริมาณงานที่มากพอที่จะบังคับให้ SQL Server ประเมินแผนอีกครั้ง
  3. มีฟังก์ชั่น Exotics บางอย่างของตัววางแผนการดำเนินการที่ยากต่อการพิจารณาโดยสามัญสำนึกและตรรกะเพียงอย่างเดียว ด้วยความแตกต่างของการสร้างโค้ดที่ล้าหลังของคิวรีที่แตกต่างกันถึงแม้ว่าดัชนีที่ไร้ประโยชน์ดูเหมือนจะสามารถช่วยในสถิติและแผนคิวรีบางอย่างที่ถูกใช้ในคิวรีที่สำคัญ

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


คุณอาจต้องการตรวจสอบกลยุทธ์การจัดทำดัชนีของคุณอีกครั้ง หากคุณมีดัชนีฟิลด์หลายร้อยดัชนีอาจไม่เหมาะสมที่สุด
JNK

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

คำตอบ:


8

วิธีการที่น่าสนใจมาก upvote ของฉันสำหรับความคิดสร้างสรรค์

เมื่อคุณเรียกคืนพื้นที่แล้วฉันถือว่าดัชนีดั้งเดิมไม่ได้อยู่ในสถานที่อีกต่อไปแล้ว? ข้อเสียของดัชนีที่กรองแล้วคือ:

  • มีจำนวนมากเกินไปที่อาจทำให้พื้นที่การค้นหาของเครื่องมือเพิ่มประสิทธิภาพใหญ่เกินไปซึ่งนำไปสู่แผนการสืบค้นที่ไม่ดีเนื่องจากเครื่องมือเพิ่มประสิทธิภาพหมดเวลา
  • มีหลายสถานการณ์ที่ดัชนีที่ถูกกรองจะไม่ถูกนำมาพิจารณาแม้ว่าจะมีค่าเทียบเท่าที่ไม่ถูกกรองก็ตาม สิ่งนี้สามารถเกิดขึ้นได้เมื่อคุณเข้าร่วมแฮชในคอลัมน์ที่จัดทำดัชนีหรือหากคุณพยายามเรียงตามคอลัมน์ (โดยไม่มีตัวกรอง)
  • การค้นหาพารามิเตอร์ไม่ทำงานกับดัชนีที่กรองแล้ว (ดู: http://www.sqlservercentral.com/blogs/practicalsqldba/2013/04/08/sql-server-part-9-filtered-index-a-new-way- สำหรับประสิทธิภาพการทำงานปรับปรุง / )

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


"พารามิเตอร์การสืบค้นไม่ทำงานกับดัชนีที่กรองแล้ว" นี้น่าจะสามารถแก้ไขด้วยตัวเลือก (recompile)
MichaelD

2

Thomas Kejser ตอบคำถามในหัวข้อนี้ได้ดีกว่า

ฉันแค่คิดถึงการเพิ่ม 2 เซ็นต์

ฉันได้เห็นดัชนีที่กรองแล้วบางตัวเท่านั้นที่ใช้งาน (แสดงในแผนการดำเนินการ) เมื่อคุณตรงกับส่วนคำสั่ง where ในแบบสอบถามของคุณเป็นตำแหน่งในดัชนีตัวกรอง

คุณเคยลองใช้มุมมองที่จัดทำดัชนีแล้วหรือยัง คอลัมน์หร็อมแหร็ม ?

ฉันเชื่อว่าตราบใดที่คุณมีข้อต่อด้านในเพียงอย่างเดียวคุณสามารถสร้างมุมมองที่มีการจัดทำดัชนีที่มีส่วนคำสั่งของดัชนีที่กรองแล้วจากนั้นคุณสามารถใช้มุมมองแทน

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

จากประสบการณ์ของฉันคุณจะได้รับการอ่านที่ดี แต่คุณจะต้องตรวจสอบการเขียน (แทรกและอัพเดต) เป็นพิเศษหากตารางเกี่ยวข้องกับการจำลองแบบ

แต่ที่ผมเข้าใจความกังวลหลักของคุณthe null valuesดังนั้นผมขอแนะนำให้คุณเบาบางคอลัมน์ในดัชนีของคุณ

คอลัมน์กระจัดกระจายเหมาะอย่างยิ่งสำหรับดัชนีที่กรอง

เนื่องจากฉันได้โฆษณาคอลัมน์หร็อมแหร็มฉันจะไม่รู้สึกดีถ้าฉันไม่ได้บอกคุณเกี่ยวกับข้อ จำกัด ของมัน:

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

เป็นผลมาจากสิ่งนี้

ข้อกำหนดหน่วยความจำเพิ่มเติมการอัพเดทอาจล้มเหลวโดยไม่คาดคิดกับข้อผิดพลาด 576 เมื่อขนาดแถวทั้งหมดรวมถึงโอเวอร์เฮดหน่วยความจำนี้เกิน 8019

และไม่มีคอลัมน์ใดถูกผลักออกจากแถว

พิจารณาตัวอย่าง> ของตารางที่มี 600 คอลัมน์แบบเบาบางประเภท bigint

หากมี 571 คอลัมน์ที่ไม่เป็น null ดังนั้นขนาดทั้งหมดบนดิสก์คือ 571 * 12 = 6852 ไบต์ หลังจากรวมค่าใช้จ่ายของแถวเพิ่มเติมและส่วนหัวของคอลัมน์ที่กระจัดกระจายค่านี้จะเพิ่มเป็นประมาณ 6895 ไบต์ หน้ายังคงมีประมาณ 1124 ไบต์พร้อมใช้งานบนดิสก์ สิ่งนี้สามารถสร้างความประทับใจได้ว่าสามารถอัปเดตคอลัมน์เพิ่มเติมได้สำเร็จ อย่างไรก็ตามในระหว่างการอัพเดตจะมีโอเวอร์เฮดเพิ่มเติมในหน่วยความจำซึ่งเป็น 2 * (จำนวนคอลัมน์ที่ไม่เป็นศูนย์) ในตัวอย่างนี้รวมถึงค่าใช้จ่ายเพิ่มเติม - 2 * 571 = 1142 ไบต์ - เพิ่มขนาดแถวบนดิสก์เป็นประมาณ 8037 ไบต์ ขนาดนี้เกินขนาดสูงสุดที่อนุญาต 8019 ไบต์ เนื่องจากคอลัมน์ทั้งหมดเป็นชนิดข้อมูลที่มีความยาวคงที่จึงไม่สามารถผลักออกจากแถวได้ เป็นผลให้การปรับปรุงล้มเหลวโดยมีข้อผิดพลาด 576

รายละเอียดเพิ่มเติมเกี่ยวกับลิงค์ด้านบน แต่ฉันชอบที่จะโพสต์ที่นี่คำเตือนนี้ด้วย:

การเปลี่ยนคอลัมน์จาก sparse เป็น nonsparse หรือ nonsparse เป็น sparse ต้องเปลี่ยนรูปแบบหน่วยเก็บของคอลัมน์

โปรแกรมฐานข้อมูลเซิร์ฟเวอร์ SQL ใช้ขั้นตอนต่อไปนี้เพื่อทำการเปลี่ยนแปลงนี้:

1 - เพิ่มคอลัมน์ใหม่ลงในตารางในขนาดและรูปแบบการจัดเก็บใหม่

2 - สำหรับแต่ละแถวในตารางอัพเดตและคัดลอกค่าที่เก็บไว้ในคอลัมน์เก่าไปยังคอลัมน์ใหม่

3 - ลบคอลัมน์เก่าออกจากตารางสคีมา

4 - สร้างตารางใหม่ (หากไม่มีดัชนีคลัสเตอร์) หรือสร้างดัชนีคลัสเตอร์ใหม่เพื่อเรียกคืนพื้นที่ที่ใช้โดยคอลัมน์เก่า


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

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

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