เป็นไปได้หรือไม่ว่าคำสั่งนั้นจะไม่รับประกันสำหรับตารางที่ซ้ำซ้อนนี้


12

ฉัน stumbled เมื่อคำถามนี้ในการสนทนา Twitter กับ Lukas เอ๊ด

แม้ว่าพฤติกรรมที่ถูกต้องจะใช้คำสั่งย่อย ORDER BY กับการสืบค้นนอกสุดเนื่องจากที่นี่เราไม่ได้ใช้ DISTINCT, GROUP BY, JOIN หรือส่วนคำสั่ง WHERE ใด ๆ ในการค้นหานอกสุดทำไม RDBMS ถึงไม่ผ่าน ข้อมูลที่เข้ามาในขณะที่มันถูกจัดเรียงตามแบบสอบถามภายใน?

SELECT * 
FROM (
    SELECT * FROM table ORDER BY time DESC
) AS t

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

ดังนั้นฉันจะสมมติว่าผู้วางแผนจะยกเลิกการสืบค้นนอกสุดเพียงเพราะซ้ำซ้อนหรือเพียงแค่ส่งผ่านผลลัพธ์จากตารางด้านใน

ไม่มีใครคิดว่านี่อาจเป็นกรณีหรือไม่


4
โปรดทราบว่าแบบสอบถามของคุณจะล้มเหลวใน SQL Server เพราะคำสั่งซื้อไม่ได้รับอนุญาตภายในตารางที่ได้รับ
a_horse_with_no_name

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

2
"ฉันจะสมมติว่าผู้วางแผนจะยกเลิกการสืบค้นนอกสุดเพียงเพราะซ้ำซ้อนหรือเพียงแค่ส่งผ่านผลลัพธ์จากตารางด้านใน" คุณสามารถสันนิษฐานได้ง่ายๆว่าผู้วางแผนจะยกเลิกส่วนคำสั่งซื้อในแบบสอบถามภายในเนื่องจากไม่มีความหมายในบริบท
สัญลักษณ์แทน

MariaDB ประมาณปี 2012กล่าวถึงปัญหานี้ ขาดภายในORDER BYนำไปสู่การที่แตกต่างกันการเพิ่มประสิทธิภาพสำหรับ GroupWise สูงสุด
Rick James เมื่อ

1
ที่จริงแล้วคุณเหมาะกับ Postgres
Erwin Brandstetter

คำตอบ:


20

ฐานข้อมูลส่วนใหญ่ค่อนข้างชัดเจนเกี่ยวกับข้อเท็จจริงที่ว่าORDER BYในแบบสอบถามย่อยเป็นอย่างใดอย่างหนึ่ง:

  • ไม่อนุญาต: เช่น SQL Server, Sybase SQL Anywhere (เว้นแต่จะได้รับการสนับสนุนTOPหรือOFFSET .. FETCH)
  • ความหมาย: เช่น PostgreSQL, DB2 (อีกครั้งยกเว้นว่ามีOFFSET .. FETCHหรือLIMIT)

นี่คือตัวอย่างจากคู่มือ DB2 LUW (เหมืองเน้นที่)

คำสั่งย่อย ORDER BY ในการเลือกย่อยจะไม่ส่งผลกระทบต่อลำดับของแถวที่ส่งคืนโดยแบบสอบถาม ส่วนคำสั่ง ORDER BY จะมีผลกับลำดับของแถวที่ส่งคืนหากมีการระบุใน fullselect สุดสุด

ถ้อยคำที่ค่อนข้างชัดเจนเช่นเดียวกับของ PostgreSQL :

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

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

หมายเหตุด้านบน DB2:

โดยเฉพาะอย่างยิ่งDB2 มีคุณสมบัติที่รู้จักน้อยกว่าที่เรียกว่าORDER BY ORDER OF <table-designator>ซึ่งสามารถใช้ดังนี้:

SELECT C1 FROM
   (SELECT C1 FROM T1
      UNION
    SELECT C1 FROM T2
    ORDER BY C1 ) AS UTABLE
ORDER BY ORDER OF UTABLE

ในกรณีพิเศษนี้การเรียงลำดับของตารางที่ได้รับสามารถนำกลับมาใช้ใหม่ได้อย่างชัดเจนใน SELECT ส่วนใหญ่ด้านนอก

หมายเหตุด้านบน Oracle:

เป็นเวลาหลายปีแล้วที่ Oracle ได้ใช้การให้OFFSETเลขหน้าโดยใช้การROWNUMคำนวณซึ่งสามารถคำนวณได้อย่างสมเหตุสมผลหลังจากสั่งซื้อตารางที่ได้รับ:

SELECT *
FROM (
  SELECT rownum AS rn, t.* -- ROWNUM here depends on the derived table's ordering
  FROM (
    SELECT * FROM table ORDER BY time DESC
  ) t
) t
WHERE rn BETWEEN 10 AND 20

เป็นที่คาดหวังได้ว่าอย่างน้อยเมื่อมีROWNUMการสืบค้นในอนาคต Oracle เวอร์ชันในอนาคตจะไม่ทำลายพฤติกรรมนี้เพื่อไม่ทำลายมรดกทั้งหมดของ Oracle SQL ที่มีอยู่ซึ่งยังไม่ได้ทำการโยกย้ายไปยังที่ต้องการและอื่น ๆ อีกมากOFFSET .. FETCHไวยากรณ์มาตรฐาน SQL ที่อ่านได้:

SELECT * FROM table ORDER BY time DESC OFFSET 10 ROWS FETCH NEXT 10 ROWS ONLY

Meaningless: E.g. PostgreSQLจริงๆควรจะ: 'น่าเชื่อถือ' เพราะมันไม่สิ่งที่หมายถึง แถวจะถูกจัดเรียงในเคียวรีด้านในและลำดับนั้นจะถูกเก็บไว้ในระดับเคียวรีด้านนอกเว้นแต่จะมีคำแนะนำเป็นอย่างอื่นหรือการเรียงลำดับใหม่เป็นโอกาสที่ดีสำหรับการดำเนินการเพิ่มเติม แม้ว่าจะเป็นเพียงรายละเอียดการนำไปใช้ แต่ก็ไม่มีความหมาย สิ่งนี้สามารถใช้สำหรับการป้อนข้อมูลเรียงลำดับเพื่อฟังก์ชั่นรวม คู่มือยังให้คำแนะนำมาก: Alternatively, supplying the input values from a sorted subquery will usually work.
Erwin Brandstetter

คำพูดที่คุณเพิ่มสำหรับ Postgres นั้นใช้กับกรณีอื่น: แบบสอบถามโดยไม่มีORDER BYเลย
Erwin Brandstetter

@ErwinBrandstetter: อย่าลังเลที่จะเพิ่มคำตอบพร้อมรายละเอียดเหล่านั้น ฉันเองไม่เห็นด้วยว่ารายละเอียดการปฏิบัติมีความหมาย เพียงแค่วันนี้ฉันได้เรียนรู้ว่าในสมัยก่อนผู้คนที่อาศัยอยู่ใน Oracle มักจะแสดงกลุ่มที่เรียงลำดับโดยการดำเนินการใน Oracle 8i (ฉันเชื่อ) เมื่อจู่ ๆ รุ่นใหม่ที่แนะนำกลุ่มแฮชโดยซึ่งทำลายสมมติฐานที่ว่า การสั่งซื้ออาจจะพึ่งพา ในคำอื่น ๆ : ฉันชอบที่จะวางไว้ในคำที่เป็นตัวหนา ไร้ความหมายมากกว่าจะเป็นโอ้ถ้าคุณรู้รายละเอียดที่ซับซ้อนของรุ่น xyz คุณสามารถ ...
Lukas Eder

ฉันได้เพิ่มคำตอบแล้ว ไม่ว่าเราจะเลือกที่จะเพิกเฉยต่อพฤติกรรมที่ไม่ได้มาตรฐานหรือคำแนะนำที่ดีอื่น ๆ ที่เรามีอยู่ข้างคำถาม: มีการรับประกันคำสั่งซื้อสำหรับคำค้นหาที่ระบุหรือไม่ มันมีไว้สำหรับ Postgres มันไม่ได้ (หรือไม่สามารถใช้งานได้) สำหรับ RDBMS อื่น และนั่นใช้ได้กับPostgres ทุกเวอร์ชันที่มีอยู่ไม่ใช่เฉพาะกับรุ่น xyz มันเป็นเอกสาร (แม้จะมีการจอง) คำพูดของคุณทำให้เข้าใจผิด ถ้าเราต้องการละเว้นพฤติกรรมที่ไม่ได้มาตรฐานเราอาจเริ่มต้นด้วย Oracle ทำให้เราเชื่อว่า NULL และสตริงว่างเหมือนกัน ยังตั้งฉากกับคำถาม
Erwin Brandstetter

@ErwinBrandstetter: น่าสนใจขอบคุณสำหรับการอัพเดท นี่เป็นการรับประกันว่าคุณกำลังอ้างถึงเอกสารหรือไม่
Lukas Eder

12

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

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

อย่าพึ่งพาพฤติกรรมที่ไม่ได้กำหนด หากคุณต้องการคำสั่งซื้อที่เฉพาะเจาะจงให้ORDER BYประโยคในสถานที่ที่เหมาะสม


เมื่อทำการทดสอบบน PostgreSQL การเรียงลำดับเสร็จสิ้นหลังจากการสแกนตามลำดับเนื่องจากฉันไม่มีดัชนีใด ๆ ในคอลัมน์ที่ ORDER BY ใช้ คุณคิดว่า RDBMS ใดที่จะข้ามแบบสอบถามภายใน ORDER BY?
Vlad Mihalcea

5
ฉันไม่สามารถบอกได้ว่าฉันรู้ว่าอะไรจะเกิดขึ้นเพียงว่าพวกเขามีอิสระที่จะทำเช่นนั้นอย่างสมบูรณ์หากพวกเขาต้องการ - มันจะเป็นการปรับให้เหมาะสมที่ยอมรับได้อย่างสมบูรณ์ตามมาตรฐานทั่วไป SQL Server จะปฏิเสธการสอบถามทันที (เว้นแต่คุณจะรวมTOP 100%ดังนั้นการสืบค้นปัจจุบันไม่สามารถพกพาได้ควรเป็นลำดับความสำคัญสำหรับโครงการของคุณเนื่องจาก Postgres เชื่อฟังการเรียงลำดับในแบบสอบถามภายในตอนนี้ไม่ได้หมายความว่าจะเกิดขึ้นในอนาคตเสมอ อันที่จริงแล้วเวอร์ชั่นเก่าทำดังนั้นคุณควรหลีกเลี่ยงการพึ่งพาพฤติกรรมในกรณีนี้
David Spillett

1
@VladMihalcea DBMS ที่ "เพิ่มประสิทธิภาพ" ซ้ำซ้อนORDER BYคือMariaDB: ทำไม ORDER BY ในแบบสอบถามย่อยถูกละเว้น?
ypercubeᵀᴹ

6

มันเป็นปัญหาที่เกิดขึ้นกับพฤติกรรมที่ไม่ได้กำหนด - เหมาะกับคุณทำงานสำหรับฉันฟอร์แมต HDD ในผลิตภัณฑ์;)

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


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

2
โดยเฉพาะอย่างยิ่งเซิร์ฟเวอร์อาจใช้ประโยชน์จากความขนานในการอ่านตาราง หากเป็นเช่นนั้นและไม่จำเป็นต้องบังคับใช้คำสั่งซื้อคุณจะได้แถวกลับมา แต่ไม่สามารถอ่านได้ (SQL Server ทำเช่นนี้เพื่อให้ a ที่SELECTไม่มีความORDER BYจริงเป็น nondeterministic และไม่เพียง แต่ในทางทฤษฎีหรือเพราะข้อมูลมีการเปลี่ยนแปลง)
Jeroen Mostert

@JeroenMostert: พฤติกรรมที่ไม่ได้กำหนดจะแย่ลงเรื่อย ๆ จะเกิดอะไรขึ้นถ้ามันไม่เรียบร้อยและเดลต้าถูกใช้เพื่อจัดทำดัชนีในอาร์เรย์
โจชัว

2

เป็นไปได้หรือไม่ว่าคำสั่งนั้นจะไม่รับประกันสำหรับตารางที่ซ้ำซ้อนนี้

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

ผู้ใช้เซิร์ฟเวอร์ SQL จะรู้สึกอึดอัดกับสิ่งนี้เนื่องจาก Microsoft ไม่อนุญาตให้ใช้ORDER BYในแบบสอบถามย่อย มีการรับประกันการเรียงลำดับสำหรับเคียวรีแบบง่ายนี้ใน Postgres อย่างไรก็ตาม ORDER BYถูกนำไปใช้ในแบบสอบถามย่อยและแบบสอบถามด้านนอกไม่ได้ทำอะไรที่อาจเปลี่ยนลำดับ

คู่มือยังให้คำแนะนำมากยิ่งขึ้นในบทรวมฟังก์ชัน :

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

โปรดทราบว่านี่เป็นจริงในขณะที่ระดับการสืบค้นภายนอกไม่สามารถเพิ่มการดำเนินการที่อาจเปลี่ยนลำดับ ดังนั้นจึงเป็นเพียง "รับประกัน" สำหรับกรณีง่าย ๆ และนั่นไม่ได้รับการสนับสนุนโดยมาตรฐาน SQL Postgres มีอิสระที่จะจัดลำดับใหม่หากมีโอกาสสำหรับการดำเนินการเพิ่มเติม ในกรณีที่มีข้อสงสัยเพิ่มอีกไปด้านนอกORDER BY SELECT(ในกรณีนี้เสียงภายในORDER BYจะเป็นเสียงซ้ำซ้อนสำหรับเคียวรีแบบง่ายนี้)


เป็นจริงหรือไม่เมื่อ"table"ไม่ใช่ตารางพื้นฐาน แต่เป็นมุมมองที่ซับซ้อนหรือตารางที่แบ่งพาร์ติชัน เป็นจริงหรือไม่เมื่อแผนมีการปฏิบัติแบบคู่ขนานด้วย เป็นจริงใน Postgres 10 เช่นกัน? (ผมก็แค่ถามว่าผมไม่แน่ใจว่าคำตอบของคำถามเหล่านี้ได้.)
ypercubeᵀᴹ

@ ypercubeᵀᴹ: ฉันยังไม่ได้ทดสอบ Postgres 10 สำหรับสิ่งเหล่านี้ทั้งหมด แต่ฉันค่อนข้างมั่นใจว่ามันเป็นจริงในทุกกรณี มีการนำใบสั่งซื้อไปใช้และไม่เปลี่ยนแปลงในการสืบค้นภายนอกสำหรับกรณีง่าย ๆ
Erwin Brandstetter
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.