SQL Academy · บทเรียน

ประสิทธิภาพของ EXISTS เทียบกับ JOIN

เลือกรูปแบบที่เร็วกว่า

บทเรียน 4 จาก 413 ขั้นตอน

ประสิทธิภาพของ 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 ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. คำค้นย่อยที่สัมพันธ์กัน
  2. EXISTS และ NOT EXISTS
  3. IN เทียบกับ ANY เทียบกับ ALL
  4. ประสิทธิภาพของ EXISTS เทียบกับ JOIN
← กลับไปที่ SQL Academy