ข้อดี Unique Index ใน MyIsam MySQL และวิธีทำสำหรับ Table ขนาดใหญ่
เหตุผลที่ต้องทำ
- มีการขึ้น Waiting for Table lock level เป็นจำนวนมาก
- ทำให้การดูดข้อมูลจาก Facebook API ช้า ฯลฯ
เข้าเรื่อง
เนื่องจากว่าผมมีข้อมูลจำนวน 20 กว่าล้าน Record แล้วพึงรู้ว่ามีการ SELECT ถามแล้ว INSERT โดย Scenario ที่ชัดเจนมากที่ทำให้ช้าเวลาจะ Insert ข้อมูลจำนวนมากๆๆๆ แล้วก็มีข้อมูลมากคือ “มีข้อมูลนี้รึยัง ถ้าไม่มี INSERT”
ต้นเหตุของความช้าคือ MyIsam นั้นจะมี Read Lock , Write Lock หรือว่าง่ายๆ จะไม่ทำสองอย่างพร้อมๆกัน ดังนั้นเมื่อเราถามก่อนแล้วค่อย Insert ด้วย Process เดียวมันจะไม่มีปัญหา แต่ถ้ามีการใช้งานพร้อมๆกันละช้าแน่ !! วิธีแก้ที่ทำได้ง่ายคือ
“การทำ Unique Index กับเปลี่ยน Query เวลาจะ Insert เป็น INSERT IGNORE INTO”
ทำให้ไม่มีการเกิด Read Lock น้อยลงทำให้ Insert ได้เร็วขึ้น และการทำ Unique Index ยังทำให้มั่นใจได้มากกว่าว่าไม่มีข้อมูลซ้ำแน่แท้กว่าการถามด้วย SELECT เป็นแน่แท้ แต่ก่อนอื่นการทำ Index ใน MySQL ปกตินั้นคือใส่ Index ได้ไม่เกิน 1000 bytes ดังนั้นถ้าจะทำ index บน varchar 255 , 2 fields ที่ผมเจอก็จะไม่พอ 255*2*3 = 1530 bytes (utf-8 3 bytes ต่อ 1 characters) ผมก็เลยต้องมีการเปลี่ยนเป็น latin1 ทั้ง 2 fields ด้วยคำสั่งนี้
ALTER TABLE `mytable`
CHANGE `field1` `field1` VARCHAR(255) CHARACTER SET latin1 COLLATE latin1_general_ci NOT NULL,
CHANGE `field2` `field2 ` VARCHAR(255) CHARACTER SET latin1 COLLATE latin1_general_ci NOT NULL
เพียงคำสั่งนี้จะเสียเวลาทำเพียงครั้งเดียว เร็วกว่าทำทีละ field ถ้าข้อมูลมี 20 ล้าน rows ก็ประหยัดเวลาไปได้มากครับ เอาละเข้าเรื่องวิธีทำ Unique Index
วิธีทำที่ดีและเร็วที่สุดกับ Table ขนาดใหญ่โดยใช้คำสั่งทำ Unique Index แบบ 2 field ดังนี้
ALTER IGNORE TABLE mytable ADD UNIQUE unique_field1_and_field2( field1, field2 )
เพียงเท่านี้มันจะทำการใส่ Unique Index ให้แถมลบข้อมูลซ้ำให้ด้วย !!
ปล. ถ้าคุณไม่มั่นใจที่จะเสียข้อมูลซ้ำไปให้ไปลองใช้วิธีอื่นครับ เช่น SELECT DISTINCT GROUP BY
ปล2. ผมมีการปรับอีก 2 ค่าใน my.cnf คือ max_write_lock_count = 50 แล้วก็ concurrent_insert = 2 ครับ
ผลลัพธ์ที่น่าพอใจ
- ความเร็วในการดูดข้อมูลจาก Facebook API ผมเร็วขึ้นจาก 1500 วินาทีเหลือ 27 วินาทีเพราะ MySQL ไม่ขึ้น Waiting for Table จากการ SELECT แล้ว INSERT
- การใช้ CPU ของ MySQL ลดลงอย่างมาก (ของผมมีการใช้งานหนักมีการ INSERT วินาทีหนึ่งประมาณ 10 – 100 records ดังนั้นถ้ามี SELECT มาขั้นแล้วค้นหาข้อมูลใน Table ขนาด 20gb มันเปลื้อง CPU ขนาดไหน !!)
