# เก็บรูปในฐานข้อมูล

## 😥 ปัญหา

เวลาที่ทำแอพอะไรก็ตาม แล้วมันต้องมีการเก็บรูปที่ผู้ใช้อัพโหลดเข้ามา **ดช.แมวน้ำ** แมวน้ำเจอบ่อยมากที่ **developer จะชอบเอาไฟล์รูปไปเก็บไว้ใน database ! 😱** ซึ่งถามว่าทำได้ไหม? คำตอบคือทำได้ครับ แต่มันจะเหมาะสมหรือเปล่า? ในบทความนี้เราจะมาดูกันว่าจริงๆแล้วเราควรจะเก็บรูปยังไง? และ ทำไม?

{% hint style="success" %}
**แนะนำให้อ่าน**\
สำหรับใครที่ยังออกแบบ database ไม่เป็น ยัง งงๆ อยู่ว่าตารางนี้ควรจะเก็บอะไรดี หรือ Normalization คืออะไร? ความรู้ส่งคืนครูหมดแล้ว ก็สามารถไปศึกษาต่อได้จากลิงค์นี้เบยครัช [👶 **บทสรุปฐานข้อมูล**](https://www.saladpuk.com/beginner-1/database-design)
{% endhint %}

## 🤔 เก็บรูปในฐานข้อมูลผิดตรงหนาย ?

ตามที่เกริ่นไปด้านบนว่า **มันก็เก็บได้นะ แต่ปรกติทั่วโลกเขาไม่เก็บไว้ในนั้นกัน** ส่วนสาเหตุหลักๆมาจาก 2 เรื่องตามด้านล่างเบย

### 💳 ค่าใช้จ่าย

ถ้าใครที่เคยจ่ายค่า database ด้วยตัวเองก็น่าจะพอทราบว่า **ขนาดความใหญ่ของฐานข้อมูล** ก็เป็นหนึ่งในปัจจัยที่ราคาจะถูกลงหรือแพงขึ้นด้วย ดังนั้นยิ่งเราทำให้ข้อมูลเราเล็กได้มากเท่าไหร่ เราก็จะประหยัดได้มากขึ้นเท่านั้นนั่นเอง

> ❓ มีน้องๆ developer หลายคนสงสัยกันต่อว่า แต่บางทีไฟล์รูปที่เก็บมันก็เล็กๆแค่ไม่มี 10KB เองนะ มันจะทำให้ฐานข้อมูลโตได้ยังไงอ่ะ ?

จากคำถามด้านบนผมลองเปรียบเทียบให้ดูง่ายๆแบบนี้ละกัน โดยสมมุติว่าผมต้องการจะเก็บรูปด้านล่างนี้เข้าฐานข้อมูล ซึ่งมันมีขนาดแค่ 29.6KB เพียงเท่านั้นเอง

![ขนาดไฟล์ 29.6 KB](/files/-M2YMefkNRlYUixKaXm0)

ซึ่งก็จริงว่ามันก็ดูเหมือนจะไม่ได้ใหญ่โตอะไรเท่าไหร่เลยชิมิ? งั้นคราวนี้ผมจะลองสร้างไฟล์ text ที่มีขนาด 29.6KB ดูบ้างนะ ซึ่งมันก็จะประมาณรูปด้านล่างนี่แหละ ซึ่งลองสังเกต scroll bar ดูนะว่ามันยาวแค่ไหน

![ขนาดไฟล์ 29.6 KB หรือราวๆ 28,951 ตัวอักษร](/files/-M2YQo_MczkO_UNAppqe)

สำหรับใครที่ไม่จุใจอยากเบิกเนตรดูเต็มตาก็โหลดไฟล์ด้านล่างไปดูก็ได้

{% file src="/files/-M2YQgtaqoy34gfmYJwr" %}
ไฟล์ขนาด 29.6 KB ยาวขนาดไหน ?
{% endfile %}

จากที่ว่ามาไฟล์ขนาด 29 KB ดูเหมือนว่ามันจะเล็กๆเอง แต่เมื่อเทียบกับปริมาณข้อมูลตัวอักษรแล้วเราจะพบว่า ตัวอักษรมันมีขนาดเล็กกว่ามากเบย ซึ่งจากรูปด้านบนผมว่าเอาไปเขียนหนังสือจบ 1 บทแน่ๆเลย

{% hint style="success" %}
**เกร็ดความรู้**\
ตัวอักษรที่เราพิมพ์ๆกันอยู่นั้นมีขนาด 1 Byte เพียงเท่านั้นเอง
{% endhint %}

แล้วลองคิดดูว่าถ้าเราต้อง**เก็บไฟล์รูปเข้าไปในฐานข้อมูลสำหรับหรับทุก record เลย**มันจะเกิดอะไรขึ้น ? เอาง่ายๆนะแค่เราเก็บรูป Profile (29.6KB) ในตารางผู้ใช้ แล้วเรามีคนใช้งานระบบเราซัก 1,000 คน  พื้นที่ในฐานข้อมูลเราก็ใหญ่ราวๆ 30 MB ได้แล้ว

![](/files/-M2YUIpbJ7k-NQXAbfwp)

แต่ในทางกลับกันถ้าเราเก็บข้อมูลเป็น text อย่างเดียว ผมเชื่อว่ามันเก็บข้อมูลผู้ใช้ได้น่าจะราวๆ 5 แสนถึง 1 ล้าน คนแน่นอน (ขึ้นอยู่กับเก็บอะไรบ้าง)

{% hint style="danger" %}
**มุมชวนคิด**\
เพียงแค่เราเก็บรูปโปรไฟล์ของผู้ใช้ 1,000 คนลงในฐานข้อมูล เราก็จะต้องจ่ายเงินเท่ากับเรามีผู้ใช้ 5 แสนถึง 1 ล้านคนละ (แพงขึ้น 100\~1,000 เท่า+) รูปโปรไฟล์มันสำคัญขนาดนั้นเลยเหรอ? และถ้าเรามีผู้ใช้ 1 ล้านคนล่ะ ? (มันก็จะโตขึ้น 30 GB เลยนะ!! นี่มันเก็บหนังได้กี่เรื่องฟร๊าา 😱)
{% endhint %}

ลองมาดูราคาที่แท้จริงกันดีกว่า สมมุติว่าเรามีฐานข้อมูลขนาด 100 GB เราจะต้องจ่ายสูงสุดปรมาณ $ 25 USD ตามรูปด้านล่าง

![](/files/-M2YYffzDAYflsK3nl7d)

### 💨 Performance

ทำไมการเก็บไฟล์รูปลงฐานข้อมูลถึงส่งผลให้ **ประสิทธิภาพตกลง** นะเหรอ? นั่นก็เพราะว่า**ตัวฐานข้อมูล (ส่วนใหญ่) มันถูกออกแบบมาให้ทำงานกับข้อมูลที่เป็น Simple type** ยังไงล่ะ เช่น ตัวอักษร, ตัวเลข, true/false, วันที่และเวลา ไรพวกนี้ ซึ่งไฟล์รูปที่เก็บอยู่ใน database มันก็ทำงานด้วยได้นะ แต่ข้อมูลพวกนั้นมันจะไม่รู้เรื่องเพราะไฟล์รูปมันอยู่ในรูปแบบของ bytes ยังไงล่ะ และมันก็จะเป็นภาระเวลาที่เราดึงข้อมูลออกมาใช้งานด้วย เช่น แค่จะไปดึงข้อมูลผู้ใช้ออกมา มันก็ต้อง**ไปดึงข้อมูลรูปพวกนั้นขึ้นมาอัดไว้ใน Memory ซึ่ง RAM มันมีจำกัดและราคาแพงม๊วกกกกกกก** แถมยังก่อให้เกิดปัญหาเวลาที่เราส่งข้อมูลกลับไปให้ client ด้วย เพราะมันจะ**เปลือง network bandwidth อีกด้วย** ลองดูราคาด้านล่างเอาละกัน หรือจะไปดูราคาเต็มๆของเซิฟเวอร์ทั้งหมดได้ที่ลิงค์นี้ [**Microsoft - VM Pricing**](https://azure.microsoft.com/en-us/pricing/details/virtual-machines/windows/)

![มันน่าจะอยู่หัวข้อค่าใช้จ่ายเน๊อะ แต่ขี้เกียจย้ายละ](/files/-M2YbtcLjKFON2rymz_q)

{% hint style="success" %}
**แนะนำให้อ่าน**\
แนวคิดพื้นฐานในการทำงานกับ database ที่เหล่าโปรแกรมเมอร์บ้านเราไม่ค่อยรู้ ไปอ่านแล้วทำความเข้าใจได้จากบทความนี้ เพราะมันโคตรสำคัญ ไม่งั้นต่อให้ทำทุกอย่างดีแค่ไหน แต่เรื่องนี้เรื่องก็ทำให้ระบบอืดจนเต่าแซงหน้าได้ [**หัวใจที่สำคัญที่สุดของฐานข้อมูล**](https://www.saladpuk.com/basic/bottlenecks/work-with-db) (🤔 ความรู้เบื้องต้นของฐานข้อมูลที่โปรแกรมเมอร์ 90% ไม่รู้)
{% endhint %}

## 🤨 เคยอ่านเจออีกแบบนิ

สำหรับแมวน้ำบางท่านอาจจะเคยอ่านเจอว่า **Blob ในฐานข้อมูลสมัยนี้มันดีขึ้นมาแล้วนะ** ไปเก็บในนั้นได้เหมือนเดิม แล้ว ซึ่ง **ดช.แมวน้ำ** ขอตอบแบบคร่าวๆว่า จริงครับสมัยนี้อะไรๆก็ดีกว่าสมัยก่อน เขาพัฒนาให้ดีขึ้นเยอะแล้ว แต่ถ้ามองใน**แง่ของการทำ Scaling เพื่อรองรับผู้ใช้ปริมาณมากๆแล้ว database ก็ยังเป็นคอขวดที่ใหญ่เป็นอันดับต้นๆของระบบอยู่ดี** ดังนั้นในมุมของการทำให้ระบบรองรับการขยายตัวเพื่อรองรับผู้ใช้งานปริมาณมหาศาลแล้ว **(Large Scalable Architectures)** **เราควรจะแยกของต่างๆออกจากกัน** เพื่อให้เราสามารถ **`ลดขวด`** ให้ได้มากที่สุด นั่นเอง ซึ่งสิ่งที่ database ถนัดที่สุดก็คือการ **เก็บข้อมูลที่เป็น simple type และ การประมวลผลคณิตรศาสตร์พื้นฐาน** ไม่ใช่การเก็บไฟล์รูปแบบอื่นๆ ดังนั้นเราก็ควรจะเอาหน้าที่เก็บไฟล์รูปแบบอื่นๆไปเก็บไว้ใน service ที่เหมาะสมกับมันนั่นเอง

จากรูปด้านล่างเป็นตัวอย่างการทำ Scalable ของตัวเว็บเพื่อรองรับผู้ใช้ปริมาณมากๆ ซึ่งข้อสังเกตคือเขาจะแยกหน้าที่การทำงานแต่ละอย่างออกมา โดยตัวไหนเก่งเรื่องอะไรก็ไปทำเรื่องนั้นซะ และ ถ้ามีอะไรที่สามารถช่วยลดภาระงานของอีกตัวได้ก็เอามาช่วยลดซะ เพราะการทำแบบนี้มันจะเป็นการลดคอขวดลง แล้วถ้าเราไปเจอคอขวดในระบบ เราก็จะสามารถขยายให้จุดนั้นมันแรงขึ้นเพื่อให้รองรับปริมาณการใช้งานได้นั่นเอง

![https://docs.microsoft.com/en-us/azure/architecture/reference-architectures/app-service-web-app/scalable-web-app](/files/-M2Z8uOuidI5EWpt0D13)

{% hint style="danger" %}
**ข้อควรระวัง**\
สมมุติว่าเราไม่กระจายงานออก แล้วไปพบว่ามันเป็นคอขวดภายหลัง วิธีแก้ปัญหาที่ง่ายที่สุดคือการ ขยายกำลังเครื่องในจุดที่เป็นคอขวด ซึ่งมันก็อาจจะแก้ได้ก็จริง แต่ประเด็นคือ **เราอาจจะได้จ่ายเงินมากกว่าที่ควร** เช่น ในจุดนั้นมันอาจจะมีงานที่รับผิดชอบ 10 เรื่อง แต่เป็นคอขวดแค่ 1 เรื่อง ซึ่งถ้าเราขยายกำลังเครื่อง มันก็จะต้องขยายทั้ง 10 เรื่องนั้นด้วย (เพราะเราไม่แยกงานมันออกเป็นแต่ละ services) เลยทำให้เราต้องจ่ายเงินเพิ่มให้กับสิ่งที่มันไม่ได้มีปัญหาด้วยนั่นเอง
{% endhint %}

{% hint style="warning" %}
**คำเตือน**\
ทั้งหมดที่ว่ามาเป็นหลักในการทำ Large Scalable Architectures ซึ่งใช้ได้กับ Database ส่วนใหญ่เท่านั้น ซึ่งมันก็จะมี database ที่ออกแบบมาทำงานอีกประเภทนึงโดยเฉพาะเหมือนกัน ซึ่งตัวไหนเก่งอะไรยังไง ต้องให้แมวน้ำแต่ละท่านไปศึกษาตัวที่ใช้อยู่เองแล้วล่ะขอรับ
{% endhint %}

## 😄 วิธีแก้ปัญหา

ก็น่าจะพอเห็นภาพความบาปในการเก็บไฟล์รูปในฐานข้อมูลแล้วนะ วิธีการแก้กรรมหนักนี้คือการไปทำบุญล้างป่าช้า เพื่อนำเหล่าไฟล์ภาพออกจากฐานข้อมูลของเราไปเก็บไว้ในที่ชอบๆของมันนั่นเอง (ซี๊ดดดดดด กาวยี่ห้อใหม่ใช้ดี)

ซึ่งจากที่ว่ามาทั้งหมดเราก็พอจะรู้แล้วว่า **ฐานข้อมูลไม่ใช่ที่เก็บไฟล์รูป** ดังนั้นเราก็ควรจะย้ายไฟล์รูปทั้งหมดไปไว้ในที่ๆสมควรของมันนั่นเอง และ **ฐานข้อมูลควรจะเก็บข้อมูลที่เป็น Simple type ดังนั้นเราก็แค่เก็บ URL ของไฟล์รูป**พวกนั้นก็เป็นอันเสร็จสิ้นแล้วนั่นเอง

### 🤔 แล้วจะเก็บรูปไว้ที่ไหน ?

> จะเก็บไว้ที่ไหนก็แล้วแต่ความสะดวกของแมวน้ำแต่ละตัว เช่น จะเก็บไว้ในเซิฟเวอร์ตัวเอง หรือ จะเอาไปไว้พวกเว็บฝากไฟล์ก็ได้ ขอแค่เราได้ URL ที่สามารถเข้าถึงได้ก็พอ (ส่วนเรื่อง privacy ก็จัดการกันเอาเองนะ)

ถ้าปิดจบแบบด้านบนก็ดูเหมือนจะใจร้ายไปหน่อยเอาเป็นแบบนี้ละกัน โดยปรกติ **ดช.แมวน้ำ** จะเก็บไฟล์ไว้ใน **Cloud Service** เพราะมันถูกม๊วก และสามารถควบคุมสิทธิ์และ privacy ได้แบบถึงลูกถึงคนเลย ชนิดที่ว่า Hack ไม่เข้าแน่นอน จะหลุดก็ต่อเมื่อเราเป็นคนตั้งค่าผิดกับมือเอง ส่วนเรื่องราคาก็ตามรูปด้านล่าง สมมุติว่าเก็บไฟล์ 100 GB ไว้ทั้งเดือนก็จ่ายแค่ $2 USD (60-70 บาท) เท่านั้นเอง

![เก็บหนัง ... ได้หลายเรื่องเลย](/files/-M2YfqxPOu5BPu0WSuqA)

แต่ถ้าเป็นไฟล์ที่นานๆๆๆครั้งจะมาเปิดดู ก็จะยิ่งถูกลงไปกว่านั้นได้อีก 100 GB จ่ายแค่ $0.2 USD (6\~7 บาท) ต่อเดือนเท่านั้นเอง ตามรูปด้านล่างเบย

![นี่มันถูกกว่าซื้อ HDD เสียอีก](/files/-M2YhF3IV8mThQ6Y2i75)

{% hint style="success" %}
**แนะนำให้อ่าน**\
สำหรับเพื่อนที่สนใจตัวเก็บไฟล์ตัวนี้ว่าจะใช้งานยังไงทำอะไรได้บ้าง ก็สามารถไปศึกษาต่อได้จากบทความนี้เลยครัช [**Blob storage**](https://www.saladpuk.com/cloud/azure-storage/blobs) ซึ่งมันเป็นส่วนหนึ่งของคอร์ส [**👶 Azure Storage**](https://www.saladpuk.com/cloud/azure-storage) ถ้าสนใจดูเนื้อหาของคอร์สทั้งหมดก็กดที่ชื่อไปดูได้เบย
{% endhint %}

## 🎯 สรุป

โดยรวมการทำงานกับฐานข้อมูลคือ ใช้งานมันให้ถูกวิธี และ ข้อมูลก็ต้องเก็บให้ถูกตามความถนัดของมันด้วย เพราะตัว database จริงๆมันเก่งและเร็วมาก ถ้าเราใช้งานมันได้ถูกต้อง ส่วนใหญ่ที่มีปัญหาคือใช้งานมันไม่ถูก ดังนั้นแนะนำให้เพื่อนๆไปอ่าน Best Practices ของตัว database ที่ตัวเองใช้อยู่ด้วย ถึงจะสามารถรีดความสามารถมันออกมาได้เต็มประสิทธิภาพอย่างแท้จริง

{% hint style="success" %}
**แนะนำให้อ่าน**\
ถ้าสงสัยว่าทำไมแอพมันช้าลองไปทำความเข้าใจเรื่อง คอขวด ของระบบจากบทความด้านล่างนี้ดู แล้วจะเข้าใจว่าผองเพื่อนของความช้านั้น เกิดจากอะไรได้บ้างครัช\
[👦 **Bottlenecks of Software**](https://www.saladpuk.com/basic/bottlenecks)
{% endhint %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://www.saladpuk.com/beginner-1/database-design/img-handling.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
