[Golang] ทำไม​ ORM ไม่ควรเป็นทางออกที่ดีที่สุด?

Teerasak N
THE EXISTING COMPANY
4 min readJun 8, 2020

--

การใช้งาน Databaseโดยการใช้ ORM เข้ามาช่วย ทำให้ประสิทธิภาพในการ Query ข้อมูลช้าลงจริงรึเปล่า มาลองพิสูจน์กัน

Photo by Campaign Creators on Unsplash

สำหรับคนมีเวลาอ่านน้อย

  • 🚀 ORM คือ การ map ระหว่าง ข้อมูลที่มีความสัมพันธ์ (Relational Database) ให้มาอยู่ในรูปแบบ Object-Oriented Language และ แปลงข้อมูลที่ในรูป Object-Oriented Language กลับไปเป็น ข้อมูลที่รูปแบบข้อมูลที่มีความสัมพัมธ์ (Relational Database)
  • ⚡️จะมีการทดสอบความแตกต่างระหว่างการใช้งาน Package ORM กับ Package Not ORM ในเรื่องประสิทธิภาพของการทำงานระหว่าง App กับ Database ในเรื่องของความเร็วแบบไหนจะเร็วกว่ากัน
  • ♻️ จากการทดสอบโดยการ Query ข้อมูลจากให้ใช้งาน Package ทั้งสองแบบพบว่า การให้งาน Package ในแบบ ที่ไม่ใช่ ORM มีความเร็วในการว่า Query กว่า Package ที่เป็นแบบ ORM

กด 🔖 (Bookmark) ไว้อ่านทีหลังกันได้ถ้าไม่มีเวลา
ใครอยากเข้าใจมากขึ้นเริ่มอ่านบทความนี้ได้เลย 👇🏻

ณ ออฟฟิศที่ยานเราจอดอยู่ 🚀

เรื่องมันเกิดขึ้นในวันหนึ่ง พี่ Panupak Vichaidit ได้รีวิว Code ของในส่วนของผม พบว่าในส่วนของ Repository ได้มี Comment หนึ่ง บอกประมาณว่า

การใช้งาน Packageในลักษณะของ ORMในโปรเจค ทำให้การใช้งานระหว่าง App กับ Database มีประสิทธิภาพน้อยกว่า การใช้งาน Packageในลักษณะของ Not ORM

วันนี้เลยจะมาเขียน Code ตัวอย่างการใช้งาน Raw Query vs ORM vs Not ORM ว่าจะมีความแตกต่างกันจริงหรือไม่ ไปดูกันครับ

มาเริ่มทดสอบกันครับ 👨‍🚀

เนื้อหาของบล็อกนี้จะมายกตัวอย่าง Code สำหรับการ Query ข้อมูลจาก Databaseโดยจะมีทั้ง type-raw query, type-safe ของ ORM และ type-safe แบบที่ไม่ใช้ ORM ที่มี logic เดียวกันเพียงแค่แตกต่างจากการนำ Package เข้ามาช่วยสำหรับการเขียน Query ข้อมูลจาก Database

เริ่มกันเลยครับเรามาดู Package ที่นำมาใช้งานกันก่อน

ส่วนของ type-raw query จะเลือกใช้ Package พื้นฐานของภาษา Go

สำหรับ type-safe ORM เจ้าของบล็อกจะเลือกให้ Package ที่จะนิยมใช้กันคือ GORM

สำหรับ type-safe ที่ไม่ใช้ลักษณะของ ORM เจ้าของบล็อกจะเลือกใช้ GO-JET

ทั้งสอง Packageโดยเลือกมาจากการแนะนำจากเว็บ Awesome Go

ในส่วนของ logic มีการใช้งาน database โดยใช้งาน postgres database โดยมีการ SELECT ข้อมูลทั้งหมด 500000 (rows) พร้อมจับเวลาการประมวลผล

มาเริ่มในส่วน Raw Query กันก่อนครับ

mkdir example-raw-query.go

มาดูผลทดสอบ Raw Query โดยใช้ Package พื้นฐานของภาษา Go กัน

go run main.go

จากการทดสอบทั้งหมด 3 ครั้งในการ select ข้อมูลทั้ง 500000 (rows)
ค่าเฉลี่ยของความเร็วในการประมวลผลคือ 1.04016838 second

มาเริ่มในส่วน Package ในที่เป็นลักษณะแบบ ORM กันต่อ

mkdir example-orm.go

มาดูผลทดสอบ ในแบบ ORM

go run main.go

จากการทดสอบทั้งหมด 3 ครั้งในการ select ข้อมูลทั้ง 500000 (rows)
ค่าเฉลี่ยของความเร็วในการประมวลผลคือ 3.226739554 second

มาเริ่มในส่วน Package ที่ไม่ใช้ลักษณะของ ORM กันต่อ

mkdir example-notorm.go

มาดูผลทดสอบ ในแบบที่ไม่ใช้ ORM

go run main.go

จากการทดสอบทั้งหมด 3 ครั้งในการ select ข้อมูลทั้ง 500000 (rows)
ค่าเฉลี่ยของความเร็วในการประมวลผลคือ 2.21162734 second

ต่อไปจะเป็นการทดสอบ Benchmark ในแต่ละ Package กัน

ส่วนของ Raw Query โดยใช้ Package database/sql ของภาษา Go

มาดูผลทดสอบกันครับ

go test -bench=BenchmarkRowQuerySlice

ส่วนของ Package GORM

go test -bench=BenchmarkORMSlice

มาต่อในส่วนของ GO-JET กัน

go test -bench=BenchmarkNotORMSlice

จะเห็นว่าจำนวนการทำงาน 1 รอบ โดยแต่ละรอบ Query ทั้งหมด 500000 (rows) base ใช้เวลา 1.200 วินาที ส่วน GORM ใช้เวลา 3.317 วินาที และ GO-JET ใช้เวลา 2.332 วินาที

สรุป

ในเรื่องของ Performance จะเห็นว่าแบบ Raw Query สามารถ query ข้อมูลได้เร็วที่สุดถ้าเทียบกับ type-safe orm โดยใช้ gorm กับ go-jet ถึงแม้ Raw Query จะมีความเร็วที่สุด ก็ยังมีข้อเสียในส่วนของการทำ Debug Code ที่ทำได้ยากกว่า type-safe SQL queries

และมีข้อดีในส่วนของการใช้ Package ที่ไม่อยู่ในรูปแบบของ ORM เจ้าของบล็อกคิดว่าการที่เราเลือกใช้ GO-JET มันทำให้เราเขียน Query ได้ใกล้เคียงภาษา SQL มากที่สุด ถือว่าเป็นข้อดีในการสะสมสกิลเพิ่มขึ้นได้ เพราะถ้าเรายังใช้ Package ORM สำหรับ 1 ภาษา ก็มี Package ORM อยู่จำนวนมาก แต่ละบริษัทก็เลือกใช้ ORM แตกต่างกันไป ทำให้เราต้องฝึกใช้ ORM ในแต่ละแบบอยู่ตลอด ซึ่งทำให้เราต้องเริ่มต้นใหม่อยู่เสมอ

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

--

--