Common Table Expression (CTE) มีประโยชน์อย่างไร?


21

จากmsdn :

ต่างจากตารางที่ได้รับ CTE สามารถอ้างอิงตนเองและสามารถอ้างอิงได้หลายครั้งในแบบสอบถามเดียวกัน

ฉันใช้ CTE ค่อนข้างมาก แต่ฉันไม่เคยคิดอย่างถี่ถ้วนเกี่ยวกับประโยชน์ของการใช้มัน

ถ้าฉันอ้างอิง CTE หลายครั้งในแบบสอบถามเดียวกัน:

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

2
Profiler ควรบอกคุณว่าจะสแกนสองครั้งหรือไม่ IMHO, CTE นั้นยอดเยี่ยมสำหรับการเรียกซ้ำ
Dan Andrews

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

คำตอบ:


25

ตามกฎCTE จะไม่ปรับปรุงประสิทธิภาพการทำงาน

CTE นั้นเป็นมุมมองแบบใช้แล้วทิ้ง ไม่มีสถิติเพิ่มเติมที่เก็บไว้ไม่มีดัชนี ฯลฯ มันทำหน้าที่เป็นชวเลขสำหรับแบบสอบถามย่อย

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


3
ตกลง. ยกเว้น CTE แบบเรียกซ้ำแล้วพวกเขาก็ช่วยให้อ่านง่าย
gbn

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

2
@a_horse_with_no_name - มันจะเทียบเท่ากับเพียงแค่ทำให้มันเป็นแบบสอบถามย่อย หากมีการใช้ผลลัพธ์มากกว่าหนึ่งครั้งในแบบสอบถามเดียวระบบจะนำกลับมาใช้ใหม่และไม่คำนวณใหม่ หากมีการใช้งานในแบบสอบถามมากกว่าหนึ่งรายการ a CTEเป็นตัวเลือกที่ไม่ถูกต้องเนื่องจากผลลัพธ์จะถูกยกเลิกหลังจากการสืบค้นครั้งแรก
JNK

@JNK: ขอบคุณ ดูเหมือนว่า SQL Server จะทำงานแตกต่างกันที่นี่
a_horse_with_no_name

บางคนพบว่า CTE อ่านได้มากขึ้นในบางสถานการณ์ FWIW stackoverflow.com/a/11170918/32453
rogerdpack

14

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

;WITH Conferences (Conference_id)
AS 
(select  m.Conference_id
FROM mydb.dbo.Conference m 
WHERE client_id = 10
    and Conference_id in 
            (select Conference_id from mydb.dbo.Expense 
            where amount <>0
            and amount is not null)
     )
--select * from Conferences
,MealEaters(NumberMealEaters, Conference_id, AttendeeType)
AS
(Select count(*) as NumberMealEaters, m.Conference_id,  AttendeeType 
from mydb.dbo.attendance ma 
join Conferences m on m.Conference_id = ma.Conference_id
where (ma.meals_consumed>0 or meals_consumed is null)and attended = 1
group by m.Conference_id)
--select * from MealEaters

,Expenses (Conference_id,expense_date, expenseDescription,  RecordIdentifier,amount)
AS
(select Conference_id,max(expense_date) as Expense_date, expenseDescription,  RecordIdentifier,sum(amount) as amount
    FROM
        (SELECT Conference_id,expense_date,  amount, RecordIdentifier
        FROM mydb.dbo.Expense
        WHERE  amount <> 0 
            and Conference_id IN 
            (SELECT  Conference_id
            FROM mydb.dbo.Conferences ) 
        group by Conference_id, RecordIdentifier) a
)
--select * from Expenses
Select m.Conference_id,me.NumberMealEaters, me.AttendeeType, e.expense_date,         e.RecordIdentifier,amount
from Conferences m
join mealeaters me on m.Conference_id = me.Conference_id
join expenses e on e.Conference_id = m.Conference_id

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


1
เพียงรายงานแบบสอบถาม? ระบบที่ฉันทำงานทุกวันมีข้อความค้นหาธุรกรรมที่ซับซ้อน ข้อความค้นหาที่เรารายงานผิดปกติมักจะเป็นคำถามที่เรียบง่ายกว่าของเรา (ยกเว้นข้อความค้นหา CRUD ที่ไม่มีส่วนร่วมที่ไม่สำคัญของหลักสูตร)
Kevin Cathcart

ฉันใช้สิ่งนั้นเป็นตัวอย่างเพราะโดยทั่วไปแล้วมันซับซ้อนที่สุดที่นี่
HLGEM

+1 บางครั้งข้อความค้นหาที่มีเหตุผล (มนุษย์อ่านได้) จะดีกว่าแบบที่มีประสิทธิภาพดีกว่า
oneday เมื่อ

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

0

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

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