ORDER BY FIELD () ใน MySQL ทำงานอย่างไรภายใน


37

ฉันเข้าใจว่าORDER BYประโยคทำงานอย่างไรและFIELD()ฟังก์ชั่นทำงานอย่างไร สิ่งที่ฉันต้องการเข้าใจคือการที่ทั้งคู่ทำงานร่วมกันเพื่อเรียงลำดับ มีการดึงแถวมาอย่างไรและเรียงลำดับอย่างไร

+----+---------+
| id |  name   |
+----+---------+
|  1 | stan    |
|  2 | kyle    |
|  3 | kenny   |
|  4 | cartman |
+----+---------+ 

SELECT * FROM mytable WHERE id IN (3,2,1,4) ORDER BY FIELD(id,3,2,1,4)

แบบสอบถามข้างต้นจะส่งผลให้

+----+---------+
| id |  name   |
+----+---------+
|  3 | kenny   |
|  2 | kyle    |
|  1 | stan    |
|  4 | cartman |
+----+---------+ 

สิ่งที่คล้ายกับการพูดสั่งซื้อโดย 3, 2, 1, 4

คำถาม

  • มันทำงานอย่างไรภายใน?
  • MySQL มีวิธีจัดเรียงแถวและคำนวณลำดับการจัดเรียงอย่างไร
  • MySQL รู้ได้อย่างไรว่าต้องเรียงตามคอลัมน์ id?

1
ลองชุดรูปแบบของแบบสอบถามนี้: SELECT *, FIELD(id,3,2,1,4) AS f FROM mytable WHERE id IN (3,2,1,4);จากนั้นเพิ่มORDER BY fหรือORDER BY FIELD(id,3,2,1,4)ลองอีกครั้ง
ypercubeᵀᴹ

คำตอบ:


64

สำหรับบันทึก

SELECT * FROM mytable WHERE id IN (1,2,3,4) ORDER BY FIELD(id,3,2,1,4);

ควรทำงานเช่นกันเพราะคุณไม่จำเป็นต้องเรียงลำดับรายการในWHEREข้อ

สำหรับวิธีการทำงาน

  • FIELD ()เป็นฟังก์ชันที่ส่งกลับตำแหน่งดัชนีของรายการที่คั่นด้วยจุลภาคหากมีค่าที่คุณค้นหาอยู่

    • IF id = 1 ดังนั้นFIELD (id, 3,2,1,4)จะส่งกลับ 3 (ตำแหน่งที่ 1 อยู่ในรายการ)
    • IF id = 2 ดังนั้นFIELD (id, 3,2,1,4)จะส่งกลับ 2 (ตำแหน่งที่ 2 อยู่ในรายการ)
    • IF id = 3 ดังนั้นFIELD (id, 3,2,1,4)จะส่งกลับ 1 (ตำแหน่งที่ 3 อยู่ในรายการ)
    • IF id = 4 ดังนั้นFIELD (id, 3,2,1,4)จะส่งกลับ 4 (ตำแหน่งที่ 4 อยู่ในรายการ)
    • IF id = อะไรอย่างอื่นFIELD (id, 3,2,1,4)จะส่งกลับ 0 (ไม่ใช่ในรายการ)
  • ORDER BYค่าได้รับการประเมินโดยสิ่งที่FIELD ()ผลตอบแทน

คุณสามารถสร้างคำสั่งแฟนซีทุกประเภท

ตัวอย่างเช่นการใช้ฟังก์ชันIF ()

SELECT * FROM mytable
WHERE id IN (1,2,3,4)
ORDER BY IF(FIELD(id,3,2,1,4)=0,1,0),FIELD(id,3,2,1,4);

นี่จะทำให้รหัส 4 รหัสแรกปรากฏที่ด้านบนของรายการมิฉะนั้นจะปรากฏที่ด้านล่าง ทำไม?

ในการที่ORDER BYคุณจะได้รับ 0 หรือ 1

  • ถ้าคอลัมน์แรกคือ 0 ให้ทำ 4 รหัสแรกปรากฏขึ้น
  • หากคอลัมน์แรกคือ 1 ให้ทำให้ปรากฏหลังจากนั้น

ลองพลิกด้วย DESC ในคอลัมน์แรก

SELECT * FROM mytable
WHERE id IN (1,2,3,4)
ORDER BY IF(FIELD(id,3,2,1,4)=0,1,0) DESC,FIELD(id,3,2,1,4);

ในตัวORDER BYคุณยังคงได้รับ 0 หรือ 1

  • หากคอลัมน์แรกคือ 1 ให้สร้างอะไรก็ได้ยกเว้น 4 รหัสแรกจะปรากฏขึ้น
  • ถ้าคอลัมน์แรกเป็น 0 ให้ 4 รหัสแรกปรากฏในลำดับเดิม

คำถามจริงของคุณ

หากคุณต้องการ internals เกี่ยวกับเรื่องนี้อย่างจริงจังไปที่หน้า 189 และ 192 ของหนังสือ

MySQL Internals

สำหรับการดำน้ำลึกที่แท้จริง

ในสาระสำคัญมีคลาส C ++ ที่เรียกว่าORDER *order( ORDER BYต้นไม้นิพจน์) ในJOIN::prepare, ถูกนำมาใช้ในการทำงานที่เรียกว่า*order ทำไมในช่วงกลางของการเรียน? ทุกการสืบค้นแม้แต่การสืบค้นกับตารางเดียวจะถูกประมวลผลเป็น JOIN เสมอ (ดูโพสต์ของฉันมีความแตกต่างในการดำเนินการระหว่างเงื่อนไข JOIN และเงื่อนไข WHERE หรือไม่ )setup_order()JOIN

ซอร์สโค้ดทั้งหมดนี้คือ sql/sql_select.cc

เห็นได้ชัดว่าที่ต้นไม้จะจัดให้มีการประเมินผลของORDER BY FIELD(id,3,2,1,4)ดังนั้นตัวเลข 0,1,2,3,4 จึงเป็นค่าที่เรียงลำดับขณะทำการอ้างอิงกับแถวที่เกี่ยวข้อง


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

สมมติว่ามีNค่าทั้งในและIN FIELDในตัวอย่างN=4นี้ ฉันเข้าใจอย่างถูกต้องว่าแบบสอบถามนี้จะดำเนินการอย่างน้อย~N^2การดำเนินงาน เพราะFIELDการคำนวณแต่ละครั้งจะทำการ~Nเปรียบเทียบหนึ่งครั้งสำหรับแต่ละแถว ถ้าเป็นเช่นนี้ค่อนข้างช้าสำหรับขนาดใหญ่Nบางทีมันอาจไม่ใช่วิธีที่ดีมาก?
Gherman

@Gherman FIELD()ฟังก์ชั่นที่ควรจะO(1)ดำเนินการเพราะมีดัชนีตัวเลขFIELD() idดังนั้นฉันไม่เห็นอะไรเลยนอกจากดูO(n)จากแถว ฉันไม่เห็นFIELD()การดำเนินการซ้ำ ๆ เช่นGREATEST()จะต้องทำ
RolandoMySQLDBA

@RolandoMySQLDBA จุดของฉันคือว่าถ้าFIELDมีNข้อโต้แย้งที่จะเปรียบเทียบกับมันก็จะดำเนินNการเปรียบเทียบ มันจะมีวิธีอื่นเปรียบเทียบหมายเลขหนึ่งกับNตัวเลขอื่น ๆ ถ้าไม่ได้ทำO(N)? ความเป็นไปได้เพียงอย่างเดียวที่ฉันสามารถนึกได้คือการปรับให้เหมาะสมบางอย่างผ่านโครงสร้างข้อมูลพิเศษเช่นแฮชหรือทรีของข้อโต้แย้ง อันที่จริงฉันรู้ว่าINมีการเพิ่มประสิทธิภาพดังกล่าว FIELDผมไม่ทราบว่าเกี่ยวกับ คุณหมายถึงอะไร "ดัชนีเชิงตัวเลข" หมายถึงอะไร
Gherman

1
เฮ้ @RaymondNijland คำสั่ง CASE นั้นเป็นที่เข้าใจได้มากกว่าในกรณีนี้น้ำตาล syntactic เพิ่งจะมีการเขียนน้อยลง
RolandoMySQLDBA

1

อาจจะไกลเกินไปจากรหัสจริงดังนั้นอย่าอยู่ในระดับต่ำพอจากสิ่งที่คุณต้องการ:

เมื่อ MySQL ไม่สามารถใช้ดัชนีเพื่อดึงข้อมูลในการเรียงลำดับมันจะสร้างตาราง / resultset ชั่วคราวพร้อมคอลัมน์ที่เลือกทั้งหมดและข้อมูลเพิ่มเติม - หนึ่งในนั้นคือคอลัมน์ชนิดหนึ่งสำหรับการจัดเก็บผลลัพธ์ของค่า ORDER BY ในแต่ละแถว - จากนั้นจะส่งตาราง tmp นี้ไปยังรูท "filesort" พร้อมข้อมูลซึ่งคอลัมน์จะเรียงลำดับ หลังจากนั้นแถวจะเรียงตามลำดับเพื่อให้สามารถเลือกได้ทีละบรรทัดแล้วส่งกลับคอลัมน์ที่เลือก


คำอธิบายนี้ไม่ได้คำนึงถึงวิธีFIELDการคำนวณฟังก์ชั่น ฉันเกรงว่าอาจมีผลกระทบอย่างมีนัยสำคัญต่อประสิทธิภาพ
Gherman

@Gherman ฉันไม่คิดว่าอย่างนั้นเว้นแต่คุณจะใช้รายการอาร์กิวเมนต์ที่ยาวมาก (เนื่องจากฟังก์ชันเป็นเส้นตรงกับจำนวนอาร์กิวเมนต์การเข้าถึงข้อมูลเป็นลำดับความสำคัญช้ากว่าการเปรียบเทียบแบบง่าย ๆ
jkavalik

ใช่รายการอาร์กิวเมนต์ที่ยาว มีข้อโต้แย้งมากเท่ากับที่มีระเบียนในตัวอย่างนี้
Gherman

ฉันจะติดป้ายชื่อเป็นร้อยเป็นพันและจากนั้นคุณจะได้รับปัญหาอื่น ๆ ต่อไป (ขนาดแบบสอบถาม ฯลฯ )
jkavalik

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