ปัญหาการมีอยู่ของ Update ใน SQL

champillon
Billme Venture
Published in
2 min readJul 8, 2018

จริงๆ ที่ office ผมเลิกใช้ command update ใน SQL มาซักพักใหญ่ๆแล้วแหละ

จะเหลือใช้ update ก็แค่ 2 กรณี
1. เปลี่ยน state ของ transaction จริงๆก็คือ update _ set status = ? where … อะไรแบบนี้

2. soft delete ซึ่งคือ update _ set is_delete = true where … อะไรประมาณนี้

.

ที่เราเลิกใช้ Update ในเรื่องอื่นๆ เพราะมันเป็นการทำลาย consistency ของ data

ผมให้นึกง่ายๆนะครับ

สมัยก่อนตอนเราไม่มีระบบไอที เราก็ใช้กระดาษ

เวลาเราเขียนผิด บางทีเราก็ขีดค่า บางทีเราก็ใช้ลิควิดลบแล้วเขียนทับ

แต่ประเด็นคือ บ่อยครั้งที่เรารู้สึกว่าเอกสารไม่สมบูรณ์

จนต้องหยิบฟอร์มกระดาษใบใหม่มาเขียนใหม่แทน

.

คำว่ารู้สึกว่าเอกสารมันไม่สมบูรณ์ อันนี้ก็สื่อถึง consistency ของ data แหละครับ

ส่วนการที่ต้องหยิบกระดาษมาเขียนใหม่ เพราะ update ไม่มีจริง…

จริงๆ แล้วการ update คือการ delete ของเดิม แล้ว insert ของใหม่

ดังนั้น update ไม่มีอยู่จริง

.

ถ้าเราไปฝืน update สิ่งที่จะเกิดตามมาคืออะไร

ก็คือ requirement บ้าๆ ที่จะตามมาจากการที่มัน update ได้หน่ะสิ

เช่น ที่ Billme เราส่งบิล แล้วเรามีการแนบเอกสารประกอบการส่งบิล

ถ้าเรา update ได้ เช่นลืมเอกสารแนบ สิ่งที่จะตามมาคือ
1. จะส่งเอกสารทั้งชุดใหม่เลยมั้ย?

2. ถ้าไม่ส่งทั้งชุดใหม่ แล้วจะส่งแค่เอกสารแนบที่เพิ่งเพิ่มเข้าไปตามไป มันจะงงมั้ย…

บลาๆ บลาๆ บลาๆ

requirement เพี้ยนๆ จะตามมาอีกมากมาย

.

นอกจากนั้น การ update เป็นการทำให้รายการนั้นเป็น stateful

เพราะไม่ว่าเราจะทำอะไรกับมัน เราจะต้องคิดเสมอว่า เค้าจะกลับมาแก้ไขได้อีก

พอเค้าจะกลับมาแก้ไขได้อีก ทุกอย่างก็ต้องเตรียมให้แก้ไขได้

การเตรียมให้แก้ไขได้คือการทำให้เก็บ state ในรายการ

ซึ่งพอรายการนั้นเป็น stateful การทำ self-recover ก็เป็นไปได้ยาก

เพราะจะ self-recover ได้ ต้อง capture ทุกๆเคส ว่า state ใด self-recover แบบไหน

ซึ่งแมร่งซับซ้อน และเพิ่ม overhead ในการพัฒนาอีกมาก

.

stateful นั้นเป็นปัญหากับการ scale อยู่แล้ว

เพราะต้อง maintain state ร่วมกัน ทำให้ scale เป็นไปได้ยาก

เพราะต้อง sync state ให้ทำงานร่วมกันได้

อย่างที่ Martin Odersky กล่าวไว้ “state is root of all evil”

.

นอกจากนั้น การที่รายการมัน update ได้

มันจะกลายเป็นน้ำผึ้งหยดเดียว ที่ทำให้ทั้ง Architecture พัง

.

Billme เรากำลังขยาย platform เป็น Billme 2.x

ซึ่งมี Kafka เป็นแกนในการทำ message delivery

เพราะความซับซ้อนกำลังจะมาอีกมากมาย

ซึ่งเดิม Architecture เราเป็นแบบนี้

.

เดิม state ของบิลเราเก็บใน CRUD

แต่ความซับซ้อนมันกำลังจะเริ่มตรงนี้แหละ

ถ้าเราสร้างบิลทีละใบ state ในการคุมมันก็จะเป็น 1–1

ซึ่งมัน nice & simple

.

แต่ถ้าเรารับบิลเป็นไฟล์ CSV หรือพูดง่ายๆว่ารับเป็น bulk นั้นแหละ

ความซับซ้อนมันกลับเพิ่มขึ้นมากมาย

การ control state ของ 1–1 กับการ control state ของ 1-n นั้นคนละเรื่องกัน

ถ้าเป็น 1–1 เราก็ cancel ทีละใบ

แต่ถ้าเป็น 1-n เราต้องมีทั้ง preview data ที่เข้ามา, approve data นั้นๆ

และหรือ cancel ไปบางใบ แล้วค่อยส่งไปสร้าง

.

ดังนั้นความซับซ้อนมันแตกต่างกันนัก

ถ้าเรายัดความซับซ้อนทั้งหมดอยู่ใน CRUD

code คงกลายเป็นสปาร์เก็ตตี้แน่

.

ที่เราทำได้คือ…

“Working Hard to Keep IT Simple”

(เหมือนที่ Odersky ได้กล่าว)

จะเห็นว่า เราแบ่ง CRUD ออกเป็น 4 ส่วน โดย

  1. CRUD เดิม ไปเป็น Single Bill Action
  2. Authentication Service แยกออกมา เพื่อให้ใช้ได้กับทุก services อื่นๆ
  3. Bulk CSV จัดการ state โดย Bulk Action
  4. ไม่ว่าจะ Bulk Bill หรือ Single Bill สุดท้ายจะไปกองที่ Archive Bill เมื่อ Bill นั้นส่งออกไปแล้ว

.

ดังนั้น จะเห็นได้ว่า เราแยก state ที่เป็น action คือกำลังสร้าง

กับ state ที่เป็น Archive คือเรื่องราวทั้งหมดจบแล้ว

แต่ถ้าเราทำให้ Bill มัน update ได้ ก็จะทำให้เรา

ไม่สามารถแยก Archive ออกมาอีกที่ได้

.

และอาจจะไม่กล้าแยก Bulk Bill กับ Single Bill ออกจากกันด้วย

เพราะ cost ในการทำทุกๆ functions ให้มัน update ได้ ในแต่ละ detail มันสูงมาก

เช่น ถ้าแก้แต่ราคา จะแจ้งเป็นบิลใหม่ยังไงให้รู้ว่าแก้แต่ราคา

หรือถ้าเพิ่มเอกสารแนบ จะส่งเฉพาะเอกสารแนบได้มั้ย

หรืออื่นๆ บลาๆ บลาๆ บลาๆ

.

แค่ Update ได้นิดนึง ประหยัดที่เก็บนิดเดียว

แต่สร้าง cost ในการ maintain อีกมหาศาล

แถมยังอาจจะเป็นตัวยึด ทำให้เรา scale ไม่ขึ้นก็ได้

.

จริงๆ บนโลกนี้ ควรระวังมากๆในการใช้ SQL ที่ชื่อ update เลย…

.

สวัสดีครับ.

.

--

--