ซึ่งมีประสิทธิภาพมากขึ้นCTE
หรือTemporary Tables
?
ซึ่งมีประสิทธิภาพมากขึ้นCTE
หรือTemporary Tables
?
คำตอบ:
ฉันว่าพวกเขามีแนวคิดที่แตกต่างกัน แต่ไม่แตกต่างกันที่จะพูดว่า "ชอล์คและชีส"
ตาราง temp นั้นดีสำหรับการนำกลับมาใช้ใหม่หรือทำการประมวลผลหลายรอบผ่านชุดข้อมูล
CTE สามารถใช้เพื่อชดเชยหรือเพื่อให้อ่านง่ายขึ้น
และเช่นเดียวกับฟังก์ชั่นที่มีมูลค่าการดูหรือตารางอินไลน์ยังสามารถได้รับการปฏิบัติเหมือนแมโครที่จะขยายในแบบสอบถามหลัก
ตาราง temp เป็นอีกตารางที่มีกฎรอบขอบเขต
ฉันได้เก็บ procs ที่ฉันใช้ทั้ง (และตัวแปรตารางด้วย)
cte vs temporary tables
IMHO คำตอบนี้ต้องเน้นข้อเสียของ CTE ให้ดีขึ้น TL; DR ของคำตอบที่เชื่อมโยง: CTE ไม่ควรใช้สำหรับประสิทธิภาพ . ฉันเห็นด้วยกับคำพูดนั้นในขณะที่ฉันพบข้อเสียของ CTE
มันขึ้นอยู่กับ.
ก่อนอื่นเลย
นิพจน์ตารางทั่วไปคืออะไร
CTE (ไม่ใช่แบบเรียกซ้ำ) จะได้รับการปฏิบัติคล้ายกับโครงสร้างอื่น ๆ ที่สามารถใช้เป็นนิพจน์ตารางแบบอินไลน์ใน SQL Server ได้ ฟังก์ชันตารางที่ได้รับมามุมมองและอินไลน์ที่ได้รับมา โปรดทราบว่าในขณะที่ BOL บอกว่า CTE "สามารถคิดได้ว่าเป็นชุดผลลัพธ์ชั่วคราว" นี่เป็นคำอธิบายเชิงตรรกะอย่างแท้จริง บ่อยกว่านั้นไม่ได้ถูก materlialized ในสิทธิของตนเอง
ตารางชั่วคราวคืออะไร
นี่คือชุดของแถวที่เก็บไว้ในหน้าข้อมูลใน tempdb หน้าข้อมูลอาจอยู่บางส่วนหรือทั้งหมดในหน่วยความจำ นอกจากนี้ตารางชั่วคราวอาจถูกทำดัชนีและมีสถิติคอลัมน์
ทดสอบข้อมูล
CREATE TABLE T(A INT IDENTITY PRIMARY KEY, B INT , F CHAR(8000) NULL);
INSERT INTO T(B)
SELECT TOP (1000000) 0 + CAST(NEWID() AS BINARY(4))
FROM master..spt_values v1,
master..spt_values v2;
ตัวอย่างที่ 1
WITH CTE1 AS
(
SELECT A,
ABS(B) AS Abs_B,
F
FROM T
)
SELECT *
FROM CTE1
WHERE A = 780
แจ้งให้ทราบล่วงหน้าในแผนด้านบนไม่มีการกล่าวถึง CTE1 มันเข้าถึงตารางฐานโดยตรงและถือว่าเหมือนกับ
SELECT A,
ABS(B) AS Abs_B,
F
FROM T
WHERE A = 780
การเขียนซ้ำโดยการทำให้ CTE เป็นจริงในตารางชั่วคราวระดับกลางที่นี่จะเป็นการตอบโต้อย่างมีประสิทธิผล
การทำให้คำนิยาม CTE เป็นจริงของ
SELECT A,
ABS(B) AS Abs_B,
F
FROM T
จะเกี่ยวข้องกับการคัดลอกข้อมูลประมาณ 8GB ลงในตารางชั่วคราวจากนั้นยังมีค่าใช้จ่ายในการเลือกจากมันเกินไป
ตัวอย่างที่ 2
WITH CTE2
AS (SELECT *,
ROW_NUMBER() OVER (ORDER BY A) AS RN
FROM T
WHERE B % 100000 = 0)
SELECT *
FROM CTE2 T1
CROSS APPLY (SELECT TOP (1) *
FROM CTE2 T2
WHERE T2.A > T1.A
ORDER BY T2.A) CA
ตัวอย่างข้างต้นใช้เวลาประมาณ 4 นาทีในเครื่องของฉัน
เฉพาะ 15 แถวของค่าสุ่ม 1,000,000 ค่าที่ตรงกับเพรดิเคต แต่การสแกนตารางราคาแพงเกิดขึ้น 16 ครั้งเพื่อค้นหาตำแหน่งเหล่านี้
นี่จะเป็นตัวเลือกที่ดีสำหรับการแสดงผลลัพธ์ระดับกลางที่เป็นจริง การเขียนตาราง temp ที่เทียบเท่านั้นใช้เวลา 25 วินาที
INSERT INTO #T
SELECT *,
ROW_NUMBER() OVER (ORDER BY A) AS RN
FROM T
WHERE B % 100000 = 0
SELECT *
FROM #T T1
CROSS APPLY (SELECT TOP (1) *
FROM #T T2
WHERE T2.A > T1.A
ORDER BY T2.A) CA
วัสดุที่อยู่ตรงกลางของส่วนหนึ่งของแบบสอบถามลงในตารางชั่วคราวบางครั้งอาจมีประโยชน์แม้ว่าจะมีการประเมินเพียงครั้งเดียว - เมื่ออนุญาตให้ส่วนที่เหลือของแบบสอบถามสามารถคอมไพล์ใหม่โดยใช้ประโยชน์จากสถิติในผลลัพธ์ที่ปรากฏ ตัวอย่างของวิธีนี้คือในบทความ SQL แมวเมื่อจะทำลายลงแบบสอบถามที่ซับซ้อน
ในบางสถานการณ์ SQL Server จะใช้สปูลเพื่อแคชผลลัพธ์ระดับกลางเช่น CTE และหลีกเลี่ยงการประเมินทรีย่อยนั้นอีกครั้ง นี้จะกล่าวถึงใน (อพยพ) รายการ Connect ให้คำแนะนำที่จะบังคับให้เป็นตัวเป็นตนกลาง CTEs หรือตารางที่ได้มา อย่างไรก็ตามไม่มีการสร้างสถิติในเรื่องนี้และแม้ว่าจำนวนของสปูลจะแตกต่างกันอย่างมากจากที่ประเมินโดยประมาณเป็นไปไม่ได้สำหรับแผนการดำเนินการที่กำลังดำเนินการเพื่อปรับแบบไดนามิกในการตอบสนอง (อย่างน้อยในรุ่นปัจจุบัน) อนาคต).
CTE มีการใช้งาน - เมื่อข้อมูลใน CTE มีขนาดเล็กและมีการปรับปรุงการอ่านที่แข็งแกร่งเช่นเดียวกับกรณีในตารางแบบเรียกซ้ำ อย่างไรก็ตามประสิทธิภาพของมันไม่ได้ดีไปกว่าตัวแปรของตารางและเมื่อมีการจัดการกับตารางที่มีขนาดใหญ่มากตารางชั่วคราวจะมีประสิทธิภาพสูงกว่า CTE นี่เป็นเพราะคุณไม่สามารถกำหนดดัชนีใน CTE และเมื่อคุณมีข้อมูลจำนวนมากที่ต้องเข้าร่วมกับตารางอื่น (CTE ก็เหมือนมาโคร) หากคุณกำลังเข้าร่วมหลายตารางพร้อมกับมีแถวเรกคอร์ดนับล้านแถวในแต่ละ CTE จะทำงานได้แย่กว่าตารางชั่วคราวอย่างมาก
ตารางชั่วคราวจะอยู่ในดิสก์เสมอดังนั้นตราบใดที่ CTE ของคุณสามารถเก็บไว้ในหน่วยความจำได้ก็จะเร็วขึ้น (เช่นตัวแปรตารางด้วย)
แต่แล้วอีกครั้งหากการโหลดข้อมูลของ CTE ของคุณ (หรือตัวแปร temp table) มีขนาดใหญ่เกินไปมันจะถูกเก็บไว้ในดิสก์ด้วยดังนั้นจึงไม่มีประโยชน์มากนัก
โดยทั่วไปแล้วฉันชอบ CTE มากกว่าตารางชั่วคราวเนื่องจากมันหายไปหลังจากที่ฉันใช้มัน ฉันไม่จำเป็นต้องคิดว่าจะทิ้งมันไว้อย่างชัดเจน
ดังนั้นในตอนท้ายไม่มีคำตอบที่ชัดเจน แต่โดยส่วนตัวแล้วฉันต้องการ CTE มากกว่าตารางชั่วคราว
ดังนั้นแบบสอบถามที่ฉันได้รับมอบหมายให้เพิ่มประสิทธิภาพจึงถูกเขียนด้วย CTE สองตัวในเซิร์ฟเวอร์ SQL มันใช้เวลา 28 วินาที
ฉันใช้เวลาสองนาทีในการแปลงให้เป็นตารางชั่วคราวและคิวรีใช้เวลา 3 วินาที
ฉันเพิ่มดัชนีลงในตารางอุณหภูมิบนสนามที่มันถูกเข้าร่วมและทำให้มันลดลงเป็น 2 วินาที
สามนาทีของการทำงานและตอนนี้มันทำงานได้เร็วขึ้น 12x ทั้งหมดโดยการลบ CTE ฉันเองจะไม่ใช้ CTE เลยเพราะพวกเขาจะยากขึ้นในการดีบักเช่นกัน
สิ่งที่บ้าคือ CTE ทั้งคู่ใช้เพียงครั้งเดียวและยังคงวางดัชนีที่พวกเขาพิสูจน์แล้วว่าเป็น 50% เร็วขึ้น
CTE จะไม่ใช้พื้นที่ทางกายภาพใด ๆ มันเป็นเพียงชุดผลลัพธ์ที่เราสามารถใช้เข้าร่วมได้
ตารางชั่วคราวนั้นชั่วคราว เราสามารถสร้างดัชนีข้อ จำกัด เช่นเดียวกับตารางปกติที่เราต้องกำหนดตัวแปรทั้งหมด
ขอบเขตของตารางชั่วคราวเท่านั้นภายในเซสชัน เช่นเปิดหน้าต่างแบบสอบถาม SQL สองหน้าต่าง
create table #temp(empid int,empname varchar)
insert into #temp
select 101,'xxx'
select * from #temp
เรียกใช้แบบสอบถามนี้ในหน้าต่างแรกแล้วเรียกใช้แบบสอบถามด้านล่างในหน้าต่างที่สองคุณสามารถค้นหาความแตกต่าง
select * from #temp
ฉันใช้ทั้งสองอย่าง แต่ในขั้นตอนที่ซับซ้อนขนาดใหญ่มักจะพบว่ามีตารางอุณหภูมิที่ดีกว่าในการทำงานและมีระเบียบมากกว่า CTE มีการใช้งาน แต่โดยทั่วไปจะมีข้อมูลขนาดเล็ก
ตัวอย่างเช่นฉันได้สร้าง sprocs ที่กลับมาพร้อมกับผลลัพธ์ของการคำนวณขนาดใหญ่ใน 15 วินาที แต่แปลงรหัสนี้ให้ทำงานใน CTE และได้เห็นมันทำงานเกิน 8 นาทีเพื่อให้ได้ผลลัพธ์เดียวกัน
ไปงานเลี้ยงสาย แต่ ...
สภาพแวดล้อมที่ฉันทำงานมีข้อ จำกัด อย่างมากสนับสนุนผลิตภัณฑ์ของผู้ขายบางรายและให้บริการ "เพิ่มมูลค่า" เช่นการรายงาน เนื่องจากข้อ จำกัด ของนโยบายและสัญญาฉันไม่ได้รับอนุญาตให้ใช้ความหรูหราของพื้นที่ตาราง / ข้อมูลแยกต่างหากและ / หรือความสามารถในการสร้างรหัสถาวร [จะดีขึ้นเล็กน้อยขึ้นอยู่กับแอปพลิเคชัน]
IOW ฉันไม่สามารถพัฒนาโพรซีเดอร์ที่เก็บไว้หรือ UDFs หรือ temp tables ได้ฉันมักจะทำทุกอย่างผ่านทางแอพพลิเคชั่นของฉัน (Crystal Reports - เพิ่ม / ลิงค์ตารางตั้งค่าข้อที่ w / ใน CR ) หนึ่งความสง่างามในการประหยัดขนาดเล็กคือ Crystal ช่วยให้ฉันใช้คำสั่ง (เช่นเดียวกับ SQL Expressions) บางสิ่งที่ไม่มีประสิทธิภาพผ่านความสามารถในการเพิ่ม / ลิงก์ตารางปกติสามารถทำได้โดยการกำหนดคำสั่ง SQL ฉันใช้ CTE ผ่านสิ่งนั้นและได้ผลลัพธ์ที่ดีมาก "จากระยะไกล" CTEs ยังช่วยในการบำรุงรักษาด้วยรายงานโดยไม่ต้องพัฒนาโค้ดส่งมอบให้ DBA เพื่อคอมไพล์เข้ารหัสโอนย้ายติดตั้งและต้องการการทดสอบหลายระดับ ฉันสามารถทำ CTE ผ่านทางโลคัลอินเตอร์เฟส
ข้อเสียของการใช้ CTEs โดยที่แต่ละรายงานแยกจากกัน แต่ละ CTE ต้องได้รับการปรับปรุงสำหรับแต่ละรายงาน ที่ฉันสามารถทำ SP และ UDF ได้ฉันสามารถพัฒนาบางสิ่งที่สามารถใช้งานได้หลายรายงานโดยต้องการเพียงการเชื่อมโยงไปยัง SP และพารามิเตอร์ส่งผ่านราวกับว่าคุณกำลังทำงานบนตารางปกติ CR ไม่ดีพอในการจัดการพารามิเตอร์ในคำสั่ง SQL ดังนั้นมุมมองของด้าน CR / CTE อาจขาดได้ ในกรณีเหล่านั้นฉันมักจะพยายามกำหนด CTE เพื่อส่งคืนข้อมูลที่เพียงพอ (แต่ไม่ใช่ข้อมูลทั้งหมด) จากนั้นใช้ความสามารถในการเลือกเรคคอร์ดใน CR เพื่อเชือดและลูกเต๋า
ดังนั้น ... การลงคะแนนของฉันสำหรับ CTE (จนกว่าฉันจะได้รับพื้นที่ข้อมูลของฉัน)
หนึ่งในการใช้งานที่ฉันพบว่าประสิทธิภาพที่ยอดเยี่ยมของ CTE คือที่ที่ฉันต้องการเข้าร่วม Query ที่ค่อนข้างซับซ้อนบนบางตารางที่มีสองสามล้านแถว
ฉันใช้ CTE เพื่อเลือกชุดย่อยตามคอลัมน์ที่มีการจัดทำดัชนีก่อนเพื่อตัดตารางเหล่านี้ลงไปที่แถวที่เกี่ยวข้องสองสามพันแถวก่อนจากนั้นจึงเข้าร่วม CTE กับแบบสอบถามหลักของฉัน สิ่งนี้ช่วยลดการใช้งานแบบสอบถามของฉันแบบทวีคูณ
ในขณะที่ผลลัพธ์สำหรับ CTE ไม่ได้ถูกแคชและตัวแปรตารางอาจเป็นตัวเลือกที่ดีกว่าฉันแค่อยากลองพวกเขาและพบว่าเหมาะสมกับสถานการณ์ข้างต้น
นี่เป็นคำถามที่สิ้นสุดจริง ๆ แล้วขึ้นอยู่กับการใช้งานและประเภทของตาราง temp (ตัวแปร Table หรือตารางดั้งเดิม)
ตาราง temp ดั้งเดิมเก็บข้อมูลใน temp DB ซึ่งจะทำให้ตาราง temp ช้าลง อย่างไรก็ตามตัวแปรตารางไม่
ฉันเพิ่งทดสอบสิ่งนี้ - ทั้ง CTE และไม่ใช่ CTE (ซึ่งพิมพ์ข้อความค้นหาสำหรับทุก ๆ อินสแตนซ์สหภาพ) ทั้งคู่ใช้เวลา ~ 31 วินาที CTE สร้างโค้ดที่อ่านได้ง่ายขึ้นมาก แต่ลดมันลงจาก 241 เป็น 130 บรรทัดซึ่งดีมาก ตารางชั่วคราวในอีกทางหนึ่งตัดมันลงไปที่ 132 สายและใช้เวลาห้าวินาทีในการทำงาน ไม่ตลก. การทดสอบทั้งหมดนี้ถูกแคชไว้คิวรีทั้งหมดจะทำงานหลายครั้งก่อนหน้านี้
จากประสบการณ์ของฉันใน SQL Server ฉันพบหนึ่งในสถานการณ์ที่ CTE มีประสิทธิภาพสูงกว่าตาราง Temp
ฉันจำเป็นต้องใช้ชุดข้อมูล (~ 100000) จากแบบสอบถามที่ซับซ้อนเพียงครั้งเดียวในขั้นตอนการจัดเก็บของฉัน
ตารางชั่วคราวก่อให้เกิดโอเวอร์เฮดบน SQL ที่โพรซีเดอร์ของฉันทำงานช้าลง (เนื่องจาก Temp Tables เป็นตาราง materialized จริงที่มีอยู่ใน tempdb และคงอยู่ตลอดชีวิตของโพรซีเดอร์ปัจจุบันของฉัน)
ในทางตรงกันข้ามกับ CTE, CTE Persist เท่านั้นจนกว่าแบบสอบถามต่อไปนี้จะทำงาน ดังนั้น CTE จึงเป็นโครงสร้างหน่วยความจำในตัวเครื่องที่มีขอบเขต จำกัด CTE ไม่ได้ใช้ tempdb เป็นค่าเริ่มต้น
นี่เป็นสถานการณ์จำลองหนึ่งที่ CTE สามารถช่วยให้โค้ดของคุณง่ายขึ้นและตารางอุณหภูมิที่ดีกว่า ฉันใช้ CTE 2 อันแล้วก็เป็นอย่างนั้น
WITH CTE1(ID, Name, Display)
AS (SELECT ID,Name,Display from Table1 where <Some Condition>),
CTE2(ID,Name,<col3>) AS (SELECT ID, Name,<> FROM CTE1 INNER JOIN Table2 <Some Condition>)
SELECT CTE2.ID,CTE2.<col3>
FROM CTE2
GO