PostgreSQL Performance & Query Optimization · บทเรียน

การปรับจำนวนผู้ทำงานและต้นทุนการรวบรวม

ปรับการตั้งค่าผู้ทำงานแบบขนานและต้นทุนต่อทูเพิล เพื่อสร้างสมดุลระหว่างความเร็วที่เพิ่มขึ้นกับค่าใช้จ่าย

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

การปรับจำนวนผู้ทำงานและต้นทุนการรวบรวม เป็นบทเรียน PostgreSQL Performance & Query Optimization ฟรีบน CoddyKit นี่คือบทเรียนที่ 2 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน PostgreSQL Performance & Query Optimization และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส PostgreSQL Performance & Query Optimization มีบทเรียนทั้งหมด 4 บทเรียน

เหตุใดแบบสอบถามแบบขนานจึงต้องปรับแต่ง

PostgreSQL สามารถแบ่งแบบสอบถามเดียวให้ทำงานบนแกนประมวลผลหลายแกนของ CPU ได้โดยใช้ ผู้ปฏิบัติงานแบบขนาน โพรเซสผู้นำจะสร้างโพรเซสผู้ปฏิบัติงานช่วย โดยแต่ละตัวสแกนข้อมูลคนละส่วน แล้วรวมผลลัพธ์กลับมาที่โหนด Gather

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

  • งานที่มีข้อจำกัดด้าน CPU (การสแกนตามลำดับขนาดใหญ่ การรวมผล และการเชื่อมต่อแบบแฮช) ได้ประโยชน์มากที่สุด
  • แบบสอบถามสั้น ๆ ที่ ไวต่อเวลาแฝง มักไม่ได้ประโยชน์

บทเรียนนี้ครอบคลุมตัวเลือกที่กำหนดว่า จะมีผู้ปฏิบัติงานกี่คนและ เมื่อใดตัววางแผนจึงเห็นว่าการทำงานแบบขนานคุ้มค่า

รูปแบบแผน: โหนด Gather และ Partial

แผนแบบขนานมีรูปแบบเฉพาะ ใต้โหนด Gather (หรือ Gather Merge) จะเป็นการดำเนินการแบบ บางส่วน ที่ผู้ปฏิบัติงานทำพร้อมกัน ส่วนเหนือโหนดนั้นทั้งหมดจะทำงานแบบอนุกรมในโพรเซสผู้นำ

อ่านแผนด้วย EXPLAIN (ANALYZE, VERBOSE) และมองหา Workers Planned เทียบกับ Workers Launched หากจำนวนต่างกัน แสดงว่าขณะทำงานจริงระบบไม่มีช่องผู้ปฏิบัติงานว่างเพียงพอ

EXPLAIN (ANALYZE, VERBOSE, BUFFERS)
SELECT count(*)
FROM orders
WHERE order_total > 100;

-- Look for:
--   Gather  (cost=... rows=...)
--     Workers Planned: 2
--     Workers Launched: 2
--     ->  Partial Aggregate
--           ->  Parallel Seq Scan on orders

max_parallel_workers_per_gather

ตัวเลือกสำคัญที่สุดสำหรับแต่ละแบบสอบถามคือ max_parallel_workers_per_gather ซึ่งกำหนดเพดานจำนวนผู้ปฏิบัติงานที่โหนด Gather เดียว สามารถร้องขอได้ ค่าเริ่มต้นคือ 2

การตั้งค่าเป็น 0 จะปิดการทำงานแบบขนานทั้งหมดสำหรับเซสชันนั้น การเพิ่มค่าจะทำให้การสแกนขนาดใหญ่ใช้แกนประมวลผลได้มากขึ้น แต่ยังไม่เกินขีดจำกัดที่ขนาดตารางและปัจจัยอื่นอนุญาต

  • นี่เป็นเพดานต่อ Gather ไม่ใช่เพดานต่อแบบสอบถาม แบบสอบถามที่มีโหนด Gather สองโหนดอาจใช้ผู้ปฏิบัติงานได้สูงสุด 2 เท่าของค่านี้
  • สามารถเปลี่ยนค่าเป็นรายเซสชันด้วย SET ได้ จึงปรับแต่งรายงานหนัก ๆ เพียงรายการเดียวได้โดยไม่ต้องแก้การตั้งค่าระดับระบบ
-- Inspect current value
SHOW max_parallel_workers_per_gather;

-- Allow up to 4 workers per gather for this session
SET max_parallel_workers_per_gather = 4;

-- Disable parallelism for a latency-critical query
SET max_parallel_workers_per_gather = 0;

งบประมาณผู้ปฏิบัติงานสามชั้น

จำนวนผู้ปฏิบัติงานถูกจำกัดด้วยการตั้งค่าที่ซ้อนกันสามระดับ จำนวนผู้ปฏิบัติงานที่ใช้ได้จริงคือ ค่าต่ำสุดของทั้งสามค่า รวมถึงค่าประเมินตามขนาดของตัววางแผนเอง

  • max_parallel_workers_per_gather — ต่อโหนด Gather (ค่าเริ่มต้น 2)
  • max_parallel_workers — กลุ่มทรัพยากรทั้งคลัสเตอร์สำหรับแบบสอบถามแบบขนานโดยเฉพาะ (ค่าเริ่มต้น 8)
  • max_worker_processes — จำนวนผู้ปฏิบัติงานเบื้องหลังทั้งหมดของเซิร์ฟเวอร์ ใช้ร่วมกับส่วนขยายและการจำลองข้อมูล (ค่าเริ่มต้น 8)

หากเพิ่มเพดานต่อ Gather แต่ยังคงให้ max_parallel_workers ต่ำ แบบสอบถามที่ทำงานพร้อมกันจะแย่งทรัพยากรกัน และหลายรายการจะทำงานด้วย ผู้ปฏิบัติงานน้อยกว่าที่วางแผนไว้

SHOW max_worker_processes;        -- server-wide ceiling
SHOW max_parallel_workers;        -- pool for parallel query
SHOW max_parallel_workers_per_gather;  -- per-gather cap

-- A sane production starting point on an 8-core box:
-- max_worker_processes = 16
-- max_parallel_workers = 8
-- max_parallel_workers_per_gather = 4

ตัววางแผนเลือกจำนวนผู้ปฏิบัติงานเริ่มต้นอย่างไร

แม้กำหนดเพดานไว้สูง ตัววางแผนก็ยังปรับจำนวนผู้ปฏิบัติงานตามขนาดรีเลชันโดยใช้กฎแบบลอการิทึม ตารางต้องมีขนาดอย่างน้อย min_parallel_table_scan_size (ค่าเริ่มต้น 8MB) จึงจะพิจารณาผู้ปฏิบัติงานแบบขนาน โดยประมาณแล้ว ทุกครั้งที่ขนาดเพิ่มขึ้น 3 เท่า จะเพิ่มผู้ปฏิบัติงานอีกหนึ่งคน

  • 8MB เป็น 24MB เป็น 72MB เป็น 216MB... → ผู้ปฏิบัติงาน 1, 2, 3... คน
  • จากนั้นผลลัพธ์จะถูกจำกัดด้วย max_parallel_workers_per_gather

นี่คือเหตุผลที่ตารางขนาดเล็กมากไม่ทำงานแบบขนาน ไม่ว่าคุณจะตั้งเพดานไว้สูงเพียงใด และเป็นเหตุผลที่บางครั้งต้องลดค่า min_parallel_table_scan_size เพื่อลองแผนแบบขนานกับข้อมูลขนาดเล็ก

SHOW min_parallel_table_scan_size;   -- default 8MB
SHOW min_parallel_index_scan_size;   -- default 512kB

-- Force consideration of parallelism on smaller tables (testing)
SET min_parallel_table_scan_size = '0';

parallel_setup_cost: ค่าใช้จ่ายส่วนเกินคงที่

parallel_setup_cost ใช้จำลองค่าใช้จ่ายครั้งเดียวในการเปิดใช้ผู้ปฏิบัติงานและตั้งค่าหน่วยความจำที่ใช้ร่วมกัน ค่าเริ่มต้นคือ 1000 ซึ่งเป็นตัวเลขสูงในหน่วยต้นทุนของตัววางแผน โดยตั้งใจให้ตัวปรับให้เหมาะสมหลีกเลี่ยงการทำงานแบบขนานสำหรับแบบสอบถามที่มีต้นทุนต่ำ

หากฮาร์ดแวร์ของคุณสร้างผู้ปฏิบัติงานได้รวดเร็ว และพบว่าแผนแบบขนานที่ดีถูกปฏิเสธ การลดค่านี้จะทำให้ตัววางแผนเต็มใจใช้การทำงานแบบขนานมากขึ้น ควรเพิ่มค่าเพื่อไม่สนับสนุนการทำงานแบบขนานบนเซิร์ฟเวอร์ OLTP ที่มีภาระสูง

SHOW parallel_setup_cost;   -- default 1000

-- Make the planner more eager to go parallel
SET parallel_setup_cost = 200;

-- Then compare plans
EXPLAIN SELECT count(*) FROM orders WHERE shipped_at IS NULL;

parallel_tuple_cost: ค่าใช้จ่ายในการรวบรวมต่อทูเพิล

parallel_tuple_cost ใช้จำลองค่าใช้จ่ายในการถ่ายโอน ทูเพิลแต่ละรายการจากผู้ปฏิบัติงานกลับไปยังโพรเซสผู้นำผ่านคิวรวบรวม ค่าเริ่มต้นคือ 0.1 ต่อทูเพิล

นี่คือเหตุผลสำคัญที่การทำงานแบบขนานเสียเปรียบในแบบสอบถามที่ส่งคืนหลายแถว เพราะทูเพิลทุกรายการที่ส่งคืนต้องเสียต้นทุน การทำงานแบบขนานจะได้เปรียบเมื่อผู้ปฏิบัติงาน ลดปริมาณข้อมูลลง เช่น กรองข้อมูลอย่างเข้มงวดหรือรวมผล ทำให้มีทูเพิลเพียงไม่กี่รายการผ่าน Gather

  • จำนวนแถวที่ออกจาก Gather สูง + parallel_tuple_cost สูง → ตัววางแผนจะเลือกการทำงานแบบอนุกรม
  • ลดค่านี้อย่างระมัดระวัง หากการถ่ายโอนทูเพิลผ่านหน่วยความจำที่ใช้ร่วมกันมีต้นทุนต่ำจริง
SHOW parallel_tuple_cost;   -- default 0.1

-- A query that aggregates (few tuples cross Gather) loves parallelism;
-- a query that returns millions of raw rows pays parallel_tuple_cost on each.
EXPLAIN
SELECT customer_id, count(*)
FROM orders
GROUP BY customer_id;   -- partial aggregate shrinks data before Gather

การกำหนดเฉพาะตาราง: พารามิเตอร์พื้นที่จัดเก็บ parallel_workers

คุณสามารถกำหนดจำนวนผู้ปฏิบัติงานตายตัวให้ตารางหนึ่ง ๆ ได้ด้วยพารามิเตอร์พื้นที่จัดเก็บ parallel_workers ค่านี้จะแทนที่สูตรตามขนาดของตัววางแผนสำหรับการสแกนตารางนั้น แต่ยังคงถูกจำกัดด้วยเพดานระดับระบบ

มีประโยชน์กับตารางข้อเท็จจริงที่มีการใช้งานสูงและถูกสอบถามด้วยการรวมผลขนาดใหญ่ ซึ่งคุณต้องการผู้ปฏิบัติงาน 6 คนเสมอ ไม่ว่าค่าเริ่มต้นแบบลอการิทึมจะเป็นเท่าใด

-- Pin parallel scans of this table to 6 workers
ALTER TABLE orders SET (parallel_workers = 6);

-- Remove the override, return to size-based defaults
ALTER TABLE orders RESET (parallel_workers);

-- Verify the setting
SELECT reloptions FROM pg_class WHERE relname = 'orders';

วัดจุดที่เหมาะสมที่สุด

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

  • ดู Workers Launched — หากต่ำกว่า Workers Planned แสดงว่ากลุ่มทรัพยากรถูกใช้จนหมด และการเพิ่มเพดานต่อ Gather จะไม่ช่วย
  • ผลตอบแทนลดลง: การเพิ่มจากผู้ปฏิบัติงาน 4 เป็น 8 คนมักให้ผลน้อยกว่าการเพิ่มจาก 1 เป็น 2 คนมาก
SET max_parallel_workers_per_gather = 2;
EXPLAIN (ANALYZE, TIMING OFF) SELECT count(*) FROM orders WHERE order_total > 100;

SET max_parallel_workers_per_gather = 4;
EXPLAIN (ANALYZE, TIMING OFF) SELECT count(*) FROM orders WHERE order_total > 100;

SET max_parallel_workers_per_gather = 8;
EXPLAIN (ANALYZE, TIMING OFF) SELECT count(*) FROM orders WHERE order_total > 100;

การทำงานพร้อมกัน: เมื่อผู้ปฏิบัติงานไม่เพียงพอ

กลุ่มผู้ปฏิบัติงานแบบขนานถูกใช้ร่วมกันทั้งคลัสเตอร์ เมื่อมีงานทำพร้อมกัน แบบสอบถามหลายรายการที่วางแผนไว้รายการละ 4 คนอาจต้องการทรัพยากรรวมเกินกว่าที่ max_parallel_workers อนุญาต ทำให้บางรายการทำงานด้วยผู้ปฏิบัติงานที่ลดลงหรือไม่มีเลย

ในระบบที่มีภาระ OLTP สูง นี่ถือเป็นคุณสมบัติที่ดี เพราะคุณต้องการให้ธุรกรรมสั้น ๆ ได้ใช้ CPU ก่อน ไม่ใช่เสียทรัพยากรให้แบบสอบถามรายงานที่จองผู้ปฏิบัติงาน 8 คน กลยุทธ์มีดังนี้:

  • กำหนด max_parallel_workers_per_gather ระดับส่วนกลางให้พอเหมาะ (2-4)
  • เพิ่มค่าเป็น รายเซสชัน เฉพาะงานประมวลผลเป็นชุดหรือรายงานที่ทราบแน่ชัด
  • ตรวจสอบว่า max_worker_processes สูงพอที่จะเหลือพื้นที่ให้ส่วนขยายและการจำลองข้อมูลด้วย

แนวทางการปรับแต่งที่ใช้งานได้จริง

เมื่อนำทุกอย่างมารวมกันสำหรับงานวิเคราะห์ที่มีข้อจำกัดด้าน CPU บนเซิร์ฟเวอร์ 8 แกน:

  • ตั้งค่า max_worker_processes = 16 (เผื่อไว้สำหรับส่วนขยาย)
  • ตั้งค่า max_parallel_workers = 8 (หนึ่งคนต่อหนึ่งแกน)
  • คงค่า max_parallel_workers_per_gather = 2 ระดับส่วนกลางไว้ เพื่อปกป้องเวลาแฝงของ OLTP
  • สำหรับเซสชันรายงานประจำคืน ให้ใช้ SET max_parallel_workers_per_gather = 6
  • ลด parallel_setup_cost / parallel_tuple_cost หลังจาก EXPLAIN ANALYZE พิสูจน์แล้วเท่านั้นว่าแผนที่ดีถูกปฏิเสธ

ตรวจสอบด้วยเวลาจริงเสมอ และกำหนดจำนวนต่อ table แบบตายตัวเฉพาะกับตารางที่มีการใช้งานสูงและมีพฤติกรรมคงที่ซึ่งเข้าใจเป็นอย่างดี

-- Per-session profile for a heavy nightly aggregation job
SET max_parallel_workers_per_gather = 6;
SET parallel_setup_cost = 200;
SET min_parallel_table_scan_size = '4MB';

EXPLAIN (ANALYZE, BUFFERS)
SELECT region, date_trunc('day', created_at) AS d, sum(amount)
FROM sales
GROUP BY region, d;

ตรวจสอบอย่างรวดเร็ว: วินิจฉัยผู้ปฏิบัติงานที่ขาดแคลน

คุณเรียกใช้แบบสอบถามรวมผลที่มีภาระสูง EXPLAIN ANALYZE แสดง Workers Planned: 4 แต่มี Workers Launched: 1 และการทำงานเร็วกว่าแบบอนุกรมเพียงเล็กน้อย การเปลี่ยนแปลงเพียงข้อใดมีแนวโน้มแก้ปัญหาผู้ปฏิบัติงานที่ขาดแคลนได้มากที่สุด

สรุปทบทวน: สร้างสมดุลระหว่างความเร็วที่เพิ่มขึ้นกับค่าใช้จ่ายส่วนเกิน

ขณะนี้คุณมีกรอบความคิดสำหรับการปรับแต่งแบบสอบถามแบบขนานแล้ว:

  • งบประมาณผู้ปฏิบัติงานมีหลายชั้น: max_parallel_workers_per_gather ≤ max_parallel_workers ≤ max_worker_processes และยังถูกปรับตามขนาดตารางเพิ่มเติม
  • ต้นทุนเป็นตัวตัดสินใจ: parallel_setup_cost คือค่าธรรมเนียมคงที่ในการเปิดใช้ผู้ปฏิบัติงาน ส่วน parallel_tuple_cost คือค่าธรรมเนียมสำหรับทุกทูเพิลที่ผ่าน Gather ดังนั้นการทำงานแบบขนานจะได้เปรียบเมื่อผู้ปฏิบัติงานลดปริมาณข้อมูลลง
  • การอ่านแผนเป็นสิ่งจำเป็น: เปรียบเทียบ Workers Planned กับ Workers Launched เพื่อแยกปัญหาจากการวางแผนออกจากปัญหากลุ่มทรัพยากรขณะทำงาน
  • ปรับแต่งเป็นรายเซสชัน ไม่ใช่ระดับส่วนกลาง เพื่อปกป้องเวลาแฝงของ OLTP พร้อมเปิดโอกาสให้งานประมวลผลเป็นชุดใช้แกนประมวลผลได้

วัดผลด้วย EXPLAIN ANALYZE และเวลาจริง อย่าเชื่อต้นทุนของตัววางแผนเพียงอย่างเดียว

เริ่มต้นได้ฟรี

เรียนรู้ SQL ด้วย AI tutor — ฟรี

เขียนและเรียกใช้โค้ดจริงในเบราว์เซอร์ของคุณ รับความช่วยเหลือทันทีจาก AI tutor 24/7 และเรียนรู้ต่อจากที่คุณหยุดบนเว็บหรือในแอป

คอร์ส
22
บทเรียน
88

คำถามที่พบบ่อย

บทเรียน “การปรับจำนวนผู้ทำงานและต้นทุนการรวบรวม” ฟรีหรือไม่

ใช่ — ข้อความเต็มของ “การปรับจำนวนผู้ทำงานและต้นทุนการรวบรวม” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส PostgreSQL Performance & Query Optimization ให้อัปเกรดเป็น CoddyKit PRO คอร์ส PostgreSQL Performance & Query Optimization มีบทเรียนทั้งหมด 4 บทเรียน

คุณจะเรียนรู้อะไรในบทเรียน “การปรับจำนวนผู้ทำงานและต้นทุนการรวบรวม”

ปรับการตั้งค่าผู้ทำงานแบบขนานและต้นทุนต่อทูเพิล เพื่อสร้างสมดุลระหว่างความเร็วที่เพิ่มขึ้นกับค่าใช้จ่าย คุณปฏิบัติ PostgreSQL Performance & Query Optimization ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน

คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน PostgreSQL Performance & Query Optimization หรือไม่

ไม่จำเป็นต้องมีประสบการณ์มาก่อน PostgreSQL Performance & Query Optimization บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 2 จากทั้งหมด 4 บทเรียน

บทเรียน “การปรับจำนวนผู้ทำงานและต้นทุนการรวบรวม” ใช้เวลานานแค่ไหน

บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย

ฉันเขียนและรันโค้ดในบทเรียน PostgreSQL Performance & Query Optimization นี้ได้ไหม

ได้ บทเรียน PostgreSQL Performance & Query Optimization ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

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

  1. เมื่อตัววางแผนเลือกแผนแบบขนาน
  2. การปรับจำนวนผู้ทำงานและต้นทุนการรวบรวม
  3. การรวมข้อมูลแบบขนานและการเชื่อมโยงแบบแฮช
  4. การวินิจฉัยสาเหตุที่ปิดการทำงานแบบขนาน
← กลับไปที่ PostgreSQL Performance & Query Optimization