ประสิทธิภาพของ EXISTS เทียบกับ JOIN
เลือกรูปแบบที่เร็วกว่า
ประสิทธิภาพของ EXISTS เทียบกับ JOIN เป็นบทเรียน SQL Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน SQL Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส SQL Academy มีบทเรียนทั้งหมด 4 บทเรียน
เหตุใดประสิทธิภาพจึงสำคัญในกรณีนี้
เมื่อต้องตรวจสอบว่าแถวที่เกี่ยวข้องมีอยู่ในอีกตารางหนึ่งหรือไม่ SQL มีเครื่องมือให้เลือกหลายอย่าง ได้แก่ EXISTS, IN และ JOIN แต่ละแบบให้ผลลัพธ์ที่ถูกต้องได้เหมือนกัน ทว่าประสิทธิภาพอาจแตกต่างกันมาก โดยขึ้นอยู่กับขนาดข้อมูล ดัชนี และกลไกฐานข้อมูลของคุณ
ในบทเรียนนี้ คุณจะได้เรียนรู้ว่าแต่ละแนวทางทำงานเบื้องหลังอย่างไร และควรเลือกใช้แนวทางใดเมื่อใด
ตารางตัวอย่าง
เราจะใช้สองตารางตลอดบทเรียนนี้ ได้แก่ customers และ orders ลูกค้าหนึ่งรายอาจมีคำสั่งซื้อเป็นศูนย์รายการหรือหลายรายการ นี่คือความสัมพันธ์แบบหนึ่งต่อหลายที่พบได้ทั่วไป ซึ่งเหมาะอย่างยิ่งสำหรับทดสอบรูปแบบการใช้ EXISTS เทียบกับ JOIN
CREATE TABLE customers (
id SERIAL PRIMARY KEY,
name VARCHAR(100)
);
CREATE TABLE orders (
id SERIAL PRIMARY KEY,
customer_id INT REFERENCES customers(id),
total NUMERIC(10,2)
);
INSERT INTO customers (name) VALUES
('Alice'), ('Bob'), ('Carol'), ('Dave');
INSERT INTO orders (customer_id, total) VALUES
(1, 120.00), (1, 85.50), (3, 200.00);แนวทางใช้ JOIN
รูปแบบที่ใช้กันทั่วไปคือการใช้ INNER JOIN เพื่อค้นหาลูกค้าที่มีคำสั่งซื้ออย่างน้อยหนึ่งรายการ วิธีนี้ใช้ได้ แต่สังเกตปัญหาให้ดี หากลูกค้ามีคำสั่งซื้อห้ารายการ ลูกค้ารายนั้นจะปรากฏห้าครั้งในชุดผลลัพธ์ก่อนที่ DISTINCT จะรวมแถวที่ซ้ำกัน
การซ้ำดังกล่าวเป็นงานส่วนเกินที่ฐานข้อมูลต้องดำเนินการ นั่นคือสร้างผลลัพธ์การเชื่อมทั้งหมด แล้วจึงตัดรายการซ้ำ
SELECT DISTINCT c.id, c.name
FROM customers c
INNER JOIN orders o ON o.customer_id = c.id;แนวทางใช้ EXISTS
EXISTS ใช้ตอบคำถามแบบใช่หรือไม่ใช่: มีแถวที่ตรงกันอย่างน้อยหนึ่งแถวหรือไม่ ทันทีที่กลไกพบรายการที่ตรงกันรายการแรก ก็จะหยุดสแกน การทำงานนี้เรียกว่า การประเมินแบบลัดวงจร
ไม่มีการสร้างแถวซ้ำ และไม่จำเป็นต้องใช้ DISTINCT เพราะ EXISTS ไม่ได้ส่งคืนแถวภายในจริง ๆ
SELECT c.id, c.name
FROM customers c
WHERE EXISTS (
SELECT 1
FROM orders o
WHERE o.customer_id = c.id
);การประเมินแบบลัดวงจรคือหัวใจสำคัญ
การประเมินแบบลัดวงจรหมายถึงแบบสอบถามย่อยจะหยุดทันทีที่พบแถวที่ผ่านเงื่อนไขหนึ่งแถว ไม่ว่าลูกค้าจะมีคำสั่งซื้อ 1 รายการหรือ 10,000 รายการ EXISTS จะอ่านจนพบรายการแรกเท่านั้น
JOIN ต้องอ่านแถวที่ตรงกันทั้งหมดเพื่อสร้างชุดผลลัพธ์ แม้ว่าคุณจะสนใจเพียงการมีอยู่ของแถวก็ตาม สำหรับตารางที่มีคอลัมน์จำนวนมากและมีแถวลูกต่อแถวแม่จำนวนมาก ความแตกต่างนี้จะทวีขึ้นอย่างรวดเร็ว
-- EXISTS stops after finding row #1
SELECT c.name
FROM customers c
WHERE EXISTS (
SELECT 1 -- 'SELECT 1' is conventional; the value does not matter
FROM orders o
WHERE o.customer_id = c.id
);
-- JOIN scans ALL matching order rows
SELECT DISTINCT c.name
FROM customers c
INNER JOIN orders o ON o.customer_id = c.id;NOT EXISTS เทียบกับ LEFT JOIN ... IS NULL
สำหรับการตรวจสอบตรงข้าม — การค้นหาลูกค้าที่ไม่มีคำสั่งซื้อ — คุณสามารถใช้ NOT EXISTS หรือรูปแบบ LEFT JOIN ... WHERE IS NULL ได้ ทั้งสองรูปแบบใช้กันทั่วไป แต่ NOT EXISTS มักอ่านเข้าใจง่ายกว่า และเครื่องมือปรับคำสั่งให้เหมาะสมก็มักเลือกใช้รูปแบบนี้
-- NOT EXISTS
SELECT c.id, c.name
FROM customers c
WHERE NOT EXISTS (
SELECT 1
FROM orders o
WHERE o.customer_id = c.id
);
-- LEFT JOIN ... IS NULL (equivalent result)
SELECT c.id, c.name
FROM customers c
LEFT JOIN orders o ON o.customer_id = c.id
WHERE o.id IS NULL;บทบาทของดัชนี
ทั้ง EXISTS และ JOIN ได้ประโยชน์อย่างมากจากดัชนีบนคอลัมน์คีย์นอก หากไม่มีดัชนีบน orders.customer_id ทุกแถวภายนอกจะทำให้เกิดการสแกนตาราง orders ทั้งหมด
การเพิ่มดัชนีดังกล่าวมักเป็นการเพิ่มประสิทธิภาพครั้งใหญ่ที่สุด และส่งผลมากกว่าการเลือกใช้ EXISTS หรือ JOIN
-- Create an index on the foreign key
CREATE INDEX idx_orders_customer_id ON orders(customer_id);
-- Now both patterns use an index lookup instead of a full scan
EXPLAIN
SELECT c.name
FROM customers c
WHERE EXISTS (
SELECT 1 FROM orders o
WHERE o.customer_id = c.id
);การอ่านผลลัพธ์ของ EXPLAIN
ใช้ EXPLAIN (หรือ EXPLAIN ANALYZE เพื่อเรียกใช้คำสั่งสอบถามด้วย) เพื่อดูว่าฐานข้อมูลดำเนินการกับคำสั่งสอบถามอย่างไร ให้มองหาจุดสังเกตต่อไปนี้:
- การสแกนด้วยดัชนี — ดี แสดงว่ามีการใช้ดัชนี
- การสแกนตามลำดับบนตารางขนาดใหญ่ — อาจเป็นสัญญาณเตือน ดัชนีอาจช่วยได้
- การเชื่อมแบบแฮช / การวนซ้อน — อัลกอริทึมการเชื่อมที่เลือกใช้ โดยการวนซ้อนทำงานได้ดีกับการสแกนด้วยดัชนี
EXPLAIN ANALYZE
SELECT c.name
FROM customers c
INNER JOIN orders o ON o.customer_id = c.id
GROUP BY c.id, c.name
HAVING COUNT(o.id) > 0;เมื่อ JOIN เหนือกว่า
EXISTS โดดเด่นในการตรวจสอบการมีอยู่เพียงอย่างเดียว แต่หากคุณต้องการข้อมูลจากตารางที่เกี่ยวข้องด้วย เช่น ยอดรวมคำสั่งซื้อหรือวันที่สั่งซื้อ คุณต้องใช้ JOIN ไม่มีวิธีส่งคืนคอลัมน์จากภายในแบบสอบถามย่อยของ EXISTS
เลือกเครื่องมือให้เหมาะกับคำถาม: EXISTS สำหรับ "มีอยู่หรือไม่" และ JOIN สำหรับ "ส่งข้อมูลจากทั้งสองตารางให้ฉัน"
-- Need order data? JOIN is the only option.
SELECT c.name, o.total, o.id AS order_id
FROM customers c
INNER JOIN orders o ON o.customer_id = c.id
ORDER BY c.name;IN เทียบกับ EXISTS สำหรับชุดข้อมูลขนาดใหญ่
IN (subquery) จะประเมินแบบสอบถามย่อยทั้งหมดก่อน สร้างรายการค่าในหน่วยความจำ แล้วตรวจสอบแต่ละแถวภายนอกกับรายการนั้น เมื่อมีหลายล้านแถว รายการนี้อาจใช้หน่วยความจำจนหมดได้
EXISTS จะถูกประเมินทีละแถวและหยุดทันทีที่พบผลลัพธ์ จึงไม่ต้องสร้างผลลัพธ์ด้านในทั้งหมดไว้ในหน่วยความจำ สำหรับการตรวจสอบแบบสัมพันธ์ขนาดใหญ่ EXISTS มักเร็วกว่า IN เกือบเสมอ
-- IN builds the full list first
SELECT name
FROM customers
WHERE id IN (
SELECT customer_id FROM orders
);
-- EXISTS evaluates per-row and short-circuits
SELECT name
FROM customers c
WHERE EXISTS (
SELECT 1 FROM orders o
WHERE o.customer_id = c.id
);สรุปช่วยตัดสินใจ
ต่อไปนี้คือข้อมูลอ้างอิงแบบย่อสำหรับเลือกวิธีที่เหมาะสม:
- EXISTS — คุณต้องการทราบเพียงว่ามีรายการที่ตรงกันหรือไม่ ใช้กับตารางลูกขนาดใหญ่ และใช้ NOT EXISTS สำหรับการเชื่อมแบบปฏิเสธ
- JOIN — คุณต้องการคอลัมน์จากตารางที่เกี่ยวข้อง หรือ ต้องการรวมค่าข้ามทั้งสองตาราง
- IN — ใช้กับรายการค่าคงที่สั้น ๆ (
WHERE status IN ('active', 'pending')) และหลีกเลี่ยงการใช้กับแบบสอบถามย่อยขนาดใหญ่ - ทำดัชนีเสมอ ให้คอลัมน์คีย์ต่างประเทศ — เรื่องนี้สำคัญกว่าการเลือกไวยากรณ์
ตรวจสอบความเข้าใจ
ข้อใดอธิบายได้ดีที่สุดว่าเหตุใด EXISTS จึงอาจเร็วกว่า INNER JOIN + DISTINCT เมื่อตรวจสอบว่ามีแถวที่เกี่ยวข้องอยู่หรือไม่
สรุปบทเรียน
ในบทนี้ คุณได้เรียนรู้วิธีเลือกระหว่าง EXISTS และ JOIN เพื่อประสิทธิภาพของเอสคิวแอล:
- EXISTS หยุดตรวจสอบทันที — จะหยุดสแกนทันทีที่พบรายการแรกที่ตรงกัน จึงหลีกเลี่ยงแถวซ้ำได้โดยไม่ต้องใช้ DISTINCT
- JOIN ส่งคืนแถวที่ตรงกันทั้งหมด — ใช้เมื่อต้องการข้อมูลจากตารางที่เกี่ยวข้อง แต่เพิ่ม DISTINCT หรือ GROUP BY หากคุณสนใจเฉพาะแถวแม่
- NOT EXISTS เป็นรูปแบบการเชื่อมแบบปฏิเสธที่กระชับ ส่วน LEFT JOIN ... IS NULL ให้ผลเทียบเท่ากันแต่เขียนยืดยาวกว่า
- หลีกเลี่ยงการใช้ IN กับแบบสอบถามย่อยขนาดใหญ่ — จะสร้างผลลัพธ์ด้านในทั้งหมดไว้ในหน่วยความจำ ส่วน EXISTS ใช้หน่วยความจำได้มีประสิทธิภาพกว่า
- ทำดัชนีให้คีย์ต่างประเทศ — ขั้นตอนเดียวนี้มักเพิ่มประสิทธิภาพได้มากที่สุด ไม่ว่าคุณจะเลือกใช้ไวยากรณ์ใด
- ใช้ EXPLAIN / EXPLAIN ANALYZE เพื่อตรวจสอบแผนการทำงานและยืนยันว่ามีการใช้ดัชนี
เรียนรู้ SQL ด้วย AI tutor — ฟรี
เขียนและเรียกใช้โค้ดจริงในเบราว์เซอร์ของคุณ รับความช่วยเหลือทันทีจาก AI tutor 24/7 และเรียนรู้ต่อจากที่คุณหยุดบนเว็บหรือในแอป
- คอร์ส
- 46
- บทเรียน
- 183
คำถามที่พบบ่อย
บทเรียน “ประสิทธิภาพของ EXISTS เทียบกับ JOIN” ฟรีหรือไม่
ใช่ — ข้อความเต็มของ “ประสิทธิภาพของ EXISTS เทียบกับ JOIN” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส SQL Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส SQL Academy มีบทเรียนทั้งหมด 4 บทเรียน
คุณจะเรียนรู้อะไรในบทเรียน “ประสิทธิภาพของ EXISTS เทียบกับ JOIN”
เลือกรูปแบบที่เร็วกว่า คุณปฏิบัติ SQL Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน
คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน SQL Academy หรือไม่
ไม่จำเป็นต้องมีประสบการณ์มาก่อน SQL Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน
บทเรียน “ประสิทธิภาพของ EXISTS เทียบกับ JOIN” ใช้เวลานานแค่ไหน
บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย
ฉันเขียนและรันโค้ดในบทเรียน SQL Academy นี้ได้ไหม
ได้ บทเรียน SQL Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- คำค้นย่อยที่สัมพันธ์กัน
- EXISTS และ NOT EXISTS
- IN เทียบกับ ANY เทียบกับ ALL
- ประสิทธิภาพของ EXISTS เทียบกับ JOIN