ภาพรวม
ไม่ได้อยู่ในยุค One-Size-Fits-All Datastore แล้ว วันนี้มีเหตุผลที่สมควรผสมผสาน SQL Datastores (MySQL, PostgreSQL, Oracle, SQLServer) กับ NoSQL Datastores (MongoDB, CouchDB, Neo4J) Oracle ยังคงเป็น System of Record หลักของ Enterprise แต่ไม่ใช่ตัวเลือกเดียวแล้ว
Developers เริ่มใช้ SQL + NoSQL ร่วมกันแก้ปัญหา บางครั้งขัดกับ DBA/IT Department
เลือกเครื่องมือที่เหมาะสมกับงาน
5 ประเภท Datastore หลัก: Column-family, Document, Graph, Key-value, Relational
Polyglot Persistence = ใช้หลายภาษา/เทคโนโลยีจัดเก็บข้อมูล ในแอปเดียวกัน อาจใช้ Cypher, JSON, SQL หรือ Query Languages อื่นๆ ร่วมกัน
"Different databases are designed to solve different problems. Using a single database engine for all requirements usually leads to non-performant solutions..." - Sadalage & Fowler
Datastore Choice ขึ้นกับ 2 เกณฑ์:
- โครงสร้างข้อมูลที่จะจัดเก็บ
- Queries ที่ใช้โต้ตอบกับข้อมูล
RDBMS ดีที่ Enforce Relationships แต่ยากเมื่อต้อง Discover Relationships หรือหาข้อมูลจากตารางต่างๆ ที่属于 Object เดียวกัน
ผู้เล่นหลัก: MongoDB, MySQL, CraigsList
MongoDB
NoSQL Alternative ยอดนิยมแทน MySQL: Scalability, Auto-sharding, Native Bindings สำหรับภาษาโปรแกรมยอดนิยม
ความแตกต่างหลัก: MongoDB เก็บข้อมูลเป็น Documents (JSON-like) แทน Tables + Foreign Keys Documents = Analogous กับ Rows/Tuples แต่ลึกได้ไม่จำกัด Query/Index ได้เต็มที่ มัก Denormalize ข้อมูลจาก Relational Model
MySQL
Classic RDBMS ยอดนิยมมากที่สุด ใช้ Relational Data Model (E.F. Codd, 1970s) Normalize, Plan, Introspect ได้ ทำให้เป็นที่นิยมสำหรับ General Data Modeling
CraigsList
Case Study: ใช้ MySQL สำหรับ Active Classifieds, MongoDB สำหรับ Archived Data (เกิน 30 วัน) ล้านรายการ/วัน ต้อง Retain ตามกฎระเบียب Schema เปลี่ยนแปลงบ่อย MongoDB ช่วย Segment Data และลดปัญหา Schema Migrations
วิธีการทำงาน (Implementation)
ปัญหา: Schema Update บน SQL Database ใหญ่ = ปวดหัว มากขึ้นตามขนาดข้อมูล
วิธีแก้: Archive ข้อมูลเก่า → ลดขนาด Data ที่ต้อง Migrate → Schema Update เร็วขึ้น หลายรอบ Archive → ได้ Heterogeneous Data มาก → ต้องใช้ Schemaless Datastore (MongoDB)
ตัวอย่าง Schema Classifieds (MySQL)
CREATE TABLE `classifieds` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`title` varchar(75), `description` text, `location` varchar(75),
`adtype` varchar(1) DEFAULT 'O', `email` varchar(75), `phone` varchar(75),
`activation_code` varchar(40), `status` tinyint(4) DEFAULT '0',
`category_id` int(11), `subcategory_id` int(11), `city_id` int(11),
`permalink` varchar(255), `image_file_name` varchar(255),
`image_content_type` varchar(255), `image_file_size` int(11),
`created_at` datetime, `updated_at` datetime,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
ใช้ created_at, updated_at 决定เมื่อไหร่ Archive
โค้ด Python: ย้ายข้อมูล MySQL → MongoDB
1. Introspect Schema ด้วย SQLAlchemy:
import sqlalchemy.schema
m = sqlalchemy.schema.MetaData("mysql://root:password@192.0.2.3/craigslist")
m.reflect()
print(m.tables.keys()) # ['classifieds', 'cities', 'subcategories', 'categories']
2. Query ข้อมูล Classifieds:
import sqlalchemy.sql
connection = m.bind.connect()
classifieds = m.tables['classifieds']
query = classifieds.select()
result = connection.execute(query)
for row in result:
print(dict(row.items())) # แต่ละ Row เป็น Dictionary
3. Insert ลง MongoDB ด้วย PyMongo:
import pymongo
client = pymongo.MongoClient('mongodb://192.0.2.2')
db = client['craigslist']
collection = db['classifieds']
collection.insert({'_id': 1})
4. แปลง ID Key (SQLAlchemy: id → MongoDB: _id):
classified['_id'] = classified.pop('id')
สรุป
SQL และ NoSQL ไม่ใช่ All-or-Nothing สามารถใช้ร่วมกันแก้ปัญหาซับซ้อนได้ Code สำหรับ Migration น้อยมาก สามารถรันด้วย Cron ได้
ความท้าทาย: การดูแล Multiple Datastores เพิ่ม Complexity ต้องมี Expertise (DBAs) มากขึ้น ธุรกิจต้องตัดสินว่าคุ้มค่าหรือไม่ มี Technologies ช่วย: Chef, Salt, Managed Services (เช่น ObjectRocket - Managed MongoDB by Rackspace)
หากปัญหานั้นได้ประโยชน์จาก Multiple Datastores อย่าให้ Assumptions หยุดการสำรวจโซลูชันเหล่านั้น