คำตอบอื่น ๆ ครอบคลุมถึงความแตกต่างของไวยากรณ์ค่อนข้างดีดังนั้นฉันจะไม่พูดเรื่องนั้น คำตอบนี้จะครอบคลุมถึงประสิทธิภาพใน Oracle
เครื่องมือเพิ่มประสิทธิภาพ Oracle อาจเลือกให้ผลลัพธ์ของ CTE เป็นจริงในตารางชั่วคราวภายใน มันใช้ฮิวริสติกในการทำเช่นนี้แทนการปรับให้เหมาะสมกับต้นทุน ฮิวริสติกคือ "การทำให้เป็นรูปธรรมของ CTE หากไม่ใช่นิพจน์ที่ไม่สำคัญและ CTE นั้นถูกอ้างอิงมากกว่าหนึ่งครั้งในการสืบค้น" มีข้อซักถามบางประการที่การทำให้เป็นรูปธรรมจะปรับปรุงประสิทธิภาพเป็น มีคำถามบางอย่างที่ทำให้เป็นรูปเป็นร่างจะลดประสิทธิภาพลงอย่างมาก ตัวอย่างต่อไปนี้เป็นบิตที่วางแผนไว้ แต่มันแสดงให้เห็นถึงจุดที่ดี:
ขั้นแรกสร้างตารางด้วยคีย์หลักที่มีจำนวนเต็มตั้งแต่ 1 ถึง 10,000:
CREATE TABLE N_10000 (NUM_ID INTEGER NOT NULL, PRIMARY KEY (NUM_ID));
INSERT /*+APPEND */ INTO N_10000
SELECT LEVEL
FROM DUAL
CONNECT BY LEVEL <= 10000
ORDER BY LEVEL;
COMMIT;
พิจารณาแบบสอบถามต่อไปนี้ที่ใช้สองตารางที่ได้รับ:
SELECT t1.NUM_ID
FROM
(
SELECT n1.NUM_ID
FROM N_10000 n1
CROSS JOIN N_10000 n2
) t1
LEFT OUTER JOIN
(
SELECT n1.NUM_ID
FROM N_10000 n1
CROSS JOIN N_10000 n2
) t2 ON t1.NUM_ID = t2.NUM_ID
WHERE t1.NUM_ID <= 0;
เราสามารถดูคำถามนี้และกำหนดได้อย่างรวดเร็วว่าจะไม่ส่งคืนแถวใด ๆ Oracle ควรจะสามารถใช้ดัชนีเพื่อพิจารณาเช่นกัน ในเครื่องของฉันแบบสอบถามเกือบเสร็จในทันทีด้วยแผนต่อไปนี้:
ฉันไม่ชอบทำซ้ำตัวเองดังนั้นลองทำแบบสอบถามเดียวกันกับ CTE:
WITH N_10000_CTE AS (
SELECT n1.NUM_ID
FROM N_10000 n1
CROSS JOIN N_10000 n2
)
SELECT t1.NUM_ID
FROM N_10000_CTE t1
LEFT JOIN N_10000_CTE t2 ON t1.NUM_ID = t2.NUM_ID
WHERE t1.NUM_ID <= 0;
นี่คือแผน:
นั่นเป็นแผนที่เลวร้ายจริงๆ แทนที่จะใช้ดัชนี Oracle จะกำหนดขนาดของแถวที่ 10,000 X 10,000 = 100000000 ลงในตารางชั่วคราวเท่านั้นในที่สุดก็จะกลับมาเป็น 0 แถว ค่าใช้จ่ายของแผนนี้ประมาณ 6 M ซึ่งสูงกว่าแบบสอบถามอื่น ๆ มาก การสืบค้นใช้เวลา 68 วินาทีในการทำให้เครื่องของฉันเสร็จ
โปรดทราบว่าแบบสอบถามอาจล้มเหลวหากมีหน่วยความจำไม่เพียงพอหรือพื้นที่ว่างในพื้นที่ตารางชั่วคราว
ฉันสามารถใช้INLINE
คำใบ้ที่ไม่มีเอกสารเพื่อไม่อนุญาตให้เครื่องมือเพิ่มประสิทธิภาพจากการทำให้ CTE เป็นจริง:
WITH N_10000_CTE AS (
SELECT /*+ INLINE */ n1.NUM_ID
FROM N_10000 n1
CROSS JOIN N_10000 n2
)
SELECT t1.NUM_ID
FROM N_10000_CTE t1
LEFT JOIN N_10000_CTE t2 ON t1.NUM_ID = t2.NUM_ID
WHERE t1.NUM_ID <= 0;
แบบสอบถามนั้นสามารถใช้ดัชนีและเสร็จสิ้นเกือบจะทันที ค่าใช้จ่ายของการสืบค้นเป็นเหมือนก่อนหน้า 11 ดังนั้นสำหรับการสืบค้นครั้งที่สองการวิเคราะห์พฤติกรรมที่ใช้โดย Oracle ส่งผลให้เกิดการเลือกการสืบค้นด้วยค่าใช้จ่ายโดยประมาณที่ 6 M แทนที่จะเป็นแบบสอบถามที่มีค่าใช้จ่ายประมาณ 11
WITH...
) คุณสามารถเขียนตารางที่ได้รับทั้งหมดเป็น CTE แต่อาจไม่ใช่วิธีอื่น ๆ ในรอบ (เช่น Recursive CTE หรือใช้ CTE ซ้ำหลายครั้ง)