SQLite เป็นฐานข้อมูลเชิงสัมพันธ์แบบฝังที่ทำงานโดยไม่ต้องมีกระบวนการเซิร์ฟเวอร์แยกต่างหาก และจัดเก็บฐานข้อมูลทั้งหมดในไฟล์เดียวบนอุปกรณ์ ด้วยการกำหนดค่าเป็นศูนย์ ขนาดไลบรารีที่เล็ก และการรองรับ SQL อย่างเต็มรูปแบบ SQLite จึงกลายเป็นมาตรฐานสำหรับการจัดเก็บข้อมูลภายในเครื่องในแอปพลิเคชันมือถือ ตามข้อมูลของ SQLite Consortium (2025) DBMS นี้ถูกใช้ในอุปกรณ์มากกว่า 4 พันล้านเครื่อง รวมถึงสมาร์ทโฟนทุกเครื่องบน iOS และ Android
ประเด็นสำคัญ
SQLite คือไลบรารีภาษา C ที่ implement DBMS เชิงสัมพันธ์โดยไม่ต้องมีเซิร์ฟเวอร์เฉพาะ มันถูกฝังลงในแอปพลิเคชันโดยตรง อ่านและเขียนข้อมูลไปยังไฟล์ทั่วไปบนระบบไฟล์ของอุปกรณ์ ขนาดไลบรารีประมาณ 600 KB ทำให้ SQLite เป็นฐานข้อมูล SQL ที่มีคุณสมบัติครบถ้วนและเบาที่สุด
SQLite รองรับมาตรฐาน SQL:1999 ส่วนใหญ่ รวมถึง JOIN, สอบถามย่อย, ทริกเกอร์, วิว, ดัชนี และฟังก์ชันหน้าต่าง ข้อจำกัดเกี่ยวข้องกับ ALTER TABLE (การรองรับจำกัด) และ RIGHT/FULL OUTER JOIN แบบเต็ม อย่างไรก็ตาม สำหรับแอปพลิเคชันมือถือ ฟังก์ชันการทำงานของ SQLite ก็เพียงพอใน 99% ของกรณีการจัดเก็บภายในเครื่อง
ตามแบบสำรวจนักพัฒนาของ Stack Overflow (2025) SQLite เป็นฐานข้อมูลยอดนิยมที่สุดสำหรับโซลูชันแบบฝัง และอยู่ในอันดับสามด้านความนิยมในบรรดา DBMS ทั้งหมดรองจาก MySQL และ PostgreSQL ในการพัฒนาโมบายล์ SQLite ถูกใช้ในทุกแอปพลิเคชัน — โดยตรงหรือผ่านตัวห่อหุ้ม
การกำหนดค่าเป็นศูนย์ — SQLite ไม่ต้องการการติดตั้ง การตั้งค่าสิทธิ์ การสร้างผู้ใช้ หรือการเริ่มบริการ ไลบรารีเชื่อมต่อกับโปรเจกต์ และฐานข้อมูลถูกสร้างขึ้นโดยเรียกใช้ฟังก์ชันเดียว สิ่งนี้ช่วยลดความยุ่งยากในการปรับใช้เมื่อเทียบกับ DBMS แบบไคลเอ็นต์-เซิร์ฟเวอร์ที่ต้องการการติดตั้งเซิร์ฟเวอร์ การกำหนดค่าพอร์ต และการตั้งค่าผู้ใช้
ไฟล์ฐานข้อมูล SQLite เป็นไฟล์ข้ามแพลตฟอร์มทั่วไปที่สามารถคัดลอก วิเคราะห์ ส่งผ่านเครือข่าย หรือกู้คืนจากสำเนาสำรองได้ รูปแบบไฟล์มีความเสถียรในระดับ API: ไฟล์ SQLite 3 ที่สร้างในปี 2004 สามารถเปิดได้ด้วยไลบรารีเวอร์ชันปัจจุบัน ซึ่งรับประกันความเข้ากันได้ของข้อมูลในระยะยาว
สถาปัตยกรรม ของ SQLite ประกอบด้วยเครื่องเสมือนแปดเครื่อง: Tokenizer, Parser, Code Generator, VM, B-Tree, Pager, OS Interface และ Utilities คำสั่ง SQL จะผ่าน Tokenizer (การแบ่งเป็นโทเค็น), Parser (การสร้าง AST), Code Generator (การแปลงเป็นไบต์โค้ด) และดำเนินการบนเครื่องเสมือน ซึ่งอ่านหน้าข้อมูลผ่าน B-Tree และ Pager
SQLite ใช้ B-Tree สำหรับจัดเก็บตารางและดัชนี แต่ละตารางถูกจัดเก็บเป็น B-Tree แยกต่างหาก โดยโหนดใบมีแถวข้อมูล ดัชนีก็ถูกจัดเก็บเป็น B-Tree เช่นกัน แต่มีคีย์อยู่ในใบ Pager จัดการการโหลดหน้า (ค่าเริ่มต้น 4096 ไบต์) จากไฟล์ไปยังหน่วยความจำ โดยให้ธุรกรรม ACID ผ่านวารสารหรือ WAL
WAL (Write-Ahead Logging) เป็นโหมดที่แนะนำสำหรับแอปพลิเคชันมือถือ การเปลี่ยนแปลงจะถูกเขียนไปยังไฟล์ WAL แยกต่างหากก่อน จากนั้นจึงถูกย้ายไปยังฐานข้อมูลหลักเป็นระยะ WAL อนุญาตให้อ่าน (ข้อมูลเก่า) และเขียน (ผ่าน WAL) พร้อมกันในฐานข้อมูล ซึ่งช่วยปรับปรุงประสิทธิภาพของแอปพลิเคชันแบบหลายเธรด วารสารมาตรฐาน (rollback journal) จะบล็อกการอ่านระหว่างการเขียน
| พารามิเตอร์ | Rollback Journal | WAL (Write-Ahead Logging) |
|---|---|---|
| การอ่านระหว่างเขียน | ถูกบล็อก | อนุญาต (อ่านข้อมูลเก่า) |
| ประสิทธิภาพการเขียน | ปานกลาง | สูง (เขียนตามลำดับไปยัง WAL) |
| การใช้ดิสก์ | น้อยกว่า (เฉพาะวารสาร Rollback) | มากกว่า (WAL + ฐานข้อมูลหลัก) |
| การกู้คืนจากขัดข้อง | ย้อนกลับไปยังจุดตรวจสอบล่าสุด | กู้คืนจาก WAL (ไม่สูญเสียข้อมูล) |
| คำแนะนำ | สำหรับสถานการณ์เธรดเดียว | สำหรับแอปพลิเคชันมือถือทั่วไป |
การสลับระหว่างโหมดทำได้ด้วยคำสั่ง SQL เดียว: PRAGMA journal_mode=WAL สำหรับแอปพลิเคชันมือถือที่มีการซิงค์พื้นหลังและเธรด UI ที่อ่านข้อมูลพร้อมกัน WAL ให้ประสิทธิภาพที่ดีกว่าและไม่มีการล็อกอินเทอร์เฟซ
SQLite ไม่ใช่ตัวเลือกเดียวสำหรับการจัดเก็บข้อมูลภายในเครื่อง แต่มีความหลากหลายมากที่สุด Realm มีความเร็วในการเข้าถึงวัตถุในหน่วยความจำโดยตรงสูงกว่า แต่ใช้รูปแบบ NoSQL ของตัวเองและมีขนาดไลบรารีใหญ่กว่า Core Data บน iOS เป็นเลเยอร์ ORM บน SQLite ที่เพิ่มการจัดการกราฟวัตถุและการยกเลิกการดำเนินการ
สำหรับแอปพลิเคชันส่วนใหญ่ SQLite ยังคงเป็นตัวเลือกที่เหมาะสมที่สุดเนื่องจากประสิทธิภาพที่คาดเดาได้ ไม่มีการล็อกผู้จำหน่าย และความเสถียรที่ผ่านการทดสอบตามกาลเวลา Realm และ Core Data เหมาะสมในโปรเจกต์ที่มีกราฟวัตถุซับซ้อน คำสั่งแบบรีแอกทีฟ หรือข้อกำหนดการซิงค์ระหว่างอุปกรณ์
| คุณลักษณะ | SQLite | Realm | Core Data |
|---|---|---|---|
| ประเภทฐานข้อมูล | เชิงสัมพันธ์ (SQL) | NoSQL (เชิงวัตถุ) | ORM (บน SQLite) |
| ขนาดไลบรารี | ~600 KB | ~4 MB | รวมอยู่ใน SDK ของ Apple |
| ประสิทธิภาพ | ปานกลาง | สูง (วัตถุในหน่วยความจำ) | ปานกลาง (ค่าใช้จ่าย ORM) |
| แพลตฟอร์ม | iOS, Android, เว็บ, เดสก์ท็อป | iOS, Android, Node.js | iOS, macOS |
| การล็อกผู้จำหน่าย | ไม่มี (มาตรฐานเปิด) | ปานกลาง (รูปแบบเฉพาะ) | สูง (Apple เท่านั้น) |
การเลือกระหว่าง SQLite, Realm และ Core Data ขึ้นอยู่กับแพลตฟอร์ม ข้อกำหนดโมเดลวัตถุ และกลยุทธ์การซิงค์ สำหรับโปรเจกต์ ข้ามแพลตฟอร์ม (KMP, Flutter) SQLite ยังคงเป็นตัวเลือกสากลเพียงตัวเดียวที่ทำงานบนทุกแพลตฟอร์มเป้าหมายโดยไม่ต้องเปลี่ยนแปลงโมเดลข้อมูล
Room คือไลบรารีจาก Android Jetpack ที่ให้เลเยอร์ ORM บน SQLite Room สร้างคำสั่ง SQL โดยอัตโนมัติจากอินเทอร์เฟซ DAO ที่มีคำอธิบายประกอบ ตรวจสอบความถูกต้องของคำสั่งในเวลาคอมไพล์ และรองรับการย้ายฐานข้อมูลเมื่อสคีมาเปลี่ยนแปลง Room เป็นวิธีที่แนะนำในการทำงานกับ SQLite บน Android
SQLiteOpenHelper คือ API ระดับต่ำสำหรับการจัดการ SQLite โดยตรงโดยไม่ต้องมี ORM คลาสนี้จัดการการสร้าง การเปิด และการอัปเกรดฐานข้อมูล SQLiteOpenHelper เหมาะสำหรับโปรเจกต์ที่มีคำสั่ง SQL ง่ายๆ หรือเมื่อต้องการควบคุมตรรกะ SQL อย่างเต็มที่โดยไม่ต้องมีสิ่งที่เป็นนามธรรมของ Room
Entity ใน Room จะมีคำอธิบายประกอบด้วย @Entity และ DAO ด้วย @Dao Room แปลงเมธอดที่มีคำอธิบายประกอบเป็นคำสั่ง SQL: @Insert สร้าง INSERT, @Query สร้าง SELECT ด้วย SQL ที่ระบุ การย้ายข้อมูลจะถูกเพิ่มผ่าน Migration โดยระบุเวอร์ชันสคีมาเก่าและใหม่ Room ตรวจสอบ SQL ในเวลาคอมไพล์ ซึ่งช่วยขจัดข้อผิดพลาดทางไวยากรณ์ใน production
@Entity
data class User(
@PrimaryKey val id: Long,
val name: String,
@ColumnInfo(name = "created_at")
val createdAt: Long
)
@Dao
interface UserDao {
@Query("SELECT * FROM user ORDER BY name ASC")
suspend fun getAllUsers(): List<User>
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insertUser(user: User)
@Query("DELETE FROM user WHERE id = :id")
suspend fun deleteUser(id: Long)
}
Room สร้างการ implement UserDao_Impl โดยอัตโนมัติ ซึ่งมีคำสั่ง SQLite ในรันไทม์ผ่าน RoomDatabase ภายใน ด้วยโครูทีน (suspend) เมธอด DAO จะทำงานแบบอะซิงโครนัสบนเธรดพื้นหลังโดยไม่บล็อก UI ชนิดส่งคืน Flow ใน @Query จะอัปเดตผลลัพธ์โดยอัตโนมัติเมื่อตารางเปลี่ยนแปลง
FMDB คือตัวห่อหุ้ม Objective-C บน SQLite C API ซึ่งในอดีตเป็นไลบรารียอดนิยมแรกสำหรับ iOS โดยให้วัตถุ FMDatabase และ FMResultSet สำหรับดำเนินการคำสั่งและรับผลลัพธ์ FMDB เรียบง่ายและน้อยชิ้น แต่ไม่รองรับโครงสร้างเฉพาะของ Swift — ตัวเลือก, Codable, async/await
GRDB คือไลบรารี Swift สมัยใหม่สำหรับทำงานกับ SQLite โดยให้ API ที่ปลอดภัยชนิด, การรองรับ Codable, Combine Publishers, async/await, การย้ายข้อมูล และการสังเกตการเปลี่ยนแปลงแบบเรียลไทม์ GRDB เป็นที่นิยมสำหรับโปรเจกต์ Swift ใหม่เนื่องจากการรวมเข้ากับ Swift Concurrency อย่างสมบูรณ์และความสามารถในการอ่านโค้ดที่ดีกว่า
GRDB กำหนดตารางผ่านคลาส Record ที่สอดคล้องกับโพรโทคอล FetchableRecord และ TableRecord คำสั่งถูกเขียนใน Swift ด้วยไวยากรณ์ที่ปลอดภัยชนิดแทนที่จะเป็น SQL ดิบ GRDB ยังรองรับ DatabaseMigrator สำหรับการกำหนดเวอร์ชันสคีมาและการย้ายข้อมูลระหว่างเวอร์ชันแอป
struct User: Codable, FetchableRecord, TableRecord {
var id: Int64
var name: String
var createdAt: Date
}
let dbPool = try DatabasePool(path: dbPath)
var migrator = DatabaseMigrator()
migrator.registerMigration("v1") { db in
try db.create(table: "user") { t in
t.autoIncrementedPrimaryKey("id")
t.column("name", .text).notNull()
t.column("createdAt", .datetime).notNull()
}
}
let users = try await dbPool.read { db in
try User.order(Column("name")).fetchAll(db)
}
DatabasePool ใช้โหมด WAL ของ SQLite สำหรับการอ่านพร้อมกัน ผู้อ่านหลายคนสามารถเข้าถึงฐานข้อมูลพร้อมกันได้ในขณะที่ผู้เขียนคนเดียวอัปเดตข้อมูลผ่าน WAL GRDB จัดการการเชื่อมต่อและธุรกรรมโดยอัตโนมัติ ให้การเข้าถึงฐานข้อมูลที่ปลอดภัยเธรดจากเธรดใดก็ได้โดยไม่ต้องซิงค์ด้วยตนเอง
ดัชนี เป็นวิธีที่มีประสิทธิภาพที่สุดในการเร่งคำสั่ง SQLite ดัชนีถูกสร้างบนคอลัมน์ที่ใช้ใน WHERE, JOIN และ ORDER BY สำหรับตารางที่มี 100000 เรกคอร์ด การค้นหาด้วยคอลัมน์ที่มีดัชนีใช้เวลาเป็นมิลลิวินาทีแทนที่จะเป็นวินาที อย่างไรก็ตาม ดัชนีทำให้ INSERT และ UPDATE ช้าลง ดังนั้นจำนวนดัชนีควรสมดุลกับความถี่ในการเขียน
การแทรกแบบกลุ่ม (batch insert) ภายในธุรกรรมเดียวช่วยเร่งการโหลดข้อมูลจำนวนมากได้อย่างรุนแรง การแทรก 1000 เรกคอร์ดทีละรายการทำให้เกิดค่าใช้จ่ายประมาณ 1 วินาที เรกคอร์ด 1000 รายการเดียวกันในธุรกรรมเดียวใช้เวลาประมาณ 5-10 มิลลิวินาที ความแตกต่างอธิบายได้จากการที่ INSERT แต่ละรายการสร้างธุรกรรมใหม่พร้อมการเขียนดิสก์แบบซิงโครนัส
PRAGMA คือคำสั่ง SQLite สำหรับกำหนดค่าพฤติกรรมของไลบรารี PRAGMA การปรับแต่งที่สำคัญ: PRAGMA synchronous=NORMAL (ลดความถี่ fsync), PRAGMA cache_size=-8000 (จัดสรรแคช 8 MB), PRAGMA temp_store=MEMORY (ตารางชั่วคราวในหน่วยความจำ) สำหรับแอปพลิเคชันมือถือที่มีปริมาณข้อมูลมาก การรวม PRAGMA เหล่านี้ช่วยเร่งคำสั่งได้ 2-3 เท่า
การปรับแต่งที่สำคัญอีกอย่างคือ การคอมไพล์ล่วงหน้า ของคำสั่ง SQL (prepared statements) หากคำสั่งถูกดำเนินการซ้ำๆ (เช่น การแทรก 10000 แถว) การคอมไพล์ SQL ครั้งเดียวแล้วใช้คำสั่งซ้ำจะลดภาระ CPU ลง 30-50% Room และ GRDB จะแคช prepared statements โดยอัตโนมัติ แต่เมื่อใช้ SQLite C API โดยตรง การคอมไพล์ต้องทำด้วยตนเอง
class UserRepository(private val db: RoomDatabase) {
suspend fun insertBatch(users: List<User>) {
db.withTransaction {
users.chunked(500).forEach { batch ->
batch.forEach { user ->
insertUser(user)
}
}
}
}
}
การแทรกแบบกลุ่มด้วย withTransaction รับประกันว่าการดำเนินการ INSERT ทั้งหมดจะดำเนินการภายในธุรกรรมเดียว การแบ่งเป็นชุดย่อย (chunked) ป้องกันไม่ให้ธุรกรรมเดียวใหญ่เกินไป ซึ่งอาจบล็อกเธรดอื่นเป็นเวลานาน สำหรับการซิงค์พื้นหลัง ขนาดชุดย่อย 500 เรกคอร์ดให้ความสมดุลที่เหมาะสมที่สุดระหว่างความเร็วและการตอบสนองของ UI
คำถามที่พบบ่อย
ใช่ SQLite รองรับการเข้าถึงแบบหลายเธรดในโหมด WAL หลายเธรดสามารถอ่านข้อมูลพร้อมกันได้ แต่มีเพียงเธรดเดียวเท่านั้นที่สามารถเขียนได้ Room และ GRDB จัดการการซิงค์โดยอัตโนมัติ ในโหมด rollback journal (ค่าเริ่มต้น) ฐานข้อมูลจะถูกล็อกอย่างสมบูรณ์ระหว่างการดำเนินการเขียนใดๆ
ข้อจำกัด ของ SQLite คือ 281 TB (สูงสุดตามทฤษฎี) ในทางปฏิบัติ ขนาดฐานข้อมูลถูกจำกัดโดยหน่วยความจำที่มีอยู่ในอุปกรณ์ สำหรับแอปพลิเคชันมือถือ ขนาดที่สบายคือสูงสุด 1-2 GB ฐานข้อมูลที่ใหญ่กว่า 2 GB จะทำให้การสำรองข้อมูล การอัปเดตผ่าน App Store ช้าลง และเพิ่มการใช้ RAM
SQLite ไม่ได้เข้ารหัสข้อมูลโดยค่าเริ่มต้น — โปรเซสใดๆ ที่เข้าถึงไฟล์ได้ก็สามารถอ่านข้อมูลได้ สำหรับการเข้ารหัส ให้ใช้ SQLCipher (ส่วนขยายที่มี AES-256), Room กับ EncryptedDatabase (Android) หรือ Encrypted Core Data บน iOS การเข้ารหัสเพิ่มค่าใช้จ่าย 5-15% ในการดำเนินการอ่านและเขียนข้อมูล
SQLite คือไลบรารีแบบฝังที่ไม่ต้องการกระบวนการเซิร์ฟเวอร์ MySQL คือ DBMS แบบไคลเอ็นต์-เซิร์ฟเวอร์ที่มีเซิร์ฟเวอร์แยกต่างหาก ผู้ใช้ สิทธิ์การเข้าถึง และโพรโทคอลเครือข่าย SQLite จัดเก็บฐานข้อมูลในไฟล์เดียว MySQL จัดเก็บในหลายไฟล์ที่จัดการโดยเซิร์ฟเวอร์ SQLite เรียบง่ายและเบากว่า MySQL มีประสิทธิภาพและปรับขนาดได้มากกว่า
สำหรับการย้ายข้อมูล SQLite ให้ใช้ ALTER TABLE (การเพิ่มคอลัมน์) หรือสร้างตารางใหม่พร้อมการถ่ายโอนข้อมูลและการลบตารางเก่า Room ทำให้กระบวนการนี้เป็นอัตโนมัติผ่านคลาส Migration: ระบุ startVersion, endVersion และคำสั่ง SQL สำหรับการเปลี่ยนแปลงสคีมา GRDB และ FMDB มี DatabaseMigrator ที่คล้ายกัน
สรุป
เราจะพัฒนาแอปพลิเคชันบนมือถือแบบครบวงจร
IT Sectr สร้างแอปพลิเคชัน iOS และ Android สำหรับสตาร์ทอัพและธุรกิจตั้งแต่ปี 2017 เราจะให้คำแนะนำและเสนอวิธีแก้ปัญหาที่ดีที่สุดแก่คุณ
อ่านเพิ่มเติม