ป้ายกำกับ: Database Architecture

T-SQL Advanced Scripting: การใช้ Cursor, Window Functions และ Stored Procedure บน SQL ServerT-SQL Advanced Scripting: การใช้ Cursor, Window Functions และ Stored Procedure บน SQL Server

ในโลกของการพัฒนาแอปพลิเคชันที่ขับเคลื่อนด้วยข้อมูล (Data-Driven Applications) ความสามารถในการจัดการตรรกะทางธุรกิจที่ซับซ้อนภายในฐานข้อมูลถือเป็นหัวใจสำคัญของระบบ การประมวลผลข้อมูลที่เกินกว่าการ Join ตารางธรรมดา ไม่ว่าจะเป็นการคำนวณลำดับ (Ranking), การเปรียบเทียบค่าในชุดข้อมูลเดียวกัน, หรือการทำงานแบบวนรอบตามเงื่อนไขที่กำหนด ล้วนเป็นความท้าทายที่นักพัฒนาฐานข้อมูลระดับสูงต้องเผชิญ

บทความนี้จะเจาะลึกถึงเครื่องมือขั้นสูงในการเขียนโค้ด PostgreSQL เพื่อให้คุณเข้าใจถึงความแตกต่างและแนวทางการใช้งานที่เหมาะสมที่สุดระหว่าง Window Functions, Stored Procedures (Functions) และ Cursors เพื่อสร้างโค้ดที่มีประสิทธิภาพสูงสุดและมีความเสถียรสูง

1. Window Functions: พลังแห่ง Set-Based Logic

Window Functions คือเครื่องมือที่ทรงพลังที่สุดในการประมวลผลข้อมูลแบบ Set-Based โดยที่ไม่จำเป็นต้องลดจำนวนแถวข้อมูล (Row) เหมือนการใช้ Group By ทั่วไป หน้าที่หลักคือการคำนวณค่ารวม (Aggregate) หรือค่าลำดับ (Ranking) ของแถวข้อมูล โดยอ้างอิงจากชุดของแถวข้อมูลที่เกี่ยวข้อง (Window) โดยไม่ทำให้ข้อมูลต้นฉบับหายไป

ตัวอย่างการใช้งาน (Ranking):

SQL

-- สมมติว่ามีตาราง 'sales' ที่มีคอลัมน์ (product, sale_date, amount)</code>
SELECT
    product,
    sale_date,
    amount,
    ROW_NUMBER() OVER (PARTITION BY product ORDER BY sale_date DESC) AS rank_number
FROM
    sales;

การใช้ `PARTITION BY` ช่วยให้เราสามารถจัดกลุ่มการคำนวณย่อยๆ ได้อย่างแม่นยำ โดยที่ PostgreSQL จะจัดการการคำนวณทั้งหมดในระดับเซิร์ฟเวอร์อย่างมีประสิทธิภาพสูง

2. Stored Procedures / Functions: การห่อหุ้มตรรกะทางธุรกิจ

ใน PostgreSQL เราใช้คำว่า Function (เขียนด้วยภาษา PL/pgSQL) เพื่อห่อหุ้มตรรกะทางธุรกิจที่ซับซ้อน การสร้าง Function ไม่เพียงแต่ช่วยเพิ่มความสามารถในการนำกลับมาใช้ใหม่ (Reusability) เท่านั้น แต่ยังเป็นกลไกสำคัญในการควบคุมการเข้าถึงข้อมูล (Security) และลด Latency ของเครือข่าย เพราะโค้ดจะถูกคอมไพล์และรันบนเซิร์ฟเวอร์โดยตรง

ตัวอย่างการใช้งาน (PL/pgSQL):

SQL

CREATE OR REPLACE FUNCTION calculate_bonus(employee_id INT, salary NUMERIC) RETURNS NUMERIC AS $$
BEGIN
    -- ตรรกะทางธุรกิจ: โบนัส 10% หากเงินเดือนเกิน 50000
    IF salary > 50000 THEN
        RETURN salary * 0.10;
    ELSE
        RETURN 0;
    END IF;
END;$$
LANGUAGE plpgsql;

3. Cursors: การวนลูปแบบ Row-by-Row (เมื่อจำเป็น)

Cursor คือกลไกที่อนุญาตให้เราประมวลผลชุดข้อมูลทีละแถว (Row-by-Row) ซึ่งโดยทั่วไปแล้วควรเป็นทางเลือกสุดท้าย (Last Resort) เนื่องจากเป็นรูปแบบที่ช้ากว่าการใช้ Set-Based Logic อย่างมาก อย่างไรก็ตาม ในบางกรณีที่ตรรกะทางธุรกิจบังคับให้ต้องมีการอัปเดตหรือคำนวณแบบลำดับ (Sequential Dependency) การใช้ Cursor จึงเป็นสิ่งจำเป็น

ข้อควรระวัง: การใช้ Cursor ควรทำเมื่อ Window Functions ไม่สามารถตอบโจทย์ได้เท่านั้น เพราะการวนลูปจะทำให้ประสิทธิภาพของระบบลดลงอย่างมาก

บทสรุป: การเลือกเครื่องมือที่เหมาะสม

ในฐานะ Senior Architect การเลือกเครื่องมือที่เหมาะสมคือหัวใจของการออกแบบระบบฐานข้อมูลที่มีประสิทธิภาพสูงสุด ลำดับความสำคัญในการใช้งานควรเป็นดังนี้:

  1. Window Functions: ใช้เป็นอันดับแรกเสมอ เมื่อต้องการการคำนวณแบบกลุ่มโดยไม่กระทบโครงสร้างข้อมูลต้นฉบับ (Set-Based Logic)
  2. Functions (PL/pgSQL): ใช้เมื่อต้องห่อหุ้มตรรกะทางธุรกิจที่ซับซ้อนและต้องการการควบคุมการเข้าถึงข้อมูล
  3. Cursors: ใช้เป็นทางเลือกสุดท้าย เมื่อตรรกะทางธุรกิจมีความจำเป็นต้องทำงานแบบลำดับ (Procedural/Sequential) จริงๆ

การเข้าใจความแตกต่างเหล่านี้จะช่วยให้คุณสร้างโค้ด PostgreSQL ที่ไม่เพียงแค่ทำงานได้ แต่ยังทำงานได้อย่างรวดเร็วและมีประสิทธิภาพในระดับ Production Environment