Realm คือฐานข้อมูล NoSQL เชิงวัตถุสำหรับมือถือที่พัฒนาขึ้นเป็นทางเลือกแทน SQLite และ Core Data สำหรับ iOS และ Android ข้อมูลถูกจัดเก็บในรูปแบบของตนเองพร้อมการเข้าถึงวัตถุในหน่วยความจำโดยตรง ซึ่งให้ความเร็วในการอ่านและเขียนสูง ด้วยการแจ้งเตือนแบบรีแอกทีฟ การซิงค์อัตโนมัติผ่าน Realm Sync และโมเดลข้อมูลข้ามแพลตฟอร์ม ทำให้ Realm ถูกใช้บนอุปกรณ์มากกว่า 1 พันล้านเครื่อง (ข้อมูล MongoDB, 2025)
ประเด็นสำคัญ
Realm คือฐานข้อมูลเชิงวัตถุที่สร้างขึ้นเฉพาะสำหรับแอปพลิเคชันมือถือ แตกต่างจาก SQLite ตรงที่ Realm ไม่ใช้ SQL หรือโมเดลเชิงสัมพันธ์ — ข้อมูลถูกจัดเก็บเป็นวัตถุมีชีวิต (Live Objects) ซึ่งเข้าถึงได้โดยตรงโดยไม่มีชั้น ORM กลาง นักพัฒนาทำงานกับวัตถุภาษาทั่วไป (Swift, Kotlin, Dart) ที่ถูกบันทึกลงในฐานข้อมูลโดยอัตโนมัติ
Realm ปรากฏในปี 2014 ในฐานะสตาร์ทอัพ Realm Inc. และในปี 2019 ถูกซื้อกิจการโดย MongoDB Inc. ตั้งแต่นั้นมา Realm ได้รับการพัฒนาเป็น MongoDB Realm ซึ่งเป็นส่วนหนึ่งของแพลตฟอร์ม Atlas Device Sync แบบครบวงจรสำหรับการซิงค์ข้อมูลมือถือ ฐานข้อมูลท้องถิ่นพื้นฐานของ Realm ยังคงฟรีและโอเพนซอร์ส (สัญญาอนุญาต Apache 2.0) ในขณะที่ Realm Sync (การซิงค์บนคลาวด์) เผยแพร่ผ่านการสมัครสมาชิก
ตามรายงาน MongoDB Developer Report (2025), Realm ถูกใช้ใน 15% ของแอปพลิเคชันมือถือเป็นพื้นที่จัดเก็บท้องถิ่นหลัก กรณีการใช้งานหลักคือแอปพลิเคชันที่มีโหมดออฟไลน์ โมเดลวัตถุที่ซับซ้อน และความต้องการซิงค์ระหว่างอุปกรณ์ ซึ่ง Realm เหนือกว่า SQLite ในด้านความเร็วในการพัฒนาและความสะดวกในการทำงานกับวัตถุ
Live Objects — วัตถุ Realm แต่ละตัวเชื่อมต่อกับดิสก์ผ่านไฟล์ที่แมปหน่วยความจำ (memory-mapped file) การเปลี่ยนวัตถุในเธรดใดๆ จะสะท้อนทันทีในเธรดอื่นๆ ทั้งหมดโดยไม่ต้องแจ้งเตือนด้วยตนเอง ส่วนติดต่อผู้ใช้จะถูกวาดใหม่โดยอัตโนมัติเมื่อข้อมูลเปลี่ยนแปลงผ่านการแจ้งเตือนของ Realm Zero-copy — Realm ไม่คัดลอกข้อมูลจากฐานข้อมูลไปยังวัตถุ วัตถุคือข้อมูลในหน่วยความจำ
แกนกลางของ Realm เขียนด้วยภาษา C++ และใช้ B+ Tree สำหรับการจัดทำดัชนีข้อมูล แตกต่างจาก SQLite ที่แต่ละแถวเป็นเรคคอร์ดในตารางเชิงสัมพันธ์ Realm จัดเก็บวัตถุเป็นโหนดในโครงสร้างกราฟพร้อมการอ้างอิงโดยตรงระหว่างกัน (forward pointers) ความสัมพันธ์ระหว่างวัตถุไม่ใช่คีย์ต่างประเทศแต่เป็นพอยน์เตอร์โดยตรง ซึ่งช่วยลดความจำเป็นในการดำเนินการ JOIN
ไฟล์ Realm (นามสกุล .realm) เป็น การแมปหน่วยความจำ (memory-mapped) — ระบบปฏิบัติการจัดการโหลดหน้าไฟล์ลงในหน่วยความจำเมื่อมีการเข้าถึงด้วยตนเอง สิ่งนี้ช่วยให้ Realm ทำงานกับฐานข้อมูลที่ใหญ่กว่า RAM ที่มีอยู่ และให้เวลาแฝงในการอ่านในระดับโครงสร้างข้อมูลภาษาดั้งเดิม (Swift Array หรือ Kotlin List) สำหรับข้อมูลที่พอดีกับ RAM
ไฟล์ที่แมปหน่วยความจำ — เทคโนโลยีหลักของ Realm แทนที่จะคัดลอกข้อมูลจากไฟล์ฐานข้อมูลไปยังวัตถุภาษา (เหมือนที่ SQLite ทำผ่าน sqlite3_step + sqlite3_column_*) Realm จะแมปไฟล์ฐานข้อมูลโดยตรงลงในพื้นที่ที่อยู่ของกระบวนการ วัตถุภาษาเป็นเพียงพอยน์เตอร์ไปยังข้อมูลในหน่วยความจำที่แมปไว้ การเปลี่ยนวัตถุจะปรับเปลี่ยนฐานข้อมูลบนดิสก์โดยไม่ต้องเรียก save แยกต่างหาก
| คุณลักษณะ | Realm (zero-copy) | SQLite (การคัดลอก) |
|---|---|---|
| การอ่าน | เข้าถึงหน่วยความจำโดยตรง (นาโนวินาที) | คัดลอกไปยังวัตถุ (ไมโครวินาที) |
| การเขียน | เขียนทันทีไปยังไฟล์ memory-mapped | save() ด้วยธุรกรรม SQL INSERT/UPDATE |
| ความสัมพันธ์ | พอยน์เตอร์โดยตรง (forward pointers) | คีย์ต่างประเทศ + JOIN |
| การใช้หน่วยความจำ | ไฟล์ + แคชหน้า OS | วัตถุ + แคชหน้า SQLite |
| วัตถุมีชีวิต | ใช่ (อัปเดตอัตโนมัติ) | ไม่ (ต้องการ fetch ใหม่) |
การใช้หน่วยความจำ สูงกว่าใน Realm เมื่ออ่านข้อมูลอย่างกระตือรือร้น (ไฟล์ทั้งหมดหรือส่วนใหญ่ถูกแมปในหน่วยความจำ) แต่ต่ำกว่าเมื่อดำเนินการเขียนเนื่องจากไม่ต้องการการจัดสรรหน่วยความจำสำหรับสำเนาวัตถุ สำหรับฐานข้อมูลขนาดสูงสุด 1 GB บนอุปกรณ์มือถือ วิธีการแมปหน่วยความจำให้ประสิทธิภาพโดยรวมดีกว่า SQLite ที่มีการคัดลอกกลาง
SQLite คือระบบจัดการฐานข้อมูลเชิงสัมพันธ์พร้อม SQL และธุรกรรม ACID Realm คือฐานข้อมูล NoSQL เชิงวัตถุพร้อมการเข้าถึงแบบแมปหน่วยความจำ Core Data คือชั้น ORM ของ Apple บน SQLite แต่ละวิธีทั้งสามมีขอบเขตการใช้งานและจุดแข็งของตนเอง Realm ชนะในด้านความเร็วการเข้าถึงวัตถุโดยตรงและการตอบสนอง SQLite ในด้านความอเนกประสงค์และความสมบูรณ์ Core Data ในด้านการรวมกับระบบนิเวศของ Apple
ประสิทธิภาพการอ่านของ Realm สูงกว่า SQLite 10-50% เนื่องจากการเข้าถึงแบบ zero-copy Realm ยังเร็วกว่าในการเขียนเนื่องจากไม่ต้องวิเคราะห์ไวยากรณ์ SQL และการปรับเปลี่ยนหน้าแบบแมปหน่วยความจำโดยตรง อย่างไรก็ตาม Realm อาจใช้ RAM มากขึ้นเมื่อทำงานกับฐานข้อมูลขนาดใหญ่ (>500 MB) เนื่องจากไฟล์ถูกแมปทั้งหมดในพื้นที่ที่อยู่
| เกณฑ์ | Realm | SQLite | Core Data |
|---|---|---|---|
| ประเภท | ฐานข้อมูลวัตถุ NoSQL | ระบบจัดการฐานข้อมูลเชิงสัมพันธ์ (SQL) | ORM บน SQLite |
| ความเร็วในการอ่าน | สูง (zero-copy) | ปานกลาง | ปานกลาง (ค่าใช้จ่าย ORM) |
| การตอบสนอง | Live Objects (ในตัว) | ต้องการตัวห่อ (Room/GRDB) | NSFetchedResultsController |
| การซิงค์ | Realm Sync (MongoDB Atlas) | ต้องการการ implement เอง | NSPersistentCloudKitContainer |
| แพลตฟอร์ม | iOS, Android, Flutter, RN, Node.js | iOS, Android, Web, เดสก์ท็อป | เฉพาะ iOS/macOS |
| ขนาดไลบรารี | ~4 MB | ~600 KB | ในตัวใน SDK |
การเลือกระหว่าง Realm และ SQLite มักขึ้นอยู่กับลำดับความสำคัญ: ความเร็วในการพัฒนาและการตอบสนอง (Realm) เทียบกับการควบคุมและความอเนกประสงค์ (SQLite) Realm เหมาะอย่างยิ่งสำหรับ MVP และต้นแบบที่โมเดลข้อมูลเปลี่ยนแปลงบ่อยและการอัปเดตส่วนติดต่อผู้ใช้แบบสดอย่างรวดเร็วเป็นสิ่งสำคัญ SQLite/Room เหมาะกว่าสำหรับผลิตภัณฑ์ที่เติบโตเต็มที่ซึ่งมีปริมาณข้อมูลจำนวนมากและคำสั่งค้นหาเชิงวิเคราะห์ที่ซับซ้อน
Realm Kotlin SDK คือไลบรารีอย่างเป็นทางการสำหรับ Android เขียนด้วย Kotlin (ไม่ใช่ตัวห่อเหนือ Java SDK) โมเดลข้อมูลถูกกำหนดผ่านคลาสที่สืบทอดจาก RealmObject พร้อมคำอธิบายประกอบ @PrimaryKey สำหรับตัวระบุที่ไม่ซ้ำกัน Realm Kotlin รองรับ Kotlin Coroutines, Flow และ KSP (Kotlin Symbol Processing) สำหรับการสร้างโค้ดในเวลาคอมไพล์
RealmQuery ให้ API ที่ปลอดภัยชนิดสำหรับการกรองโดยไม่ต้องใช้ SQL คำสั่งค้นหาถูกสร้างผ่านลูกโซ่เมธอด: query → filter → sort → find ผลลัพธ์สามารถส่งคืนเป็นรายการ (โหลดในหน่วยความจำ) หรือเป็น Flow (สตรีมรีแอกทีฟที่อัปเดตเมื่อข้อมูลเปลี่ยนแปลง) Realm Kotlin ยังรองรับวัตถุที่ซ้อนกันและรายการ (RealmList)
โมเดลข้อมูล Realm ถูกกำหนดเป็น data class ที่ implement อินเทอร์เฟซ RealmObject ฟิลด์ _id ถูกทำเครื่องหมายด้วย @PrimaryKey สำหรับการระบุที่ไม่ซ้ำกัน ความสัมพันธ์แบบหนึ่งต่อกลุ่มถูก implement ผ่าน RealmList — รายการของ RealmObject อื่น การดำเนินการเขียนทั้งหมด (สร้าง, อัปเดต, ลบ) จะดำเนินการภายในบล็อกธุรกรรม write
class Project : RealmObject {
@PrimaryKey
var _id: ObjectId = ObjectId().generate()
var name: String = ""
var tasks: RealmList<Task> = realmListOf()
}
class Task : RealmObject {
@PrimaryKey
var _id: ObjectId = ObjectId().generate()
var title: String = ""
var isComplete: Boolean = false
}
val config = Realm.Configuration.Builder(
schema = setOf(Project::class, Task::class)
).build()
val realm = Realm.open(config)
realm.write { transactionRealm ->
val project = copyToRealm(Project().apply {
name = "Mobile App"
})
project.tasks.add(copyToRealm(Task().apply {
title = "Design UI"
}))
}
val projects: Flow<RealmResults<Project>> =
realm.query<Project>()
.sort(Project::name, Sort.ASCENDING)
.asFlow()
คำสั่งค้นหาที่ส่งคืน Flow จะปล่อยผลลัพธ์ใหม่โดยอัตโนมัติเมื่อมีการเปลี่ยนแปลงข้อมูลใดๆ ใน Realm: การเพิ่ม, อัปเดตหรือลบ Project หรือ Task วิธีการ Flow เข้ากันได้อย่างสมบูรณ์แบบกับ Compose: collectAsState() ใน ViewModel จะประกอบส่วนติดต่อผู้ใช้ใหม่โดยอัตโนมัติเมื่อข้อมูลเปลี่ยนแปลงโดยไม่ต้องอัปเดตอะแดปเตอร์รายการด้วยตนเองหรือใช้ LiveData
Realm Swift SDK ให้ API Swift ดั้งเดิมพร้อมการสนับสนุน async/await, Combine Publishers และ Swift Concurrency โมเดลข้อมูลถูกกำหนดเป็นคลาสที่สืบทอดจาก Object โดยใช้ @Persisted สำหรับคุณสมบัติ Realm Swift อัปเดตวัตถุโดยอัตโนมัติเมื่อมีการเปลี่ยนแปลง และการแจ้งเตือน (NotificationToken) อนุญาตให้สมัครรับการเปลี่ยนแปลงของวัตถุหรือคอลเลกชันแต่ละรายการ
@ObservedRealmObject และ @ObservedResults คือ Property Wrapper สำหรับ SwiftUI ที่วาด View ใหม่โดยอัตโนมัติเมื่อข้อมูล Realm เปลี่ยนแปลง @ObservedResults ทำงานกับผลลัพธ์คำสั่งค้นหา @ObservedRealmObject ทำงานกับวัตถุเฉพาะ คุณสมบัติทั้งสองยกเลิกการสมัครเมื่อ View ถูกดีอินิเชียลไลซ์
การรวม SwiftUI Realm เป็นหนึ่งในจุดแข็งของ SDK Property Wrapper @ObservedResults เชื่อมโยงคำสั่งค้นหา Realm กับการแสดงผลใน SwiftUI เมื่องานใดๆ เปลี่ยนแปลง SwiftUI จะประกอบรายการใหม่โดยอัตโนมัติ realm.writeAsync ดำเนินธุรกรรมบนเธรดพื้นหลังโดยไม่บล็อกส่วนติดต่อผู้ใช้
import RealmSwift
class TaskItem: Object, Identifiable {
@Persisted(primaryKey: true) var _id: ObjectId
@Persisted var title: String = ""
@Persisted var isDone: Bool = false
@Persisted var priority: Int = 0
}
struct TaskListView: View {
@ObservedResults(TaskItem.self,
sortDescriptor: SortDescriptor(["priority"]))
var tasks
var body: some View {
List {
ForEach(tasks) { task in
TaskRow(task: task)
}
}
Button("Add Task") {
let realm = try! Realm()
try! realm.write {
realm.add(TaskItem(value: ["title": "New task"]))
}
}
}
}
@ObservedResults จัดการวงจรชีวิตของคำสั่งค้นหา Realm โดยอัตโนมัติ: เมื่อสร้าง View จะสร้างการสมัครรับการเปลี่ยนแปลง เมื่อถูกทำลายจะถูกยกเลิก Property Wrapper ยอมรับ predicate ที่เป็นตัวเลือก (NSPredicate) และ descriptor การเรียงลำดับ สิ่งนี้ช่วยลดความจำเป็นในการเขียนคำขอ fetch ด้วยตนเอง สร้าง ViewModel และสมัครรับการแจ้งเตือน Realm
แอปพลิเคชันออฟไลน์ — Realm เหมาะสำหรับสถานการณ์ที่ข้อมูลต้องพร้อมใช้งานโดยไม่ต้องใช้อินเทอร์เน็ต การซิงค์ในตัว (Realm Sync กับ MongoDB Atlas) แก้ไขข้อขัดแย้งโดยอัตโนมัติเมื่อเชื่อมต่อกับเครือข่าย แอปยังคงทำงานกับข้อมูลท้องถิ่น และการซิงค์พื้นหลังจะอัปเดตข้อมูลเมื่อมีการเชื่อมต่อ
ส่วนติดต่อแบบรีแอกทีฟ — Live Objects และการแจ้งเตือน Flow/Combine ทำให้ Realm เป็นตัวเลือกที่สะดวกสำหรับแอปพลิเคชันที่มีข้อมูลที่อัปเดตบ่อย: แชท, ฟีดงาน, เอกสารร่วมมือ ส่วนติดต่อผู้ใช้อัปเดตโดยอัตโนมัติเมื่อเพิ่ม เปลี่ยนแปลง หรือลบข้อมูลโดยไม่ต้องเรียก reloadData หรือ invalidate ด้วยตนเอง
โปรเจกต์ข้ามแพลตฟอร์ม — Realm รองรับ Kotlin Multiplatform (KMP), Flutter, React Native และ Xamarin โมเดลข้อมูลถูกกำหนดครั้งเดียวและใช้บนทุกแพลตฟอร์ม สิ่งนี้ลดการทำซ้ำโค้ดและรับประกันความสอดคล้องของสคีมาระหว่างแอปพลิเคชัน iOS และ Android ที่มีตรรกะธุรกิจร่วมกัน
Realm Sync คือบริการคลาวด์ที่สร้างใน MongoDB Atlas แอปพลิเคชันซิงค์ข้อมูลโดยอัตโนมัติระหว่างอุปกรณ์ของผู้ใช้และเซิร์ฟเวอร์ ข้อขัดแย้งถูกแก้ไขด้วยกลยุทธ์ “last write wins” หรือผ่านฟังก์ชันแก้ไขข้อขัดแย้งที่กำหนดเองบนเซิร์ฟเวอร์ Realm Sync รองรับการซิงค์บางส่วน (ชุดย่อยของข้อมูล) เพื่อลดปริมาณการรับส่งข้อมูล
class SyncRepository {
private val app = App(
AppConfiguration(
appId = "my-realm-app-id"
)
)
suspend fun syncData() {
val user = app.login(Credentials.anonymous())
val config = SyncConfiguration.Builder(
user, setOf(Project::class)
).build()
val syncedRealm = Realm.open(config)
// การซิงค์อัตโนมัติกำลังทำงาน
}
}
SyncConfiguration กำหนดค่าการเชื่อมต่อไปยัง MongoDB Atlas และกำหนดชุดของโมเดลที่จะซิงค์ หลังจากผู้ใช้รับรองความถูกต้อง Realm จะโหลดข้อมูลจากคลาวด์โดยอัตโนมัติและรวมเข้ากับการเปลี่ยนแปลงท้องถิ่น การซิงค์ทำงานบนเธรดพื้นหลังและไม่ต้องการการเรียกด้วยตนเอง — เพียงสร้างอินสแตนซ์ Realm ด้วย SyncConfiguration
คำถามที่พบบ่อย
ใช่ ฐานข้อมูลท้องถิ่น Realm ฟรีอย่างสมบูรณ์ (สัญญาอนุญาต Apache 2.0) Realm Sync (การซิงค์บนคลาวด์) ผ่าน MongoDB Atlas เป็นบริการแบบชำระเงินที่รวมอยู่ในการสมัครสมาชิก Atlas Device Sync ระดับฟรีของ Atlas รวมข้อมูล 500 MB แรกและ 1 ล้านรายการต่อเดือน
ใช่ การย้าย สามารถทำได้โดยการส่งออกข้อมูลจาก SQLite เป็น JSON และนำเข้าไปยัง Realm ในการโหลดแอปพลิเคชันครั้งแรก สำหรับปริมาณมาก ให้ใช้การย้ายแบบสตรีมมิ่ง: เขียนข้อมูลไปยังฐานข้อมูลทั้งสองแบบขนานในขณะที่ผู้ใช้เปลี่ยนไปใช้เวอร์ชันแอปใหม่ จากนั้นลบไฟล์ SQLite
Realm Sync โดยค่าเริ่มต้นใช้กลยุทธ์ “last write wins” — การเขียนครั้งล่าสุดจะเขียนทับครั้งก่อนหน้า สำหรับข้อขัดแย้งที่ซับซ้อน ให้กำหนดค่าฟังก์ชันแก้ไขข้อขัดแย้งที่กำหนดเองบนเซิร์ฟเวอร์ MongoDB Atlas ที่รวมการเปลี่ยนแปลงจากอุปกรณ์ต่างๆ ตามตรรกะธุรกิจของแอปพลิเคชัน (เช่น รวมค่าแทนที่จะแทนที่)
Realm ไม่รองรับการรวมกลุ่ม SQL (SUM, AVG, GROUP BY) ในระดับฐานข้อมูล สำหรับคำสั่งค้นหาเชิงวิเคราะห์ แนะนำให้ส่งออกข้อมูลจาก Realm ไปยัง MongoDB Atlas ผ่าน Realm Sync และดำเนินการรวมกลุ่มผ่าน MongoDB Aggregation Pipeline สำหรับการนับอย่างง่าย ให้ใช้ realm.query<T>().count()
Realm ไม่เข้ารหัสข้อมูลโดยค่าเริ่มต้น สำหรับการเข้ารหัส ให้ระบุคีย์ 64 ไบต์ในการกำหนดค่า: Realm.Configuration(encryptionKey: key) การเข้ารหัสใช้ AES-256 + SHA-2 HMAC และเพิ่มค่าใช้จ่ายในการดำเนินการ 10-20% หากไม่มีการเข้ารหัส ไฟล์ .realm สามารถอ่านได้โดยกระบวนการใดๆ ที่มีการเข้าถึงระบบไฟล์
สรุป
เราจะพัฒนาแอปพลิเคชันบนมือถือแบบครบวงจร
IT Sectr สร้างแอปพลิเคชัน iOS และ Android สำหรับสตาร์ทอัพและธุรกิจตั้งแต่ปี 2017 เราจะให้คำแนะนำและเสนอวิธีแก้ปัญหาที่ดีที่สุดแก่คุณ
อ่านเพิ่มเติม