#MySQL

Build APM บน Windows ตอนที่ 4: คอมไพล์ MariaDB 11.8 LTS เอง
ตอนที่ 4 ของซีรีส์ Build APM บน Windows พาคอมไพล์ MariaDB 11.8.9 จาก source ด้วย CMake และ Ninja ทีละขั้น ตั้งแต่เตรียมเครื่องมือ รันสคริปต์ ทดสอบบนพอร์ต 3399 ไปจนถึงเหตุผลที่ต้องล็อก collation เป็น utf8mb4_unicode_ci

ไม่มีมิเตอร์ kWh แต่อยากรู้ค่าไฟรายวัน คิดจากกระแสที่วัดได้
บันทึกการแปลงค่ากระแสจากหัววัด CT ให้กลายเป็นหน่วยไฟและค่าไฟรายวันแบบแยกช่วงเวลา ตั้งแต่สูตรกำลังไฟสามเฟส จังหวะการอ่านที่เป็นส่วนหนึ่งของสูตร การข้ามช่วงไฟดับ ไปจนถึงการแยกช่วง peak กับ off-peak ด้วยเลขคณิตบน epoch และตารางสรุปรายวันที่ทำให้หน้าเว็บเร็วขึ้นเจ็ดเท่า

อ่านจากฐานสำรอง ต้องมีป้ายบอกว่าข้อมูลเก่ากี่นาที
replication บอกว่าตามหลัง 0 วินาทีได้ทั้งที่ข้อมูลค้างอยู่เมื่อวาน เพราะสองสัญญาณนี้วัดคนละเรื่องกัน — วิธีตั้งตัวเฝ้าที่เทียบทั้ง Seconds_Behind_Master และความสดของข้อมูลธุรกิจ พร้อมจับคนที่แอบเขียนลง slave และตัวเฝ้าที่เฝ้าตัวเฝ้าอีกชั้น

time-series เป็น JSON โตวันละ 50 MB ย้ายลงคอลัมน์โดยไม่แก้ dashboard
เก็บค่าที่อ่านจากอุปกรณ์ทั้งเฟรมเป็น JSON array วินาทีละแถว ผ่านไปสองสัปดาห์ตารางโต 183 MB ที่ปลายทางและ 625 MB บนเซิร์ฟเวอร์ พร้อมกับ JSON_EXTRACT ที่ทำ index ไม่ได้ — วิธีย้ายไปเก็บเป็นคอลัมน์ int แล้วให้ API ประกอบ array คืนแบบ sparse เพื่อไม่ให้ dashboard รู้ตัวสักบรรทัด

audit ระบบ prod ที่มีข้อมูลลูกค้าจริง โดยไม่ทิ้งขยะสักแถว
เจ้าของระบบสั่งให้ทดสอบทั้งระบบบนเครื่องจริงที่มีข้อมูลลูกค้าอยู่ แล้วห้ามเหลือแถวขยะไว้แม้แถวเดียว วิธีที่ผมใช้คือ bootstrap Laravel เองแล้วเรียก controller ตรง ๆ ใน transaction ที่ rollback ทิ้ง พร้อมนับ COUNT ทุกตารางก่อนและหลังเป็นหลักฐาน

ย้ายการคำนวณจาก PHP ไปทำในเบราว์เซอร์: 12 วินาที เหลือ 12 มิลลิวินาที
หน้าเดียวยิง subquery หลักหมื่นครั้งจนโหลดนาน 12 วินาที ผมแก้ด้วยการทำตารางสรุปไว้ล่วงหน้า ส่ง dataset ก้อนเดียว 107 KB แล้วย้ายสูตรไปคำนวณในเบราว์เซอร์ เหลือ 12 มิลลิวินาที พร้อม parity test ที่บังคับให้ผลฝั่ง JS ตรงกับ PHP ทุกแถว

MariaDB ที่ยังใช้ค่า default — buffer pool 128M บนเครื่อง RAM 55 GB
เครื่อง 16 core RAM 55 GB SSD แต่ MariaDB ยังใช้ buffer pool 128 MB ตามค่าติดตั้ง ผลคืออ่านดิสก์ไป 50 ล้านครั้งใน 5 วัน ค่าก่อนหลังทั้งชุด กับดักชื่อ service กับ path config บน DirectAdmin/Debian วิธี rollback และ MyISAM อีก 500 ตารางที่รอแปลง

charset ไม่ตรง ทำ index ตายเงียบ ตอน JOIN ข้ามฐาน — mirror utf8mb4
ฐานเก่าเป็น tis620 ฐานใหม่เป็น utf8mb4 พอ JOIN ข้าม database ปุ๊บ index ทุกตัวกลายเป็นของประดับทันทีโดยไม่มี error สักบรรทัด — วิธีพิสูจน์ด้วย EXPLAIN และวิธีทำ mirror แปลง tis620 เป็น utf8mb4 ตอน dump พร้อมกับดัก sed ที่ทำตารางพังเงียบ ๆ

query เดียวค้าง 54 นาที ทำเว็บล่ม 504 ทั้งเว็บ เพราะ MyISAM lock
ตารางเดียวขนาด 30 MB ทำให้เว็บทั้งระบบขึ้น 504 ทุกหน้า ทั้งที่ RAM ยังว่าง 9.5 GB — ไล่จาก information_schema.PROCESSLIST จนเจอ SELECT ตัวเดียวที่ค้าง 54 นาทีบนตาราง MyISAM แล้วลามเป็น metadata lock ทั้งเซิร์ฟเวอร์ พร้อมวิธีแก้เฉพาะหน้าและวิธีกันไม่ให้เกิดซ้ำ

ย้ายบอร์ด vBulletin 4.2.5 ไป Flarum: บทเรียนจากสองแสนโพสต์
ย้ายฟอรัมเก่า vBulletin 4.2.5 ที่มีสมาชิกเจ็ดพันกว่า กระทู้สองหมื่นกว่า และโพสต์สองแสนกว่า ไปอยู่บน Flarum — บันทึกกับดักที่เสียเวลาจริง ตั้งแต่ guest userid 0 ที่ทำ FK พังทั้งชุด, md5 ซ้อน md5 ของรหัสผ่านเก่า, การแปลง BBCode เป็น s9e XML, attachment ที่อยู่บนดิสก์ไม่ใช่ใน DB ไปจนถึงเหตุผลที่ต้อง scp สคริปต์แทน heredoc

กู้ MariaDB ที่ InnoDB redo-log เสียด้วย force_recovery แล้ว reinit
MariaDB สตาร์ทไม่ขึ้นหลังเครื่องดับไม่สะอาด — InnoDB redo log เสีย ลาก system table mysql.global_priv พังตาม นี่คือลำดับกู้จริง เริ่มจาก innodb_force_recovery ให้พออ่านได้ แล้ว dump ทีละ db ก่อน reinit ระบบใหม่ทั้งก้อน พร้อมกฎว่าอย่าดันเลข force_recovery เกินจำเป็น

นำเข้า/ย้ายข้อมูลไทยให้ไม่พัง: กับดัก VARCHAR, idempotency, สระ OCR
บทเรียนจริงจากงานนำเข้า/ย้ายข้อมูลไทยหลายแสนแถว — VARCHAR สั้นไปตัด synthetic key จนชนกันเงียบๆ, idempotency ที่ต้อง DELETE ก่อน INSERT ไม่งั้นยอดพุ่ง 200%, collation ที่มอง su001 กับ SU001 เท่ากันแต่เก็บทั้งคู่, และสระไทยเพี้ยนจาก OCR ที่ต้องมี normalization map ก่อน insert

แอปเก่าพังหลังย้ายเซิร์ฟเวอร์ — error 1364/1366 กับ MariaDB strict mode
ย้ายเว็บจากเซิร์ฟเวอร์เก่ามาเครื่องใหม่แล้วฟอร์มสมัครสมาชิกพังทั้งที่โค้ดไม่เปลี่ยน — ต้นเหตุคือ STRICT_TRANS_TABLES ใน sql_mode ของ MariaDB รุ่นใหม่ พร้อมวิธีแก้ 3 ระดับ ตั้งแต่ conf.d จนถึง SET SESSION รายแอป