จัดการฐานข้อมูลขนาดใหญ่ด้วย Table Partitioning

ฐานข้อมูลขนาดใหญ่มากๆมีเป็นล้านๆแถว ปัญหาคือดูแลยาก จะเพิ่มจะลบวุ่นวายมากสิ่งที่จะมาช่วยเราจัดการเรื่องนี้คือ partition ซึ่งเป็นของใหม่ใน postgres 11

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

การทำ partition  คือการแยกตารางใหญ่เป็นตารางย่อยๆโดยที่ไม่ต้องสร้างตารางขึ้นมาจริงๆ แต่ใช้ระบบ partition เอา ตารางจะมีอยู่ 2 ประเภทคือ master, child ตาราง master คือตารางหลักเราจะแก้ไข ปรับปรุงเปลี่ยนแปลงให้ทำที่ตาราง master  หลังจากนั้นข้อมูลจะไหลไปที่ child โดยอัตโนมัติ เวลาดึงข้อมูลก็จะดึงจาก child โดยอัตโนมัติเช่นเดียวกัน

การสร้างตาราง child จะมีอยู่ด้วยกัน  2 แบบคือ 

1. range partitioning

คือการสร้างโดยให้ช่วงของข้อมูลเป็นตัวกำหนดว่าจะต้องสร้าง child table แบบไหน เช่นเราต้องการแบ่งข้อมูลตามเดือน ดังนั้นเราจะต้องสร้างฐานข้อมูลเพิ่มอีก 12 ตารางต่อการเก็บข้อมูล 1 ปี

2. list partitioning

คือการสร้างตารางโดยให้ความสำคัญของประเภทข้อมูลที่อยู่ด้านในเช่น เราต้องการแยกประเภทตามประเทศของคนที่เราเก็บไว้ เราก็จะต้องสร้างตารางอีก 195 อันเพื่อรองรับข้อมูลประเทศทั้งหมด


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


ภาพจาก https://logicalread.com/partition-tables-sql-server-perf-dn01/#.XVjUB3UvOV4

ตารางสีดำคือตารางเก็บข้อมูลขนาดใหญ่ 10 ล้านแถว แต่เราได้สร้าง partition เอาไว้เพื่อแยกเก็บข้อมูลเหล่านี้ออกจากกัน โดยแบ่งตามเวลา ข้อมูลใน 1 ปีจะถูกแยกเก็บในตาราง 12 ตารางแยกออกจากกันโดยเด็ดขาด ทำให้แทนที่ข้อมูลจะถูกดึงจากตารางใหญ่เพียงอย่างเดียวทำให้ดึงได้ช้า แต่ระบบ partition จะแยกข้อมูลออกจากกันเป็นหลายๆตารางทำให้สามารถดึงข้อมูลได้เร็วกว่าเดิมมาก


แล้วถ้าจะใช้ต้องทำยังไง ตัวอย่างการเขียน sql ของ postgres

CREATE TABLE measurement (
    id         int not null,
    name       string not null,
    date         date not null,

) PARTITION BY RANGE (date); 
ตามตัวอย่างด้านบนเราสร้างตาราง measurement ขึ้นมาเป็นตาราง master จากนั้นเรากำหนดไปว่าให้มีการสร้าง partition โดยแบ่งข้อมูลตามวันเวลาที่เก็บ จากนั้นเราไปสร้างตาราง child ที่เหลือดังนี้

CREATE TABLE measurement_y2006m02 PARTITION OF measurement
    FOR VALUES FROM ('2006-02-01') TO ('2006-03-01');

CREATE TABLE measurement_y2006m03 PARTITION OF measurement
    FOR VALUES FROM ('2006-03-01') TO ('2006-04-01');

...
CREATE TABLE measurement_y2007m11 PARTITION OF measurement
    FOR VALUES FROM ('2007-11-01') TO ('2007-12-01');

CREATE TABLE measurement_y2007m12 PARTITION OF measurement
    FOR VALUES FROM ('2007-12-01') TO ('2008-01-01')
    TABLESPACE fasttablespace;

CREATE TABLE measurement_y2008m01 PARTITION OF measurement
    FOR VALUES FROM ('2008-01-01') TO ('2008-02-01')
    WITH (parallel_workers = 4)
    TABLESPACE fasttablespace;

เราสร้างตาราง child โดยแยกเก็บตามระยะเวลา ดังนั้นใน 1 ปีเราจะเก็บข้อมูลเพิ่มเป็น 12 ตาราง


สรุป

คำถาม เวลาดึงข้อมูลต้องไปดึงจาก child หรือ ยุ่งตายชักเลยมีไม่รู้กี่ตาราง
ตอบ ดึงจากตาราง master อันเดียวเลยไม่ต้องยุ่งกับ child เลย ข้อมูลมันจะดึงมาจาก child เข้าหา master เองเราไม่ต้องไปยุ่งเลย


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


คำถาม มีข้อจำกัดอะไรอีกมั้ย
ตอบ มีเยอะถ้าใช้ postgres 10 แต่ในภาค 11 เค้าจัดการข้อจำกัดให้หมดแล้ว โดยส่วนใหญ่ที่เกี่ยวกับการทำ index นะ


จบเรื่องของการทำ partitioning

author
นันทวัฒน์ ไชยรัตน์

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