มีความแตกต่างด้านประสิทธิภาพระหว่าง CTE, Sub-Query, Temporary Table หรือ Table Variable หรือไม่?


222

ในคำถาม SO ที่ยอดเยี่ยมนี้ความแตกต่างระหว่างCTEและsub-queriesถูกกล่าวถึง

ฉันต้องการถามเฉพาะ:

แต่ละเหตุการณ์ต่อไปนี้มีประสิทธิภาพมากขึ้น / เร็วขึ้นในสถานการณ์ใด

  • CTE
  • แบบสอบถามย่อย
  • ตารางชั่วคราว
  • ตัวแปรตาราง

ตามเนื้อผ้าฉันได้ใช้ความพยายามอย่างมากtemp tablesในการพัฒนาstored proceduresเนื่องจากดูเหมือนว่าจะสามารถอ่านได้มากกว่าแบบสอบถามย่อยแบบพัน

Non-recursive CTEสรุปชุดข้อมูลได้ดีมากและอ่านได้มาก แต่มีสถานการณ์เฉพาะที่ใคร ๆ สามารถพูดได้ว่าพวกเขาจะทำงานได้ดีขึ้นหรือไม่ หรือว่าเป็นกรณีที่ต้องทำตัวตาม ๆ ตัวเลือกต่าง ๆ เพื่อหาทางออกที่มีประสิทธิภาพที่สุด?


แก้ไข

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


4
คำตอบทั่วไป: มันขึ้นอยู่กับ และมันก็ขึ้นอยู่กับปัจจัยหลายอย่างข้อความทั่วไปที่อาจเป็นเท็จ - ในบางสถานการณ์ โดยทั่วไป: คุณต้องทดสอบและวัด - ดูว่าแบบไหนดีที่สุดสำหรับคุณ!
marc_s

@marc_s - ตกลง บางทีคำถามนี้ควรถูกปิดเพราะเป็นอัตนัย คุณคิดว่าคำถาม SQL จำนวนมากใน SO นั้นอาจถูกตัดสินว่าเป็นอัตนัย
ทำไม

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

@marc_s เป็นการดีที่จะลองและรักษาไว้ - คำแนะนำใด ๆ ในการแก้ไข OP ที่เป็นไปได้เพื่อพยายามทำให้เจาะจงและแคบกว่านี้?
ทำไม

โปรดทราบคำถามนี้เฉพาะกับ SQL Server สำหรับ DB อื่น ๆ เช่น postgres CTE มักจะช้ากว่าเคียวรีย่อยที่เทียบเท่า (ดูhttp://blog.2ndquadrant.com/postgresql-ctes-are-optimization-fences/ )
Jay

คำตอบ:


243

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

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

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

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

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

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


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

3
ระบุว่ากระดาษนั้นถูกนำเสนอในปี 2007 ความคิดใด ๆ ว่าพวกเขาได้รวมไว้ใน SQL Server 2012 หรือไม่?
Gordon Linoff

3
คำตอบที่ดี! เพียงเพื่อเน้น: SQL เป็นภาษาที่ประกาศและเราไม่ได้ควบคุมวิธีการดึงข้อมูล ดังนั้นประสิทธิภาพ / ความเร็วแตกต่างกันไปจากแบบสอบถามเพื่อสอบถาม
Simcha Khabinsky

2
@RGS . . ดัชนีในตารางชั่วคราวจะปรับปรุงการสืบค้นที่สามารถใช้ประโยชน์จากดัชนีเหล่านั้นได้อย่างแน่นอนเช่นเดียวกับดัชนีในตารางถาวร แต่ถ้าคุณสร้างแบบสอบถามย่อยเป็นตารางชั่วคราวคุณอาจสูญเสียความได้เปรียบของดัชนีในตารางต้นฉบับ
Gordon Linoff

2
@RGS . . เมื่อเครื่องมือฐานข้อมูล materialize แบบสอบถามย่อย / CTE ในระหว่างการดำเนินการค้นหาที่ซับซ้อนก็ไม่ได้เพิ่มดัชนีใน Materialization คุณสามารถทำได้ด้วยตนเองโดยใช้ตารางชั่วคราว
Gordon Linoff

77

ไม่มีกฎ ฉันพบว่า CTE สามารถอ่านได้มากขึ้นและใช้พวกเขายกเว้นว่าพวกเขามีปัญหาด้านประสิทธิภาพซึ่งในกรณีนี้ฉันตรวจสอบปัญหาจริงแทนที่จะคาดเดาว่า CTE นั้นเป็นปัญหาและลองเขียนใหม่โดยใช้วิธีอื่น โดยทั่วไปมักจะมีปัญหามากกว่าวิธีที่ฉันเลือกที่จะบอกความตั้งใจของฉันกับแบบสอบถาม

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

ค่อนข้างตรงไปตรงมามีตัวแปรมากเกินไปที่จะให้คำตอบที่ "ถูกต้อง" สำหรับคำถามของคุณ ไม่มีวิธีที่สามารถคาดเดาได้ว่าแบบสอบถามจะให้ทิปเมื่อมีวิธีใดวิธีหนึ่งหรือเพียงแค่รู้ว่าในทางทฤษฎีความหมายเดียวกันสำหรับ CTE หรือแบบสอบถามย่อยเดียวควรดำเนินการแบบเดียวกัน ฉันคิดว่าคำถามของคุณจะมีค่ามากกว่าหากคุณนำเสนอบางกรณีที่ไม่เป็นความจริง - อาจเป็นไปได้ว่าคุณได้ค้นพบข้อ จำกัด ในเครื่องมือเพิ่มประสิทธิภาพ (หรือค้นพบที่รู้จัก) หรืออาจเป็นได้ว่าแบบสอบถามของคุณไม่เทียบเท่าเชิงความหมาย หรือองค์ประกอบนั้นมีองค์ประกอบที่ขัดขวางการเพิ่มประสิทธิภาพ

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


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

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

ใต้คำถามของคุณมีลิงก์link / edit / close / flag- หากมีการโหวตให้ปิดคำถามคุณจะเห็นclose (n)ว่าnจำนวนผู้ใช้ที่โหวตให้ปิดคำถามของคุณอยู่ที่ไหน หากคุณคลิกที่ลิงก์คุณจะเห็นสาเหตุที่ผู้ใช้เลือก
Aaron Bertrand

@whytheq ยังเห็นบล็อกโพสต์ล่าสุดโดยบ๊อบ Beauchemin มันไม่ได้ปฏิบัติกับคำค้นหาย่อย CTE โดยเฉพาะ แต่มีแนวคิดแบบเดียวกันที่ใช้: หากคุณเลือกรูปแบบที่ไม่ได้ใช้งานง่ายสำหรับเหตุผลด้านประสิทธิภาพให้จัดทำอึออกจากเอกสารและเข้าชมอีกครั้งเพื่อให้แน่ใจว่ามุมแหลมที่คุณค้นพบยังคงเป็นจริง ฉันยังอาจแนะนำให้ปล่อยให้แบบสอบถามมีความคิดเห็นที่เป็นธรรมชาติมากกว่านี้เว้นแต่คุณจะมีระบบควบคุมแหล่งที่เชื่อถือได้แทนรุ่นก่อนหน้า
Aaron Bertrand

1
ลิงก์ถาวรด้านบน: sqlskills.com/blogs/bobb/…
ADJenks

19

#temp ถูกทำให้เป็นโมฆะและ CTE ไม่ใช่

CTE เป็นเพียงไวยากรณ์ดังนั้นในทางทฤษฎีมันเป็นเพียงแบบสอบถามย่อย มันถูกประหารชีวิต #temp เป็นรูปธรรม ดังนั้น CTE ราคาแพงในการเข้าร่วมที่ดำเนินการหลายครั้งอาจดีกว่าใน #temp ในอีกด้านหนึ่งถ้าเป็นการประเมินง่าย ๆ ที่ไม่ได้ดำเนินการ แต่ไม่กี่ครั้งก็ไม่คุ้มกับค่าใช้จ่ายของ #temp

มีบางคนใน SO ที่ไม่ชอบตัวแปร table แต่ฉันชอบพวกเขาเนื่องจากเป็นรูปธรรมและสร้างได้เร็วกว่า #temp มีบางครั้งที่เครื่องมือเพิ่มประสิทธิภาพการสืบค้นทำได้ดีกว่าด้วย #temp เปรียบเทียบกับตัวแปรตาราง

ความสามารถในการสร้าง PK บน #temp หรือตัวแปรตารางให้ข้อมูลเครื่องมือเพิ่มประสิทธิภาพการสืบค้นมากกว่า CTE (เนื่องจากคุณไม่สามารถประกาศ PK บน CTE)


ตัวย่อ "TVP" คืออะไร ... คล้ายกับ #temp
ทำไม

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

1
คำเตือน - TVPs ไม่มีแผนการดำเนินการ! อย่าใช้ TVP สำหรับสิ่งอื่นใดนอกจากรายการค้นหาสั้น ๆ ที่ง่ายที่สุด หากคุณทำการเชื่อมต่อแทรกหรืออัพเดทใด ๆ ที่ซับซ้อนคุณอาจพบปัญหาการเพิ่มประสิทธิภาพจำนวนมาก เชื่อใจฉันฉันถูกไฟไหม้โดยสิ่งนี้
Heliac

12

เพียง 2 สิ่งที่ฉันคิดว่าทำให้ดีกว่าเสมอที่จะใช้ # Temp Table แทน CTE คือ:

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

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


- เมื่อวานเมื่อวานนี้

นี่คือตัวอย่างที่ข้อ จำกัด #table สามารถป้องกันข้อมูลที่ไม่ถูกต้องซึ่งไม่ใช่ใน CTE

DECLARE @BadData TABLE ( 
                       ThisID int
                     , ThatID int );
INSERT INTO @BadData
       ( ThisID
       , ThatID
       ) 
VALUES
       ( 1, 1 ),
       ( 1, 2 ),
       ( 2, 2 ),
       ( 1, 1 );

IF OBJECT_ID('tempdb..#This') IS NOT NULL
    DROP TABLE #This;
CREATE TABLE #This ( 
             ThisID int NOT NULL
           , ThatID int NOT NULL
                        UNIQUE(ThisID, ThatID) );
INSERT INTO #This
SELECT * FROM @BadData;
WITH This_CTE
     AS (SELECT *
           FROM @BadData)
     SELECT *
       FROM This_CTE;

3
ALWAYSไกลเกินไป แต่ขอบคุณคำตอบ ในแง่ของความสามารถในการอ่านการใช้ CTE อาจเป็นเรื่องที่ดี
ทำไม

3
ฉันไม่เข้าใจประเด็นที่สองของคุณเลย วิธีที่ฉันเห็นมันแบบสอบถามที่กำหนด CTE นั้นคล้ายกับข้อ จำกัด ที่คุณวางไว้บนตารางชั่วคราวโดยสังเกตว่าในอดีตสามารถประกอบเพรดิเคตที่ซับซ้อนโดยพลการในขณะที่หลังมี จำกัด มากขึ้น (เช่นCHECKข้อ จำกัด หมายถึงหลายแถว / ตาราง ไม่ได้รับอนุญาต). คุณสามารถโพสต์ตัวอย่างที่ CTE แสดงข้อผิดพลาดที่เทียบเท่ากับ temp table ไม่ได้หรือไม่?
oneday เมื่อ
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.