ความแตกต่างระหว่าง CTE และ SubQuery หรือไม่


143

จากโพสต์นี้จะใช้ ROW_NUMBER อย่างไรในขั้นตอนต่อไปนี้?

มีสองรุ่นของคำตอบที่หนึ่งใช้sub-queryและอื่น ๆ ใช้CTEเพื่อแก้ปัญหาเดียวกัน

ตอนนี้ข้อดีของการใช้คำCTE (Common Table Expression)สั่งย่อย 'over-query' (ดังนั้นยิ่งอ่านง่ายยิ่งขึ้นว่าการสืบค้นทำอะไรอยู่จริง)

ประโยชน์เฉพาะของใช้CTEมากกว่าsub-selectคือว่าที่จริงผมสามารถตั้งชื่อ sub-queryมีความแตกต่างอื่น ๆ ระหว่างสองสิ่งนี้หรือไม่เมื่อใช้ CTE เป็น CTE แบบง่าย ๆ (ไม่ใช่แบบเรียกซ้ำ)?


คำถามอนุพันธ์ที่มีการอภิปรายที่ดี: stackoverflow.com/q/11169550/781695
ผู้ใช้

7
IMO ใครก็ตามที่คิดว่า CTE นั้นสามารถอ่านได้น้อยกว่ากลุ่มย่อยของ interwoven ขนาดใหญ่นั้นไม่เห็นกองขยะของแบบสอบถามที่มีรูปฟันซี่ทำให้เกิดความสับสนในการใช้งานในระบบการจัดการข้อมูลองค์กรส่วนใหญ่ ขนาดใหญ่คำสั่งที่ไม่น่ารำคาญอย่างมากมักจะง่ายต่อการอ่านในภายหลังหรือด้วยตาใหม่กว่า subqueries และอย่างน้อยในกรณีของ Postgres ดำเนินการอย่างน่าอัศจรรย์มากที่ดีขึ้นในหลายกรณี ([สำหรับเหตุผลที่ฉันยังไม่เข้าใจ [( stackoverflow.com/questions/33731068/ ...... ) เนื่องจากตรงกันข้ามดูเหมือนมีแนวโน้มมากขึ้น)
zxq9

คำตอบ:


102

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

ในทั่วไป ; CTE สามารถใช้ซ้ำได้ แบบสอบถามย่อยไม่สามารถ สิ่งนี้ทำให้พวกเขาเหมาะอย่างยิ่งกับโครงสร้างต้นไม้


1
ขออภัยฉันควรชัดเจนขึ้นในคำถามของฉัน อะไรคือความแตกต่างระหว่าง CTE และแบบสอบถามย่อยในบริบทที่ CTE ใช้แบบสอบถามย่อย LIKE
dance2die

2
@ Marc Gravell: เราสามารถทำได้มากกว่านั้นแม้ว่าจะไม่รับประกันพฤติกรรมของผู้สร้างโปรไฟล์เทียบกับพฤติกรรมของ CTE ซึ่งก็คือ (ในแง่ของการประเมินผล)
casperOne

1
ไม่แน่ใจว่าข้อความนี้สมเหตุสมผลมากแค่ไหนสำหรับผู้ที่มองหา CTS และความแตกต่างของA CTE can be used recursively; a sub-query cannotคำถามย่อย - ตัวอย่างจะดีมาก
Aniket Thakur

88

ข้อได้เปรียบหลักของCommon Table Expression (เมื่อไม่ได้ใช้สำหรับการสอบถามซ้ำ ) คือการห่อหุ้มแทนที่จะต้องประกาศแบบสอบถามย่อยในทุกที่ที่คุณต้องการใช้คุณสามารถกำหนดได้ครั้งเดียว แต่มีการอ้างอิงหลายรายการ เพื่อมัน

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


"คิดว่า CTE เป็นตัวแปรตาราง temp" หมายความว่า CTE ถูกเก็บไว้ในดิสก์หรือในหน่วยความจำหรือไม่?
dance2die

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

@AlexCuse: ฉันคิดว่าฉันได้อธิบายบริบทของ CTE ให้เพียงพอ แต่ฉันได้เพิ่มอีกเพื่อลองและอธิบายเพิ่มเติม
casperOne

@AlexCuse: ยังไม่มีนัยที่ว่า CTE หรือแบบสอบถามย่อยสามารถใช้ในหลาย ๆ ที่ได้ ความแตกต่างระหว่าง CTE และเครื่องมือเพิ่มประสิทธิภาพคือการรับประกันพฤติกรรมของ CTE ในขณะที่พฤติกรรมของเครื่องมือเพิ่มประสิทธิภาพนั้นไม่ได้
casperOne

และฉันจะยอมรับว่าอาจมีบางกรณีที่ขอบ optimizer chokes และแบบสอบถามย่อยได้รับการประเมินมากกว่าหนึ่งครั้งฉันยังไม่พบปัญหาใด ๆ จากนั้นอีกครั้งฉันใช้ CTE ทุกที่ที่ฉันสามารถทำได้)
AlexCuse

15

CTEมีประโยชน์มากที่สุดสำหรับการเรียกซ้ำ:

WITH hier(cnt) AS (
        SELECT  1
        UNION ALL
        SELECT  cnt + 1
        FROM    hier
        WHERE   cnt < @n
        )
SELECT  cnt
FROM    hier

จะส่งคืน@nแถว (มากถึง101) มีประโยชน์สำหรับปฏิทิน, หุ่นจำลองเป็นต้น

พวกเขายังสามารถอ่านได้มากขึ้น (ในความคิดของฉัน)

นอกเหนือจากนี้CTE's และsubqueriesเหมือนกัน


ใน MSSQL คุณจะต้องเพิ่มเซมิโคลอน (;) ก่อนด้วย, สั่งซื้ออย่างชาญฉลาดคุณจะได้รับข้อผิดพลาด มันควรจะเป็น;WITH blabla AS ...)
Obinna Nnenanya

2
@ObinnaNnenanya: เฉพาะในกรณีที่ไม่ใช่ข้อความแรกในแบทช์ การยกเลิกงบของคุณด้วยเครื่องหมายอัฒภาคเป็นความคิดที่ดีอยู่แล้วแม้ว่า SQL Server จะไม่บังคับใช้ในเวอร์ชันปัจจุบันที่นอกเหนือจากก่อนหน้าWITHนี้MERGEและสิ่งที่คล้ายกัน
Quassnoi

10

ความแตกต่างอย่างหนึ่งที่ไม่ได้กล่าวถึงคือ CTE เดียวสามารถอ้างอิงได้ในหลายส่วนของสหภาพ


8

ถ้าฉันไม่มีอะไรขาดหายไปคุณสามารถตั้งชื่อ CTE และคิวรีย่อยได้อย่างง่ายดาย

ฉันเดาว่าความแตกต่างที่สำคัญคือความสามารถในการอ่าน (ฉันพบว่า CTE สามารถอ่านได้มากขึ้นเพราะมันจะกำหนดแบบสอบถามย่อยของคุณไว้ด้านหน้าแทนที่จะอยู่ตรงกลาง)

และถ้าคุณต้องการทำอะไรกับการเรียกซ้ำคุณจะมีปัญหานิดหน่อยในการทำแบบสอบถามย่อย)


1
ผมไม่แน่ใจว่ามีการใด ๆ ที่แตกต่างไม่ใช่ความงาม ( แต่ผมคาดหวังว่าในบางสถานการณ์อาจจะมีความแตกต่างกันเล็กน้อยในแผนการดำเนินการ) สนใจที่จะสอนฉัน
AlexCuse

2
คุณสามารถตั้งชื่อ CTE แต่คุณสามารถนามแฝงเฉพาะแบบสอบถามย่อย ความแตกต่างคือคุณสามารถใช้ CTE ซ้ำด้วยนามแฝงหลายรายการ (cf. @Michael Petito ตัวอย่างในคอมเมนต์ของเขาไปที่ casperOne) ฉันไม่รู้ว่าจะทำอย่างไรกับเคียวรี่ย่อย
kmote

7

ข้อเท็จจริงสำคัญอย่างหนึ่งที่ไม่มีใครพูดถึงคืออย่างน้อยก็ใน postgres CTE เป็นรั้วการเพิ่มประสิทธิภาพ:

https://blog.2ndquadrant.com/postgresql-ctes-are-optimization-fences/

นั่นคือพวกเขาจะได้รับการปฏิบัติเหมือนเป็นแบบสอบถามอะตอมของตัวเองแทนที่จะถูกพับลงในแผนแบบสอบถามทั้งหมด ฉันไม่มีความเชี่ยวชาญในการให้คำอธิบายที่ดีกว่า แต่คุณควรตรวจสอบ semantics สำหรับเวอร์ชั่นของ sql ที่คุณใช้อยู่ สำหรับผู้ใช้ขั้นสูงความสามารถในการสร้างรั้วการปรับให้เหมาะสมสามารถช่วยประสิทธิภาพหากคุณอยู่ในระดับผู้เชี่ยวชาญในการควบคุมตัววางแผนคิวรี อย่างไรก็ตามใน 99% ของกรณีคุณควรหลีกเลี่ยงการพยายามบอกนักวางแผนแบบสอบถามว่าจะทำอย่างไรเพราะสิ่งที่คุณคิดว่าจะเร็วกว่าน่าจะแย่กว่าที่คิดไว้เร็วกว่า :-)


6

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


4

สิ่งหนึ่งที่คุณต้องเข้าใจก็คือใน SQL Server เวอร์ชันเก่า (ใช่แล้วหลายคนยังต้องการสนับสนุนฐานข้อมูล SQL Server 2000), CTE ไม่ได้รับอนุญาตและจากนั้นตารางที่ได้มาก็เป็นทางออกที่ดีที่สุดของคุณ


2

คำแนะนำ: (MAXRECURSION n)

คุณสามารถ จำกัด จำนวนระดับการเรียกซ้ำที่อนุญาตสำหรับคำสั่งเฉพาะโดยใช้MAXRECURSIONคำใบ้และค่าระหว่าง0ถึง 32,767ในOPTIONข้อ

ตัวอย่างเช่นคุณสามารถลอง:

OPTION 
      (MAXRECURSION 150)

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