- Mattermost ใช้ Elasticsearch เพื่อลดภาระของฐานข้อมูลและให้ผลการค้นหาที่เร็วขึ้นมาก
- เพื่อให้ Elasticsearch ทำงานได้อย่างเหมาะสม จำเป็นต้องทำดัชนีข้อมูลทั้งหมดที่เป็นเป้าหมายการค้นหา
- สำหรับข้อมูลที่ทำดัชนีไปแล้ว การทำดัชนีโพสต์และไฟล์ใหม่ในภายหลังค่อนข้างเร็ว
- แต่การทำดัชนีฐานข้อมูลขนาดใหญ่มาก (โพสต์ 100 ล้านรายการ) ใหม่ทั้งหมดตั้งแต่ต้นนั้นช้ามาก (ผ่านไป 18 ชั่วโมงยังทำได้ไม่ถึงครึ่ง และยิ่งช้าลงเรื่อยๆ)
- จากกราฟเวลาที่ใช้ต่อการเรียกฐานข้อมูลแต่ละครั้ง พบว่า SQL query ของเมธอด
PostStore.GetPostsBatchForIndexing เป็นปัญหา
- คิวรีนี้โดยพื้นฐานจะเรียงโพสต์ตาม creation timestamp และคืนค่าโพสต์ใหม่กว่า timestamp ที่กำหนดจำนวน N รายการ
- งาน indexing จะรันคิวรีนี้ซ้ำไปเรื่อยๆ จนกว่าโพสต์ทั้งหมดจะถูกทำดัชนี
- ใช้
EXPLAIN (ANALYZE, BUFFERS) เพื่อวิเคราะห์ execution plan ของคิวรี:
- ระหว่างการทำ index scan บนตาราง Posts มีการประมวลผล 40 ล้านบล็อกเพื่อใช้เงื่อนไข Filter (309GB)
- การ JOIN กับตาราง Channels ไม่ใช่ปัญหา
- ในเงื่อนไข OR ของ WHERE หากใช้เฉพาะส่วน
Posts.CreateAt > ?1 จะเร็วขึ้นมาก (30ms)
- จากนั้นเมื่อใช้เงื่อนไข
Posts.CreateAt = ?1 AND Posts.Id > ?2 จะเร็วอย่างมากเป็นพิเศษ (0.047ms)
- การหาสาเหตุ:
- คิวรีต้นฉบับสแกนทุกแถวของ Posts แล้วค่อยกรองด้วย Filter ขณะที่คิวรีที่แก้ไขแล้วตรวจเฉพาะดัชนีและดึงเฉพาะแถวที่ต้องใช้
- สาเหตุที่คิวรีช้าลงเรื่อยๆ ตามเวลาคือมีจำนวนแถวที่ต้องกรองทิ้งเพิ่มขึ้นเรื่อยๆ
- วิธีแก้ไข:
- ใช้ความสามารถ row constructor comparison ของ PostgreSQL โดยเปลี่ยนเงื่อนไขเป็น
(Posts.CreateAt, Posts.Id) > (?1, ?2)
- หลังเปลี่ยนแล้ว คิวรีนี้ลดเวลารันลงอย่างมากเหลือ 34 มิลลิวินาที
- แต่ใน MySQL คิวรีที่เปลี่ยนกลับทำงานช้ากว่าเดิม ตรงกันข้าม MySQL ทำงานได้เร็วกว่าด้วยคิวรีต้นฉบับ จึงแยกโค้ดให้ใช้คิวรีต่างกันตามฐานข้อมูล
- สิ่งที่ได้เรียนรู้:
- เวลาใช้
EXPLAIN ควรใส่ตัวเลือก BUFFERS เสมอ
- ควรทำให้ใช้ Index Cond แทน Filter
- ควรตั้งต้นไว้เสมอว่า PostgreSQL และ MySQL ทำงานต่างกันเกือบทุกครั้ง
- สรุป
- การปรับแต่งครั้งนี้ช่วยลดเวลารันคิวรีได้มากกว่า 1000 เท่า
- การปรับแต่งนี้ถูกรวมอยู่ใน Mattermost v9.7.0 และ v9.5 ESR
- การปรับแต่งครั้งนี้ทำให้ได้เรียนรู้อะไรมากมาย
3 ความคิดเห็น
อย่างที่มีเขียนไว้ในย่อหน้าสุดท้าย ชื่อบทความนี้ก็ให้ความรู้สึกเหมือนพาดหัวล่อคลิกนิดหน่อย...ถ้าจะปรับให้สื่อความจริงมากขึ้น
ก็คงเป็น
'กรณีศึกษาการใช้งาน PostgreSQL ที่ได้เรียนรู้ผ่านความผิดพลาด'
ละมัง..
อืม... โดยส่วนตัวแล้ว ถ้าเขียนบทความระดับนี้โดยพาดพิงบริษัท/ผลิตภัณฑ์ใดผลิตภัณฑ์หนึ่ง ผมกลับรู้สึกว่าความน่าเชื่อถือต่อผลิตภัณฑ์นั้นจะลดลงไปมากเสียมากกว่า
การเรียบเรียงทำได้ชัดเจนเป็นลำดับดี แต่ก็น่าเสียดายที่คุณค่าทางเทคนิคที่อยู่ข้างในดูจะยังขาดไปสักหน่อย
หลังจากผมอ่านบทความนี้แล้วกลับยิ่งเชื่อถือน้อยลงไปอีก เพราะนี่หมายความว่าสินค้าที่รับเงินขายกันอยู่ได้ปล่อยฟีเจอร์ออกมาโดยไม่ได้ทดสอบการรองรับข้อมูลปริมาณมากเลย ดัชนีที่เรียบง่ายระดับนั้นน่าจะต้องตั้งไว้ตั้งแต่ขั้นตอนพัฒนาฟีเจอร์ไม่ใช่หรือ ผมรู้สึกว่ามีการข้ามขั้นตอนการพัฒนาซอฟต์แวร์ไปหลายอย่าง