2.4 Fixed vs Variable Text in Databases
ใน Module 0.4 เราเรียนว่า CHAR(n) จองพื้นที่ตายตัว VARCHAR(n) ยืดหยุ่น ตอนนี้ถึงเวลาดูลึกขึ้น — เมื่อไหร่ใช้อะไร และมี TEXT อีก type ที่คนมักลืม
3 วิธีเก็บ text ใน SQL
Section titled “3 วิธีเก็บ text ใน SQL”| Type | พื้นที่ | ขีดจำกัด | เหมาะกับ |
|---|---|---|---|
| CHAR(n) | จอง n bytes เสมอ | สูงสุด ~255 (ขึ้นอยู่กับ dialect) | ค่าที่ยาวเท่ากันเสมอ |
| VARCHAR(n) | ใช้ตามจริง + 1-2 bytes overhead | สูงสุด ~65,535 | ค่าที่ยาวไม่เท่ากัน แต่มีขีดจำกัด |
| TEXT | ใช้ตามจริง | สูงสุด ~1 GB+ (ขึ้นอยู่กับ dialect) | เนื้อหายาวมาก (notes, articles) |
เจาะลึกแต่ละ type
Section titled “เจาะลึกแต่ละ type”CHAR(n) — ค่าคงที่
Section titled “CHAR(n) — ค่าคงที่”CHAR(2): 'TH' → เก็บ 'TH' (2 bytes พอดี)CHAR(2): 'T' → เก็บ 'T ' (เติม space ให้ครบ 2)CHAR(2): 'USA' → ERROR! (เกิน 2 ตัวอักษร)ใช้เมื่อ: ค่าทุกแถวมีความยาวเท่ากันเสมอ
- รหัสประเทศ ISO:
CHAR(2)—'TH','US','JP' - รหัสสกุลเงิน:
CHAR(3)—'THB','USD','JPY' - เพศ:
CHAR(1)—'M','F','X'
VARCHAR(n) — ยืดหยุ่นแต่มีขีดจำกัด
Section titled “VARCHAR(n) — ยืดหยุ่นแต่มีขีดจำกัด”VARCHAR(100): 'Ploy' → เก็บ 4 chars + length infoVARCHAR(100): 'Ploy Srisuwan' → เก็บ 13 chars + length infoVARCHAR(100): (99 chars) → ได้VARCHAR(100): (101 chars) → ERROR หรือ truncate!ใช้เมื่อ: ค่ามีความยาวไม่เท่ากัน แต่มีขอบเขตที่เหมาะสม
- ชื่อ:
VARCHAR(100) - email:
VARCHAR(254)(RFC 5321 จำกัดที่ 254 chars) - เบอร์โทร:
VARCHAR(20) - URL:
VARCHAR(2048)
TEXT — ไม่จำกัดความยาว (เกือบ)
Section titled “TEXT — ไม่จำกัดความยาว (เกือบ)”TEXT: 'บทความยาว 10,000 ตัวอักษร...' → ได้TEXT: 'เนื้อหา 1 ล้านตัวอักษร...' → ได้ใช้เมื่อ: ไม่รู้ขีดจำกัดของความยาว หรือเนื้อหาอาจยาวมาก
- คอมเมนต์ / review
- บทความ / blog post
- JSON data
- log messages
Sheets ไม่มีความแตกต่าง CHAR/VARCHAR/TEXT — ทุก cell รับ text ยาวแค่ไหนก็ได้ (สูงสุด ~50,000 characters ต่อ cell)
แต่คุณจำลองได้:
| A (ชื่อ column) | B (type) | C (ตัวอย่างค่า) | D (validation) |
|---|---|---|---|
| country_code | CHAR(2) | TH | =IF(LEN(C1)=2,"OK","ผิดความยาว!") |
| name | VARCHAR(50) | Ploy Srisuwan | =IF(LEN(C2)<=50,"OK","ยาวเกิน!") |
| bio | TEXT | (ข้อความยาวๆ) | =LEN(C3)&" chars" |
ลอง Data Validation:
- เลือก column C สำหรับ country_code
- ไปที่ Data → Data validation
- ตั้ง Custom formula:
=LEN(C1)=2 - ลองพิมพ์
THA→ จะแจ้งเตือน!
นี่คือสิ่งที่ SQL ทำให้อัตโนมัติ แต่ Sheets ต้องตั้ง validation เอง
ใน C ความแตกต่างนี้ชัดเจนที่สุด — เพราะ programmer จัดการหน่วยความจำเอง:
#include <stdio.h>#include <stdlib.h>#include <string.h>
int main() { // เหมือน CHAR(2) — fixed size char country[3]; // 2 chars + null strcpy(country, "TH"); printf("CHAR(2): \"%s\" (sizeof=%zu)\n", country, sizeof(country)); // sizeof = 3 เสมอ ไม่ว่าจะเก็บ "T" หรือ "TH"
// เหมือน VARCHAR(100) — dynamic แต่มีขีดจำกัด char name[101]; // max 100 chars + null strcpy(name, "Ploy"); printf("VARCHAR(100): \"%s\" (sizeof=%zu, strlen=%zu)\n", name, sizeof(name), strlen(name)); // sizeof = 101 (จองตายตัว), strlen = 4 (ใช้จริง)
// เหมือน TEXT — ไม่จำกัดความยาว (ใช้ malloc) char *bio = malloc(10000); // จองตามต้องการ if (bio != NULL) { strcpy(bio, "This is a very long bio..."); printf("TEXT: \"%s\" (strlen=%zu)\n", bio, strlen(bio)); free(bio); // ต้อง free เอง! }
// อันตรายของ fixed size // strcpy(country, "USA"); // Buffer overflow! 3 chars + null > sizeof(3)
return 0;}Key insight:
char[n]=CHAR(n)— จองพื้นที่ตายตัว, overflow ถ้าเกินchar[n]ใหญ่ =VARCHAR(n)— จองเยอะ ใช้จริงน้อยmalloc()=TEXT— จองตามต้องการ แต่ต้องfree()เอง
import pandas as pd
# Python ไม่มี CHAR/VARCHAR/TEXT — ทุกอย่างคือ strcountry = "TH"name = "Ploy Srisuwan"bio = "A very long text..." * 1000
print(type(country)) # <class 'str'>print(type(name)) # <class 'str'> — ชนิดเดียวกัน!print(type(bio)) # <class 'str'> — ชนิดเดียวกัน!
# แต่เวลาส่งไป SQL ต้องคิดถึง type ของ column!# ถ้า SQL column เป็น CHAR(2) แล้วส่ง "THA" → error# ถ้า SQL column เป็น VARCHAR(50) แล้วส่ง string 51 chars → error
# pandas + SQLAlchemy: สร้าง table ที่มี type ชัดเจนfrom sqlalchemy import create_engine, String, Textfrom sqlalchemy.types import CHAR
# engine = create_engine('postgresql://...')# df.to_sql('students', engine, dtype={# 'country_code': CHAR(2),# 'name': String(100), # = VARCHAR(100)# 'bio': Text() # = TEXT# })
# จำลอง validation ใน pandasdf = pd.DataFrame({ 'country_code': ['TH', 'US', 'JPN', 'A'], 'name': ['Ploy', 'John', 'Yuki', 'X' * 101],})
# ตรวจสอบ CHAR(2) ruleinvalid_char = df['country_code'].str.len() != 2print("Invalid CHAR(2):")print(df[invalid_char])# JPN (len=3) และ A (len=1) จะ fail
# ตรวจสอบ VARCHAR(100) ruletoo_long = df['name'].str.len() > 100print("Too long for VARCHAR(100):")print(df[too_long])-- สร้างตาราง example ที่ใช้ทั้ง 3 typesCREATE TABLE profiles ( country_code CHAR(2), -- fixed: 'TH', 'US' name VARCHAR(100), -- variable: ชื่อ bio TEXT -- unlimited: ประวัติ);
-- ทดสอบ CHAR(2)INSERT INTO profiles (country_code) VALUES ('TH'); -- OKINSERT INTO profiles (country_code) VALUES ('T'); -- OK (เติม space: 'T ')-- INSERT INTO profiles (country_code) VALUES ('THA'); -- ERROR: value too long
-- ทดสอบ VARCHAR(100)INSERT INTO profiles (name) VALUES ('Ploy'); -- OK (4 chars)INSERT INTO profiles (name) VALUES (REPEAT('x', 100)); -- OK (100 chars พอดี)-- INSERT INTO profiles (name) VALUES (REPEAT('x', 101)); -- ERROR!
-- ทดสอบ TEXTINSERT INTO profiles (bio) VALUES (REPEAT('Hello ', 10000)); -- OK (60,000 chars)
-- ดูความแตกต่างSELECT country_code, LENGTH(country_code) AS char_len, -- อาจได้ 2 (ตัด trailing space) OCTET_LENGTH(country_code) AS bytes, -- ได้ 2 (bytes จริง) name, LENGTH(name) AS varchar_len, LENGTH(bio) AS text_lenFROM profilesWHERE country_code IS NOT NULL;
-- Performance: CHAR อ่านเร็วกว่า (fixed offset)-- แต่ในยุคปัจจุบัน ความเร็วต่างกันน้อยมาก-- ใช้ CHAR เมื่อ data มีความยาวเท่ากันจริงๆ เท่านั้นเปรียบเทียบ dialect:
| Feature | PostgreSQL | MySQL | SQLite |
|---|---|---|---|
CHAR(n) max | 10,485,760 | 255 | ไม่มี (= TEXT) |
VARCHAR(n) max | 10,485,760 | 65,535 | ไม่มี (= TEXT) |
TEXT max | 1 GB | 4 GB | 2 GB |
VARCHAR vs TEXT ต่างกัน? | แทบไม่ต่าง | ต่าง (indexing) | ไม่ต่างเลย |
แผนภาพตัดสินใจ
Section titled “แผนภาพตัดสินใจ”ถามตัวเอง 3 คำถาม:
-
ความยาวเท่ากันเสมอไหม?
- ใช่ →
CHAR(n)(เช่น country code, currency code) - ไม่ → ไปข้อ 2
- ใช่ →
-
รู้ขีดจำกัดที่เหมาะสมไหม?
- ใช่ →
VARCHAR(n)(เช่น ชื่อ ≤ 100, email ≤ 254) - ไม่ → ไปข้อ 3
- ใช่ →
-
เนื้อหาอาจยาวมากไหม?
- ใช่ →
TEXT(เช่น bio, comment, article)
- ใช่ →