ทำให้คำสั่ง SQL ที่ตรงเป้าหมายคืออะไร?


252

ตามคำจำกัดความ (อย่างน้อยจากสิ่งที่ฉันเห็น) หมายถึงการที่สามารถระบุได้ว่าการสืบค้นมีความสามารถในการทำให้เอ็นจินการสืบค้นปรับแผนการดำเนินการที่เคียวรีใช้ให้เหมาะสม ฉันพยายามค้นหาคำตอบ แต่ดูเหมือนจะไม่มากในประเด็น ดังนั้นคำถามคืออะไรหรือไม่ทำให้แบบสอบถาม SQL sargable? เอกสารใด ๆ ที่จะได้รับการชื่นชมอย่างมาก

สำหรับการอ้างอิง: SARGable


58
+1 สำหรับ "sargable" นั่นคือคำพูดของฉันในวันนี้สำหรับวันนี้ :-p
B

1
ฉันอาจเพิ่มคำตอบของอดัมว่าในกรณีส่วนใหญ่ข้อมูลส่วนใหญ่นั้นมีความพิเศษเฉพาะสำหรับเครื่องยนต์ DB แต่ละตัว
Hoagie

30
SARG = ค้นหา ARGument สิ่งที่ตลกคือ: "SARG" ในภาษาเยอรมันแปลว่า "โลงศพ" ดังนั้นฉันต้องยิ้มเสมอเมื่อผู้คนพูดถึง SARGABLE - สามารถใส่โลงศพได้หรือไม่? :-)
marc_s

sargability ขึ้นอยู่กับสภาพแวดล้อมของคุณ มีการบันทึกไว้ที่นี่ของ MySQL: dev.mysql.com/doc/refman/5.0/en/mysql-indexes.html
Frank Farmer

การมีฟิลด์ข้อความอิสระแทนที่จะเป็น "ตารางการค้นหา" ก็ขัดกับเจตนารมณ์ของการสร้างแบบสอบถามที่สามารถโต้แย้งได้ ผู้ใช้สะกดคำผิดเมื่อป้อนข้อความอิสระ (เช่นชื่อเมือง) ในขณะที่ตารางการค้นหาบังคับให้ผู้ใช้เลือกรายการสะกดที่ถูกต้อง คุ้มค่ากับปัญหาพิเศษเล็กน้อยเนื่องจากสามารถทำดัชนีได้อย่างเหมาะสมแทนที่จะใช้ LIKE '% ... %' ในภาคแสดง
วิศวกรที่กลับรายการ

คำตอบ:


256

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

SELECT ... FROM ...
WHERE Year(myDate) = 2008

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

WHERE myDate >= '01-01-2008' AND myDate < '01-01-2009'

ตัวอย่างอื่น ๆ :

Bad: Select ... WHERE isNull(FullName,'Ed Jones') = 'Ed Jones'
Fixed: Select ... WHERE ((FullName = 'Ed Jones') OR (FullName IS NULL))

Bad: Select ... WHERE SUBSTRING(DealerName,4) = 'Ford'
Fixed: Select ... WHERE DealerName Like 'Ford%'

Bad: Select ... WHERE DateDiff(mm,OrderDate,GetDate()) >= 30
Fixed: Select ... WHERE OrderDate < DateAdd(mm,-30,GetDate()) 

7
การรวมฟังก์ชั่นภายใน GROUP BYทำให้ข้อความค้นหาไม่สามารถระบุเป้าหมายได้หรือไม่
Mike Bailey

1
เอ็นจินฐานข้อมูลบางตัว (Oracle, PostgreSQL) รองรับดัชนีในนิพจน์, dontcha รู้หรือไม่?
Craig

3
รุ่นที่ดียิ่งขึ้นWHERE ((FullName = 'Ed Jones') OR (FullName IS NULL))จะเป็นSELECT... FROM ... WHERE FullName = 'Ed Jones' UNION SELECT...FROM...WHERE FullName IS NULLอย่างไร ฉันเคยได้รับการบอกเล่าจากคนที่เหมาะสมที่สุดที่ใช้ OR ในส่วนคำสั่งที่สามารถยกเลิกการสอบถาม .. ?
ที่ราบสูง Grifter

2
@HighPlainsGrifter คุณควรใช้ยูเนี่ยนทั้งหมดในแบบสอบถามที่ - ยูเนี่ยนมีนัยที่แตกต่างกันซึ่งจะทำให้แบบสอบถามมากมีราคาแพงกว่าที่จะต้องมีเมื่อคุณมีการชุดข้อมูลพิเศษร่วมกันมากขึ้น
วิน Lamothe

1
@BradC ใน MSSQL 2016 ไม่มีความแตกต่างระหว่างแผนการดำเนินการและSelect ... WHERE isNull(FullName,'Ed Jones') = 'Ed Jones' Select ... WHERE ((FullName = 'Ed Jones') OR (FullName IS NULL))พวกเขาทั้งสองใช้ดัชนีบน FullName และค้นหาดัชนี
CEGRD

79

อย่าทำสิ่งนี้:

WHERE Field LIKE '%blah%'

ที่ทำให้การสแกนตาราง / ดัชนีเนื่องจากค่า LIKE เริ่มต้นด้วยอักขระตัวแทน

อย่าทำสิ่งนี้:

WHERE FUNCTION(Field) = 'BLAH'

ที่ทำให้การสแกนตาราง / ดัชนี

เซิร์ฟเวอร์ฐานข้อมูลจะต้องประเมิน FUNCTION () เทียบกับทุกแถวในตารางแล้วเปรียบเทียบกับ 'BLAH'

หากเป็นไปได้ให้ทำย้อนกลับ:

WHERE Field = INVERSE_FUNCTION('BLAH')

สิ่งนี้จะรัน INVERSE_FUNCTION () กับพารามิเตอร์หนึ่งครั้งและจะยังคงอนุญาตให้ใช้ดัชนี


5
ข้อเสนอแนะของคุณในการพลิกฟังก์ชั่นจะทำงานได้ก็ต่อเมื่อข้อมูลรอบการเดินทาง (หมายถึง f (f (n)) = n)
Adam Robinson เมื่อ

5
จริง ฉันถือว่าการเพิ่ม INVERSE_FUNCTION แต่ไม่ต้องการสับสน ฉันจะเปลี่ยนมัน
ชายหาด

9

ในคำตอบนี้ฉันคิดว่าฐานข้อมูลมีดัชนีครอบคลุมเพียงพอ มีคำถามเกี่ยวกับหัวข้อนี้เพียงพอ

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

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

คุณสามารถค้นหาโพสต์รายละเอียดและตัวอย่างที่นี่


4

เพื่อให้การดำเนินการที่จะพิจารณาว่าเป็น sargable นั้นไม่เพียงพอที่จะสามารถใช้ดัชนีที่มีอยู่ได้ ในตัวอย่างข้างต้นการเพิ่มการเรียกฟังก์ชันกับคอลัมน์ที่จัดทำดัชนีไว้ในส่วนคำสั่ง where จะยังคงใช้ประโยชน์จากดัชนีที่กำหนดมากที่สุด มันจะ "สแกน" หรือที่เรียกว่าดึงค่าทั้งหมดจากคอลัมน์นั้น (ดัชนี) จากนั้นกำจัดค่าที่ไม่ตรงกับค่าตัวกรองที่มีให้ มันยังคงมีประสิทธิภาพไม่เพียงพอสำหรับตารางที่มีจำนวนแถวสูง สิ่งที่กำหนด sargability จริง ๆ คือความสามารถในการสอบถามเพื่อสำรวจดัชนี b-tree โดยใช้วิธีการค้นหาแบบไบนารีที่อาศัยการกำจัดแบบครึ่งชุดสำหรับอาร์เรย์รายการที่เรียงลำดับ ใน SQL มันจะแสดงบนแผนการดำเนินการในฐานะ "ค้นหาดัชนี"

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