CTE และ Temp Table แตกต่างกันอย่างไร


174

Common Table Expression (CTE) และ temp แตกต่างกันอย่างไร และฉันควรใช้อันใดอันหนึ่ง

CTE

WITH cte (Column1, Column2, Column3)
AS
(
    SELECT Column1, Column2, Column3
    FROM SomeTable
)

SELECT * FROM cte

ตารางอุณหภูมิ

SELECT Column1, Column2, Column3
INTO #tmpTable
FROM SomeTable

SELECT * FROM #tmpTable


คำตอบ:


200

มันค่อนข้างกว้าง แต่ฉันจะให้คำตอบโดยทั่วไปเท่าที่จะทำได้

CTEs ...

  • ไม่สามารถทำดัชนีได้ (แต่สามารถใช้ดัชนีที่มีอยู่กับวัตถุที่อ้างอิงได้)
  • ไม่สามารถมีข้อ จำกัด
  • ทิ้งหลักVIEWs
  • คงอยู่จนกว่าจะมีการเรียกใช้แบบสอบถามถัดไป
  • สามารถเกิดซ้ำได้
  • ไม่มีสถิติเฉพาะ (ขึ้นอยู่กับสถิติในวัตถุต้นแบบ)

#Temp Tables ...

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

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

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


เร่งความเร็วค่า MERGE ขนาดใหญ่โดยใช้ CTE เป็นสิ่งที่
AgentFire

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

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

29

แก้ไข:

โปรดดูความคิดเห็นของ Martin ด้านล่าง:

CTE ไม่ได้ปรากฏเป็นตารางในหน่วยความจำ มันเป็นเพียงวิธีการห่อหุ้มคำนิยามแบบสอบถาม ในกรณีของ OP มันจะ inlined SELECT Column1, Column2, Column3 FROM SomeTableและเช่นเดียวเพียงแค่การทำ เวลาส่วนใหญ่ที่พวกเขาไม่ได้รับการปรากฏตัวขึ้นล่วงหน้าซึ่งเป็นสาเหตุที่ไม่มีผลตอบแทนแถวWITH T(X) AS (SELECT NEWID())SELECT * FROM T T1 JOIN T T2 ON T1.X=T2.Xยังตรวจสอบแผนการดำเนินการ แม้ว่าบางครั้งมันเป็นไปได้ที่จะแฮ็คแผนเพื่อรับสปูล มีรายการเชื่อมต่อที่ขอคำแนะนำสำหรับสิ่งนี้ - Martin Smith 15 กุมภาพันธ์ 2555 เวลา 17:08 น


คำตอบเดิม

CTE

อ่านเพิ่มเติมเกี่ยวกับ MSDN

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

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

ตารางอุณหภูมิ

อ่านเพิ่มเติมเกี่ยวกับ MSDN - เลื่อนลงประมาณ 40% ของวิธีการ

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

ตารางชั่วคราวมีให้เลือกสองแบบ: ท้องถิ่นและทั่วโลก ในแง่ของ MS SQL Server คุณใช้การ#tableNameกำหนดสำหรับท้องถิ่นและการ##tableNameกำหนดสำหรับทั่วโลก (โปรดทราบการใช้หนึ่งหรือสอง # เป็นลักษณะการระบุ)

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


โดยทั่วไปฉันจะใช้ตาราง temp สำหรับแบบสอบถามที่ยาวกว่าหรือใหญ่กว่าและ CTEs หรือตัวแปร table หากฉันมีชุดข้อมูลขนาดเล็กอยู่แล้วและต้องการสคริปต์โค้ดเร็ว ๆ ประสบการณ์และคำแนะนำของผู้อื่นบ่งชี้ว่าคุณควรใช้ CTE ที่คุณมีจำนวนแถวที่คืนกลับมาเล็กน้อย หากคุณมีจำนวนมากคุณอาจได้รับประโยชน์จากความสามารถในการจัดทำดัชนีในตารางชั่วคราว


11
CTE ไม่ได้ปรากฏเป็นตารางในหน่วยความจำ มันเป็นเพียงวิธีการห่อหุ้มคำนิยามแบบสอบถาม ในกรณีของ OP มันจะถูก inline และเหมือนกับการทำSELECT Column1, Column2, Column3 FROM SomeTable
Martin Smith

4
เวลาส่วนใหญ่ที่พวกเขาไม่ได้รับการปรากฏตัวขึ้นล่วงหน้าซึ่งเป็นสาเหตุที่ไม่มีผลตอบแทนแถวWITH T(X) AS (SELECT NEWID())SELECT * FROM T T1 JOIN T T2 ON T1.X=T2.Xยังตรวจสอบแผนการดำเนินการ แม้ว่าบางครั้งมันเป็นไปได้ที่จะแฮ็คแผนเพื่อรับสปูล มีรายการเชื่อมต่อที่ขอคำแนะนำสำหรับสิ่งนี้
Martin Smith

16

ตอบรับที่นี่กล่าวว่า "CTE ไม่ควรนำมาใช้สำหรับการทำงาน" - แต่ที่อาจทำให้เข้าใจผิด ในบริบทของ CTE เมื่อเทียบกับตาราง temp ฉันเพิ่งเสร็จสิ้นการลบขยะจากชุด procs ที่เก็บไว้เพราะ doofus บางคนต้องคิดว่ามีค่าใช้จ่ายเล็กน้อยหรือไม่มีเลยในการใช้ตาราง temp ฉันผลักล็อตไปสู่ ​​CTE ยกเว้นพวกที่ถูกกฎหมายจะถูกใช้ซ้ำตลอดกระบวนการ ฉันได้รับประสิทธิภาพประมาณ 20% จากการวัดทั้งหมด ฉันตั้งค่าเกี่ยวกับการลบเคอร์เซอร์ทั้งหมดที่พยายามใช้การประมวลผลแบบเรียกซ้ำ นี่คือที่ฉันเห็นได้รับมากที่สุด ฉันสิ้นสุดเวลาตอบสนองอย่างเจ็บแสบโดยปัจจัยสิบ

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


ตอนนี้ขอความยุติธรรม - เคอร์เซอร์คือความชั่วร้ายที่ยิ่งใหญ่ ; ตารางชั่วคราวอยู่ที่เลวร้ายที่สุดที่น้อยกว่าความชั่วร้าย :-) มันไม่ยุติธรรมเลยที่จะทำให้พวกเขาอยู่ในระดับเดียวกับที่คุณเห็นตัวเอง
RDFozz

@RDFozz ขวานรกมี 9 วงการในขณะที่เราทุกคนรู้ว่า ให้วางตารางชั่วคราวที่ 2 และเคอร์เซอร์ที่ ... 7th? ;)
ypercubeᵀᴹ

1
คุณรู้หรือไม่ว่า 'ความชั่วร้ายที่ยิ่งใหญ่' ในการเขียนโปรแกรมคืออะไร? เมื่อมีคนบอกว่าเทคนิคเฉพาะคือความชั่วร้าย มีที่สำหรับเคอร์เซอร์ พวกเขาสามารถทำได้ดีกว่าเทคนิคอื่น ๆ ในบางสถานการณ์ ไม่มีความชั่วร้ายอยู่ที่นี่ - คุณต้องเรียนรู้ที่จะใช้เครื่องมือที่เหมาะสมสำหรับงาน วัดสิ่งที่คุณทำและไม่เชื่อว่าโฆษณาของ CTE, Temp Tables หรือ Cursors นั้นชั่วร้าย การวัด - เพราะความจริงขึ้นอยู่กับสถานการณ์
Dave Hilditch

@DaveHilditch นั่นเป็นความคิดเห็นที่ยุติธรรม แต่มันก็เป็นความคิดเห็นที่ยุติธรรมเพื่อยืนยันว่าในหลาย ๆ สถานการณ์เคอร์เซอร์ไม่ใช่ทางออกที่ถูกต้อง
Mel Padden

1
จากประสบการณ์ของฉันเคอร์เซอร์ไม่ได้เลวร้ายในตัวเอง เคอร์เซอร์มักจะใช้ "ผิด" โดยนักพัฒนาเพราะในภาษาการเขียนโปรแกรมส่วนใหญ่คุณต้องคิดซ้ำแล้วซ้ำอีกเมื่อเทียบกับ SQL ที่คุณต้องคิดเป็นชุด ฉันรู้ว่านี่เป็นข้อผิดพลาดทั่วไปที่สถานที่ทำงานของฉันซึ่ง Devs ไม่สามารถ "มองเห็น" ปัญหาที่นอกเหนือจาก CURSOR ได้ดังนั้นเหตุใด DBA ที่ดีจึงมีประโยชน์ในการสอนและแก้ไขให้ถูกต้อง @DaveHilditch นั้นถูกต้องทั้งหมด: เครื่องมือที่เหมาะสมสำหรับงานที่ถูกต้องคือสิ่งที่ต้องทำ
ฟิลิปป์

14

CTE อาจถูกเรียกซ้ำ ๆ ภายในแบบสอบถามและประเมินผลทุกครั้งที่มีการอ้างอิง - กระบวนการนี้สามารถเรียกซ้ำได้ ถ้ามันถูกเรียกเพียงครั้งเดียวมันจะทำตัวคล้ายกับเคียวรีย่อยแม้ว่า CTE จะสามารถกำหนดพารามิเตอร์ได้

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

ตัวแปรตาราง IIRC (ในทางกลับกัน) เป็นโครงสร้างในหน่วยความจำเสมอ


4
สามารถกำหนดพารามิเตอร์ CTE ได้หรือไม่ อย่างไร? นอกจากนี้ตัวแปรตารางไม่ได้เสมอโครงสร้างในหน่วยความจำ ดูคำตอบที่ดีเลิศของ Martin สำหรับคำถามที่เกี่ยวข้อง
Paul White

11

ตารางชั่วคราวเป็นวัตถุจริงใน tempdb แต่ cte เป็นเพียงตัวห่อหุ้มรอบเคียวรีที่ซับซ้อนเพื่อทำให้ไวยากรณ์ของการจัดการการเรียกซ้ำเป็นเรื่องง่ายในขั้นตอนเดียว


8

เหตุผลหลักในการใช้ CTE คือเข้าถึงฟังก์ชั่นหน้าต่างเช่นrow_number()และอื่น ๆ อีกมากมาย

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

with reallyfastcte as (
select *, 
row_number() over (partition by groupingcolumn order by sortingcolumn) as rownum
from sometable
)
select *
from reallyfastcte
where rownum = 1;

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

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

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

ในที่สุด CTE จะไม่ใช้ tempdb โดยค่าเริ่มต้นดังนั้นคุณจึงลดความขัดแย้งในคอขวดนั้นผ่านการใช้งาน

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


คะแนนที่ดีทั้งหมด ... +1
Mel Padden

6

ดูเหมือนว่าจะมีการคัดค้านเล็กน้อยต่อ CTE

ความเข้าใจของฉันเกี่ยวกับ CTE คือโดยทั่วไปมันเป็นมุมมองแบบเฉพาะกิจ SQL เป็นทั้งการประกาศและชุดภาษา CTE เป็นวิธีที่ดีในการประกาศชุด! การไม่สามารถจัดทำดัชนี CTE นั้นเป็นสิ่งที่ดีเพราะคุณไม่จำเป็นต้องทำ! จริง ๆ แล้วมันเป็นน้ำตาลทรายชนิด syntactic เพื่อให้การสืบค้นอ่าน / เขียนง่ายขึ้น เครื่องมือเพิ่มประสิทธิภาพที่เหมาะสมจะทำงานกับแผนการเข้าถึงที่ดีที่สุดโดยใช้ดัชนีบนตารางที่เกี่ยวข้อง ซึ่งหมายความว่าคุณสามารถเพิ่มความเร็วในการสืบค้น CTE ของคุณได้อย่างมีประสิทธิภาพโดยทำตามคำแนะนำดัชนีในตารางพื้นฐาน

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

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

ฉันต้องยอมรับว่าประสบการณ์ของฉันเป็นส่วนใหญ่กับ DB2 ดังนั้นฉันสมมติว่างานของ CTE ในลักษณะที่คล้ายกันในผลิตภัณฑ์ทั้งสอง ฉันจะยืนแก้ไขอย่างมีความสุขหาก CTE นั้นด้อยกว่าในเซิร์ฟเวอร์ SQL ;)

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