ดัชนีค้นหา vs สแกนดัชนี


64

ดูที่แผนการดำเนินการของคิวรีที่รันช้าและฉันสังเกตว่าบางโหนดเป็นดรรชนีและบางอันก็สแกนดรรชนี

ความแตกต่างระหว่างกับการค้นหาดัชนีและการสแกนดัชนีคืออะไร?

แบบไหนดีกว่ากัน?

SQL จะเลือกอย่างใดอย่างหนึ่งได้อย่างไร

ฉันรู้ว่านี่คือคำถาม 3 ข้อ แต่ฉันคิดว่าการตอบคำถามแรกจะอธิบายคำถามอื่น ๆ


6
คุณมีการอ้างอิงที่ดีในการใช้งานที่ดัชนีลุค
แมเรียน

7
ไม่ใช่การสแกนทั้งหมดที่ไม่ดี - บางครั้งก็เป็นวิธีที่มีประสิทธิภาพที่สุดในการตอบคำถาม โปรดทราบว่าไม่ใช่การค้นหาทั้งหมดที่ค้นหา - บ่อยครั้งที่พวกเขาสแกนช่วงจริงและการค้นหาเพียงระบุว่ามันได้มาถึงจุดเริ่มต้นของช่วง
Aaron Bertrand

@AaronBertrand แต่ถ้ามันถึงจุดเริ่มต้นของช่วงและอ่านมันก็หมายความว่าคุณต้องการข้อมูลอยู่แล้ว นอกจากนี้ยังค้นหาจุดสิ้นสุดของช่วง
George Polevoy

คำตอบ:


76

เวอร์ชั่นสั้น: การค้นหาดีกว่ามาก

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

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

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

การสแกนดัชนีด้วยการค้นหาแถว:เมื่อไม่พบดัชนีที่สามารถใช้สำหรับการค้นหาได้โดยตรง แต่ดัชนีที่มีคอลัมน์ที่ถูกต้องจะแสดงการสแกนดัชนี ตัวอย่างเช่นหากคุณมีตารางขนาดใหญ่ที่มี 20 คอลัมน์ที่มีดัชนีในคอลัมน์ 1, col2, col3 และคุณออกSELECT col4 FROM exampletable WHERE col2=616ในกรณีนี้การสแกนดัชนีเพื่อค้นหาcol2จะดีกว่าการสแกนทั้งตาราง เมื่อพบแถวที่ตรงกันแล้วหน้าข้อมูลจะต้องอ่านเพื่อรับ col4 สำหรับเอาท์พุท (หรือการเข้าร่วมเพิ่มเติม) ซึ่งเป็นขั้นตอน "การค้นหาบุ๊กมาร์ก" เมื่อคุณเห็นในแผนคิวรี

การสแกนดัชนีโดยไม่มีการค้นหาแถว:หากตัวอย่างด้านบนเป็นเช่นSELECT col1, col2, col3 FROM exampletable WHERE col2=616นั้นไม่จำเป็นต้องใช้ความพยายามในการอ่านหน้าข้อมูลเพิ่มเติม: เมื่อcol2=616พบการจับคู่แถวดัชนีแล้วจะต้องทราบข้อมูลที่ร้องขอทั้งหมด นี่คือเหตุผลที่บางครั้งคุณเห็นคอลัมน์ที่จะไม่ถูกค้นหา แต่มีแนวโน้มที่จะถูกร้องขอสำหรับเอาท์พุทเพิ่มไปยังจุดสิ้นสุดของดัชนี - มันสามารถบันทึกการค้นหาแถว เมื่อเพิ่มคอลัมน์ในดัชนีด้วยเหตุผลนี้และด้วยเหตุผลนี้เท่านั้นเพิ่มคอลัมน์ด้วยINCLUDEประโยคเพื่อบอกเอ็นจินว่าไม่จำเป็นต้องปรับเลย์เอาต์ดัชนีสำหรับการสืบค้นตามคอลัมน์เหล่านี้ (สิ่งนี้สามารถเร่งความเร็วการอัปเดตของคอลัมน์เหล่านั้น) . การสแกนดัชนีอาจเป็นผลมาจากการสืบค้นที่ไม่มีคำสั่งการกรองเช่นกัน: SELECT col2 FROM exampletableจะสแกนดัชนีตัวอย่างนี้แทนที่จะเป็นหน้าตาราง

การค้นหาดัชนี (โดยมีหรือไม่มีการค้นหาแถว) :ในการค้นหาดัชนีทั้งหมดจะไม่ได้รับการพิจารณา สำหรับเคียวรีเคียวรีSELECT * FROM exampletable WHERE c1 BETWEEN 1234 AND 4567เคียวรีสามารถค้นหาแถวแรกที่จะจับคู่โดยทำการค้นหาแบบทรีบนดัชนีc1จากนั้นมันสามารถนำทางดัชนีตามลำดับจนกว่ามันจะถึงจุดสิ้นสุดของช่วง (ซึ่งจะเหมือนกับแบบสอบถาม เพราะc1=1234อาจมีหลายแถวที่ตรงกับเงื่อนไขแม้สำหรับการ=ดำเนินการ) ซึ่งหมายความว่าต้องอ่านหน้าดัชนีที่เกี่ยวข้องเท่านั้น (บวกกับจำนวนเล็กน้อยที่จำเป็นสำหรับการค้นหาเริ่มต้น) แทนที่จะเป็นทุกหน้าในดัชนี (หรือตาราง)

ดัชนีแบบคลัสเตอร์:ด้วยดัชนีแบบคลัสเตอร์ข้อมูลตารางจะถูกเก็บไว้ในโหนดใบไม้ของดัชนีนั้นแทนที่จะอยู่ในโครงสร้างฮีปที่แยกต่างหาก ซึ่งหมายความว่าไม่จำเป็นต้องมีการค้นหาแถวพิเศษใด ๆ หลังจากค้นหาแถวโดยใช้ดัชนีนั้นไม่ว่าจะต้องการคอลัมน์ใด [เว้นแต่ว่าคุณมีข้อมูลนอกหน้าเช่นTEXTคอลัมน์หรือVARCHAR(MAX)คอลัมน์ที่มีข้อมูลยาว]

คุณสามารถมีดัชนีคลัสเตอร์เดียวได้ด้วยเหตุนี้[1]ดัชนีคลัสเตอร์คือตารางของคุณแทนที่จะมีโครงสร้างฮีปแยกต่างหากดังนั้นหากคุณใช้[2]เลือกตำแหน่งที่คุณวางไว้อย่างระมัดระวังเพื่อให้ได้รับประโยชน์สูงสุด

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

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

[2] เมื่อผมบอกว่า "ถ้าคุณใช้ดัชนีคลัสเตอร์" ไม่ทราบว่าจะแนะนำกันโดยทั่วไปว่าคุณทำมีหนึ่งในแต่ละโต๊ะ มีข้อยกเว้นเช่นเดียวกับกฎ - ของ - นิ้วหัวแม่มือทุกตารางที่เห็นนอกเหนือจากเม็ดมีดจำนวนมากและการอ่านแบบไม่เรียงลำดับ (ตารางการจัดเตรียมสำหรับกระบวนการ ETL) อาจเป็นตัวอย่างเคาน์เตอร์ทั่วไป

จุดเพิ่มเติม: การสแกนที่ไม่สมบูรณ์:

เป็นสิ่งสำคัญที่ต้องจำไว้ว่าขึ้นอยู่กับส่วนที่เหลือของแบบสอบถามสแกนตาราง / ดัชนีอาจไม่สแกนทั้งตารางจริง - ถ้าตรรกะช่วยให้แผนแบบสอบถามอาจจะทำให้มันยกเลิกก่อน ตัวอย่างที่ง่ายที่สุดของเรื่องนี้คือSELECT TOP(1) * FROM HugeTable- ถ้าคุณดูที่แผนแบบสอบถามสำหรับสิ่งที่คุณจะเห็นว่ามีเพียงหนึ่งแถวที่ถูกส่งคืนจากการสแกนและถ้าคุณดูสถิติ IO ( SET STATISTICS IO ON; SELECT TOP(1) * FROM HugeTable) คุณจะเห็นว่ามันอ่านตัวเลขเพียงเล็กน้อยเท่านั้น จากหน้า (อาจเป็นเพียงหนึ่ง)

สิ่งเดียวกันสามารถเกิดขึ้นได้หากเพรดิเคตของ a WHEREหรือJOIN ... ONประโยคสามารถรันพร้อมกันกับการสแกนที่เป็นแหล่งหากข้อมูลของมัน ตัววางแผนคิวรี / รันเนอร์สามารถฉลาดมากเกี่ยวกับการผลักเพรดิเคตกลับไปยังแหล่งข้อมูลเพื่อให้สามารถยกเลิกการสแกนก่อนหน้านี้ด้วยวิธีนี้ (และบางครั้งคุณสามารถฉลาดในการจัดคิวรีใหม่เพื่อช่วยทำ! ในขณะที่ข้อมูลไหลจากขวาไปซ้ายตามลูกศรในการแสดงแผนแบบสอบถามมาตรฐานตรรกะวิ่งจากซ้ายไปขวาและแต่ละขั้นตอน (จากขวาไปซ้าย) ไม่จำเป็นต้องเรียกใช้ให้เสร็จก่อนที่จะเริ่มต้นต่อไป ในตัวอย่างง่ายๆข้างต้นหากคุณดูแต่ละบล็อกในแผนแบบสอบถามเป็นตัวแทนSELECTตัวแทนจะขอให้TOPตัวแทนแถวซึ่งจะถามTABLE SCANตัวแทนหนึ่งจากนั้นSELECTตัวแทนขออีก แต่TOPตัวแทนรู้ว่าไม่จำเป็นต้องไม่รำคาญแม้แต่จะถามผู้อ่านตารางSELECTตัวแทนได้รับการตอบสนอง "ไม่เกี่ยวข้องมาก" และรู้ว่างานทั้งหมดจะทำ การดำเนินงานหลายป้องกันการเรียงลำดับของการเพิ่มประสิทธิภาพของหลักสูตรนี้จึงมักจะอยู่ในตัวอย่างที่ซับซ้อนมากขึ้นตารางการสแกน / ดัชนีจริงๆไม่อ่านทุกแถว แต่ต้องระวังไม่ให้ข้ามไปยังข้อสรุปว่าการสแกนอื่น ๆ จะต้องมีการดำเนินการที่มีราคาแพง


6

โดยทั่วไปการค้นหาดีสแกนไม่ดี

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

การสแกนคือที่ที่คิวรีค้นหาผ่านดัชนีทั้งหมดพยายามค้นหาสิ่งที่ต้องการ

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

มีหนังสือสองสามเล่มให้อ่านที่อาจเป็นที่สนใจ - ทั้งจากร้านหนังสือ Red-Gate ที่http://www.red-gate.com/community/books/

  • แผนการดำเนินการของ SQL Server โดย Grant Fritchey
  • Inside the Query Optimizer โดย Benjamin Nevarez
  • SQL Server สถิติโดย Holger Schmeling

7
สำหรับแผนเดียวกันการสแกนตารางเดียวนั้นดีการค้นหานับล้านครั้งนั้นไม่ดี ดังนั้นข้อความแรกของคุณไม่ถูกต้องทั้งหมด
แมเรียน

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

5

หากคุณต้องการที่จะขุดเรื่องหนังสือที่เป็นประโยชน์มาก (อย่างน้อยสำหรับฉัน) เป็น SQL Server แผนดำเนินการโดยแกรนท์ Fritchey ได้อย่างอิสระที่มีอยู่ใน RedGate ที่นี่

หากคุณมีคำถามเช่น

SELECT *
FROM myTable

SQL Server มีแนวโน้มที่จะใช้การสแกนดัชนีเนื่องจากต้องผ่านทุกแถวเพื่อแสดงผลลัพธ์ที่ต้องการ

ในทางตรงกันข้าม,

SELECT *
FROM myTable
WHERE myID = 1

จะทำให้ดัชนีค้นหาอย่างแน่นอน SQL Server จะใช้โครงสร้าง B-treeของดัชนี myID และการดึงข้อมูลบรรทัดที่เหมาะสมจะเร็วขึ้นมาก


ฉันไม่รู้ว่าฉันเห็นด้วยกับ "แน่นอน" - แม้ว่าดัชนีมี myID เป็นคอลัมน์นำการค้นหาอาจไม่ใช่คำตอบที่ดีที่สุด (ขึ้นอยู่กับหลาย ๆ อย่างเช่นไม่ว่าจะเป็นเอกลักษณ์หรือไม่ - ซึ่งอาจเป็น จริงในตารางลูกค้า แต่ไม่ใช่สำหรับ customerID ในตารางคำสั่งจำนวนคอลัมน์ที่ต้องครอบคลุม แต่ไม่ได้อยู่ในดัชนีและอื่น ๆ )
Aaron Bertrand

ฉันไม่คิดว่าคำตอบนี้ครอบคลุมคำถามจริง ๆ
Zero3

5

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

แต่เป็นตัวอย่างสมมติว่ารหัสของคุณกำลังสืบค้นคอลัมน์ A และคอลัมน์ B ในตัวกรองที่กำหนด แต่คุณต้องการส่งคืนค่าของคอลัมน์ C และคอลัมน์ E คุณอาจต้องการสร้างดัชนีในคอลัมน์ A และ B ด้วย INCLUDE ตัวเลือกที่มีคอลัมน์ C และ E ด้วยวิธีการค้นหาดัชนีเดี่ยวจะส่งคืนทุกสิ่งที่คุณต้องการเนื่องจากไม่จำเป็นต้องทำการค้นหาเพื่อดึงค่าอื่น ๆ (C และ E) ในแถวเดียวกัน

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