تخزين البيانات القابل للتوسّع: SQL مقابل NoSQL
اختر بين قواعد البيانات العلائقية، ومخازن المفتاح-القيمة، وقواعد بيانات المستندات، والمخازن ذات الأعمدة العريضة، بناءً على أنماط الوصول ومتطلبات الاتساق والتوسّع.
تخزين البيانات القابل للتوسّع: SQL مقابل NoSQL درس مجاني في Coding Interview Prep على CoddyKit. هذا هو الدرس 2 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في Coding Interview Prep، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة Coding Interview Prep 4 دروس في المجموع.
اختيار مخزن البيانات مفاضلة
يُعد اختيار مخزن البيانات أحد أكثر القرارات تأثيرًا في تصميم الأنظمة. لا توجد قاعدة بيانات هي الأفضل على نحو مطلق — فكل نوع مُحسّن لأنماط وصول وضمانات اتساق وخصائص توسع مختلفة. ويؤدي اتخاذ القرار الخطأ في بيئة الإنتاج إلى أشهر من أعمال الترحيل الشاقة.
في المقابلات، يفحص المحاورون مدى فهمكم للاختلافات الأساسية وقدرتكم على مواءمة محرك تخزين مع متطلبات المشكلة. لا يكون السؤال أبدًا «أيهما أفضل؟» بل «أيهما أفضل لعبء العمل المحدد هذا؟». احرصوا دائمًا على تبرير اختياركم بمتطلبات محددة.
# Storage decision matrix summary
factors = [
'Data structure (tabular, documents, key-value, graph, time-series)',
'Read vs write ratio (read-heavy, write-heavy, balanced)',
'Query patterns (point lookups, range scans, aggregations, joins)',
'Consistency requirements (ACID vs eventual consistency)',
'Scale requirements (single node, sharding, global distribution)',
'Latency requirements (milliseconds vs microseconds)',
'Team familiarity and operational complexity',
]
print('Key factors for storage selection:')
for f in factors:
print(f' - {f}')قواعد البيانات العلائقية (SQL): نقاط القوة
تخزن قواعد البيانات العلائقية (PostgreSQL وMySQL وSQLite) البيانات في جداول ذات مخططات ثابتة، وتدعم معاملات ACID — الذرية والاتساق والعزل والديمومة. وتتميز بالاستعلامات المعقدة التي تتضمن عمليات الربط والتجميع والتصفية، ما يجعلها مثالية للبيانات المهيكلة ذات العلاقات المحددة جيدًا.
نقاط القوة الرئيسية: تنفيذ استعلامات معقدة متعددة الجداول عبر SQL، وقيود المفاتيح الخارجية لضمان سلامة البيانات، وفهرسة قوية (B-tree وhash وfull-text)، ومنظومة ناضجة مع النسخ المتماثل والنسخ الاحتياطية. استخدموا SQL عندما تكون بياناتكم مترابطة بدرجة كبيرة، ويكون الاتساق أمرًا بالغ الأهمية، وتكون الاستعلامات معقدة ومتنوعة.
# SQL excels at: complex queries, joins, transactions
# Example: find top 5 products by revenue this month
sql_query = '''
SELECT p.name, SUM(oi.quantity * oi.price) AS revenue
FROM orders o
JOIN order_items oi ON o.id = oi.order_id
JOIN products p ON oi.product_id = p.id
WHERE o.created_at >= DATE_TRUNC('month', NOW())
GROUP BY p.id, p.name
ORDER BY revenue DESC
LIMIT 5;
'''
print('SQL shines for relational queries with JOINs:')
print(sql_query)
print('ACID guarantees example (transfer $100 between accounts):')
transfer_sql = '''
BEGIN;
UPDATE accounts SET balance = balance - 100 WHERE id = 1;
UPDATE accounts SET balance = balance + 100 WHERE id = 2;
COMMIT; -- either both succeed or neither does
'''
print(transfer_sql)تحديات توسيع نطاق SQL
تتوسع قواعد بيانات SQL رأسيًا بطبيعتها (خادم أكبر، ووحدة معالجة مركزية وذاكرة وصول عشوائي أكبر)، لكن التوسع الأفقي معقد. تتعامل النسخ المتماثلة للقراءة مع أحمال العمل الكثيفة القراءة من خلال توجيه القراءات إلى عقد النسخ المتماثلة والكتابات إلى العقدة الأساسية. لكن إنتاجية الكتابة تظل محدودة بعقدة أساسية واحدة ما لم تضيفوا Sharding.
يقسّم Sharding البيانات عبر عدة مثيلات لقاعدة البيانات باستخدام مفتاح تقسيم (مثل user_id mod N). ويحقق ذلك توسعًا في الكتابة، لكنه يعطل عمليات الربط والمعاملات عبر الأجزاء — وهما من أقوى ميزتي SQL. وتتجاوز معظم تطبيقات الويب قدرات SQL ذي العقدة الواحدة عند نحو 5-10 TB من البيانات أو قرابة 100K عملية كتابة/ثانية.
# SQL scaling strategies
strategies = {
'Read replicas': {
'how': 'One primary (writes), multiple replicas (reads)',
'scales': 'Read throughput (10x+)',
'limit': 'Write throughput still bounded by single primary',
},
'Connection pooling (PgBouncer)': {
'how': 'Pool of persistent DB connections shared among app servers',
'scales': 'Connection count (PostgreSQL max ~500 connections)',
'limit': 'Does not increase query throughput',
},
'Horizontal sharding': {
'how': 'Partition rows by shard key across N database instances',
'scales': 'Both reads and writes (N×)',
'limit': 'Cross-shard joins and transactions broken; complex routing',
},
'CQRS': {
'how': 'Separate write model (SQL) from read model (denormalised/NoSQL)',
'scales': 'Optimise each path independently',
'limit': 'Eventual consistency between write and read models',
},
}
for strategy, info in strategies.items():
print(f'{strategy}:\n How: {info["how"]}\n Scales: {info["scales"]}\n Limit: {info["limit"]}\n')مخازن المفتاح-القيمة: Redis وDynamoDB
تخزن مخازن المفتاح-القيمة البيانات على هيئة أزواج مفتاح ← قيمة، مع قراءة وكتابة بتعقيد O(1) باستخدام المفتاح. وهي تضحي بمرونة الاستعلامات مقابل أداء فائق وقابلية توسع أفقي هائلة. يحقق Redis (داخل الذاكرة) زمن وصول بالميكروثانية، بينما يحقق DynamoDB (خدمة مُدارة) زمن وصول أحادي الرقم بالميلي ثانية مع توسيع تلقائي لأي معدل إنتاجية.
استخدموا مخازن المفتاح-القيمة في: تخزين الجلسات، والتخزين المؤقت، وأعلام الميزات، وعمليات ربط عناوين URL المختصرة، وسلال التسوق، ولوحات الصدارة الفورية. لا تستخدموها عندما تحتاجون إلى: استعلامات معقدة، أو علاقات بين الكيانات، أو تصفية مخصصة — إذ لا يمكنكم البحث إلا باستخدام مفتاح مطابق تمامًا.
# Key-value store use cases
kv_operations = {
'GET key': 'O(1) point lookup — the core operation',
'SET key value': 'O(1) insert or update',
'DEL key': 'O(1) delete',
'EXPIRE key ttl': 'Set time-to-live; key auto-deleted after ttl seconds',
'INCR key': 'Atomic increment — useful for counters and rate limiting',
'LPUSH/LRANGE': 'List operations — useful for queues and recent-items feeds',
'ZADD/ZRANGE': 'Sorted set — leaderboards, rate limiting with sliding window',
}
print('Redis operation set:')
for op, desc in kv_operations.items():
print(f' {op:25s}: {desc}')
print('\nDynamoDB vs Redis:')
print(' Redis: microsecond latency, in-memory, needs persistence config')
print(' DynamoDB: single-digit ms, managed, auto-scaling, durable by default')مخازن المستندات: MongoDB
تخزن مخازن المستندات (MongoDB وCouchbase) البيانات على هيئة مستندات شبيهة بـ JSON، ما يتيح مخططات مرنة — إذ يمكن أن تختلف الحقول بين المستندات في المجموعة نفسها. وهي تدعم الفهرسة على أي حقل واستعلامات غنية إلى حد معقول (الفلاتر والإسقاطات والتجميعات)، رغم أن المعاملات التي تشمل عدة مستندات محدودة بدرجة أكبر من SQL.
تلائم مخازن المستندات التطبيقات التي: يختلف فيها شكل البيانات من كيان إلى آخر (مثل ملفات المستخدمين التي تحتوي على سمات مختلفة)، أو يُتوقع فيها تطور المخطط بسرعة (مثل الشركات الناشئة التي تغيّر نماذج البيانات باستمرار)، أو تتركز أنماط القراءة فيها على استرجاع الكيانات كاملة بدلًا من الربط عبر الجداول.
# MongoDB document example
user_doc = {
'_id': 'user123',
'name': 'Alice',
'email': 'alice@example.com',
'preferences': {
'theme': 'dark',
'language': 'en',
'notifications': ['email', 'push']
},
'addresses': [
{'type': 'home', 'city': 'Berlin', 'country': 'DE'},
{'type': 'work', 'city': 'Munich', 'country': 'DE'}
],
'subscription_tier': 'pro',
# Note: not all users have all fields -- flexible schema!
}
import json
print('Document structure (flexible schema):')
print(json.dumps(user_doc, indent=2))
print('\nDocument store strengths:')
print(' - Nested/array fields without joins')
print(' - Flexible schema (different fields per document)')
print(' - Scales horizontally by sharding on _id')مخازن الأعمدة العريضة: Cassandra
تخزن مخازن الأعمدة العريضة (Apache Cassandra وHBase) البيانات في صفوف وأعمدة، لكنها تسمح بأن تمتلك كل صف مجموعة مختلفة من الأعمدة. وقد صُممت لتحقيق إنتاجية كتابة هائلة موزعة عبر عدد كبير من العقد، مع اعتماد الاتساق النهائي افتراضيًا. يحقق Cassandra توسعًا خطيًا في الكتابة — فمضاعفة عدد العقد تضاعف إنتاجية الكتابة.
أما المفاضلة فهي أن الاستعلامات يجب أن تُصمم حول مفتاح التقسيم. ولا يمكنكم تصفية الأعمدة العشوائية أو فرزها بكفاءة — بل يجب تحديد نمط الاستعلام أولًا، ثم تصميم الجدول بما يلائمه. وهذا عكس نهج SQL القائم على «تصميم البيانات ثم كتابة أي استعلام».
# Cassandra table design for time-series events
# Design around the query: 'give me all events for user X, most recent first'
cassandra_table = '''
CREATE TABLE user_events (
user_id UUID,
event_time TIMESTAMP,
event_type TEXT,
metadata MAP<TEXT, TEXT>,
PRIMARY KEY (user_id, event_time)
) WITH CLUSTERING ORDER BY (event_time DESC);
-- Query (matches partition key exactly):
SELECT * FROM user_events WHERE user_id = ? LIMIT 100;
'''
print('Cassandra wide-column design:')
print(cassandra_table)
print('Properties:')
print(' - user_id = partition key (all rows for one user on same node)')
print(' - event_time = clustering key (sorted within partition)')
print(' - Very fast writes: append-only, no locking')
print(' - Cannot query by event_type alone (no partition key)')نظرية CAP: الاتساق والتوافر وتحمل الانقسام
تنص نظرية CAP على أن النظام الموزع يمكنه ضمان اثنين فقط كحد أقصى من الخصائص التالية: الاتساق (تعيد كل قراءة أحدث كتابة)، والتوافر (يحصل كل طلب على استجابة غير متعلقة بخطأ)، وتحمل الانقسام (يواصل النظام عمله رغم انقسامات الشبكة).
وبما أن انقسامات الشبكة تحدث دائمًا في الأنظمة الموزعة، فإن الاختيار الفعلي يكون بين CP (إعطاء الأولوية للاتساق، مع احتمال رفض الطلبات أثناء الانقسام) وAP (إعطاء الأولوية للتوافر، مع احتمال إرجاع بيانات قديمة). تكون قواعد بيانات SQL عمومًا من نوع CP؛ أما Cassandra وDynamoDB فمن نوع AP (الاتساق النهائي افتراضيًا). ويكون Redis Cluster من نوع CP.
# CAP theorem applied to common databases
databases = {
'PostgreSQL (single node)': {'C': True, 'A': True, 'P': False, 'note': 'Not distributed; CA'},
'PostgreSQL (multi-AZ)': {'C': True, 'A': False, 'P': True, 'note': 'CP: primary fails over, brief downtime'},
'MySQL Cluster': {'C': True, 'A': False, 'P': True, 'note': 'CP'},
'Cassandra': {'C': False, 'A': True, 'P': True, 'note': 'AP: eventual consistency default'},
'DynamoDB (default)': {'C': False, 'A': True, 'P': True, 'note': 'AP: eventual consistency'},
'DynamoDB (strong read)': {'C': True, 'A': False, 'P': True, 'note': 'CP: strongly consistent reads'},
'Redis Cluster': {'C': True, 'A': False, 'P': True, 'note': 'CP'},
'MongoDB (default)': {'C': True, 'A': False, 'P': True, 'note': 'CP: reads from primary'},
}
for db, caps in databases.items():
c_str = 'C' if caps['C'] else '-'
a_str = 'A' if caps['A'] else '-'
p_str = 'P' if caps['P'] else '-'
print(f'{db:35s} [{c_str}{a_str}{p_str}] {caps["note"]}')اختيار التخزين: إطار لاتخاذ القرار
إطار عملي لاتخاذ قرار اختيار التخزين في المقابلات:
- هل تحتاجون إلى معاملات ACID؟ → قاعدة بيانات علائقية (PostgreSQL وMySQL)
- هل تحتاجون إلى عمليات بحث بزمن وصول أقل من ميلي ثانية أو إلى تخزين مؤقت؟ → مخزن مفتاح-قيمة (Redis)
- هل تحتاجون إلى مخطط مرن أو بيانات موجهة نحو المستندات؟ → مخزن مستندات (MongoDB)
- هل تحتاجون إلى إنتاجية كتابة هائلة (>100K/sec) مع بيانات سلاسل زمنية أو بيانات أحداث؟ → مخزن أعمدة عريضة (Cassandra)
- هل تحتاجون إلى توزيع عالمي مع توسيع مُدار؟ → DynamoDB أو Cosmos DB
- هل تحتاجون إلى اجتيازات للرسوم البيانية؟ → قاعدة بيانات رسوم بيانية (Neo4j)
# Decision tree in code form
def choose_storage(needs_acid, high_write_throughput, flexible_schema,
sub_ms_latency, graph_queries, global_scale):
if sub_ms_latency:
return 'Redis (in-memory key-value)'
if graph_queries:
return 'Neo4j (graph database)'
if needs_acid:
return 'PostgreSQL / MySQL (relational)'
if high_write_throughput and not flexible_schema:
return 'Cassandra (wide-column, write-optimised)'
if flexible_schema:
return 'MongoDB (document store)'
if global_scale:
return 'DynamoDB or Cosmos DB (managed global KV/document)'
return 'PostgreSQL (safe default for most web apps)'
# Example scenarios
scenarios = [
{'needs_acid': True, 'high_write_throughput': False, 'flexible_schema': False,
'sub_ms_latency': False, 'graph_queries': False, 'global_scale': False},
{'needs_acid': False, 'high_write_throughput': True, 'flexible_schema': False,
'sub_ms_latency': False, 'graph_queries': False, 'global_scale': False},
{'needs_acid': False, 'high_write_throughput': False, 'flexible_schema': False,
'sub_ms_latency': True, 'graph_queries': False, 'global_scale': False},
]
for s in scenarios:
print(f'{choose_storage(**s)}')التخزين متعدد التقنيات: استخدام مخازن متعددة
نادرًا ما تستخدم أنظمة الإنتاج قاعدة بيانات واحدة لكل شيء. يعني التخزين متعدد التقنيات استخدام تقنية التخزين المناسبة لكل جزء من النظام. وقد يستخدم تطبيق ويب نموذجي: PostgreSQL لبيانات المستخدمين والطلبات المرجعية، وRedis لتخزين الجلسات والتخزين المؤقت، وElasticsearch للبحث في النصوص الكاملة، وS3 لتخزين الملفات، وCassandra لسجلات الأحداث والتحليلات.
أما المفاضلة فهي أن التعقيد التشغيلي يزداد مع كل نوع من قواعد البيانات. إذ يتعين على الفريق صيانة أنظمة متعددة ومراقبتها وإجراء نسخ احتياطية منها. وتبرير التصميم هو أن مكاسب الأداء وقابلية التوسع الناتجة عن مواءمة كل حمل عمل مع مخزن التخزين المناسب تفوق التكلفة التشغيلية عند التوسع.
# Polyglot persistence in an e-commerce system
components = {
'User accounts, orders, payments': {
'storage': 'PostgreSQL',
'reason': 'ACID transactions (payment integrity), complex queries',
},
'Product catalogue': {
'storage': 'MongoDB or PostgreSQL with JSONB',
'reason': 'Flexible product attributes vary by category',
},
'Session tokens': {
'storage': 'Redis (with TTL)',
'reason': 'O(1) lookup, automatic expiry, high throughput',
},
'Product search': {
'storage': 'Elasticsearch',
'reason': 'Full-text search, faceted filtering, relevance scoring',
},
'Activity/event log': {
'storage': 'Cassandra or Kafka + S3',
'reason': 'High write throughput, append-only, time-series queries',
},
'Product images / videos': {
'storage': 'S3 + CloudFront CDN',
'reason': 'Cheap object storage, global distribution via CDN',
},
}
for component, info in components.items():
print(f'{component}:\n {info["storage"]}: {info["reason"]}\n')استراتيجية الفهرسة عبر أنواع التخزين
تستخدم جميع أنظمة التخزين الفهارس لتسريع عمليات القراءة، على حساب إبطاء عمليات الكتابة وزيادة مساحة التخزين. ويُعد فهم الفهرسة عبر أنواع التخزين المختلفة أمرًا بالغ الأهمية في تصميم الأنظمة:
- SQL: فهرس B-tree على أي عمود؛ وفهارس مركبة للاستعلامات متعددة الأعمدة؛ وفهارس تغطية لتجنب البحث في الجداول
- MongoDB: فهرس على أي حقل؛ وفهارس مركبة؛ وفهارس TTL لانتهاء الصلاحية تلقائيًا
- Cassandra: لا تتم فهرسة سوى مفتاح التقسيم وأعمدة التجميع أصلًا؛ والفهارس الثانوية مكلفة
- Redis: المجموعات المرتبة بوصفها فهارس للاستعلامات النطاقية؛ ولا حاجة إلى فهرسة تقليدية مع المفتاح-القيمة
# Indexing examples across storage types
# PostgreSQL: B-tree composite index
postgres_index = '''
CREATE INDEX idx_orders_user_created
ON orders(user_id, created_at DESC);
-- Optimises: SELECT * FROM orders WHERE user_id=? ORDER BY created_at DESC
'''
# MongoDB: compound index
mongo_index = '''
db.products.createIndex({ category: 1, price: -1 })
// Optimises: db.products.find({category:'Electronics'}).sort({price:-1})
'''
# Cassandra: cluster key ordering (built into table design)
cassandra_index = '''
-- No separate index needed; clustering key IS the index:
PRIMARY KEY (user_id, event_time) WITH CLUSTERING ORDER BY (event_time DESC)
'''
print('PostgreSQL:', postgres_index)
print('MongoDB:', mongo_index)
print('Cassandra:', cassandra_index)SQL أم NoSQL في المقابلات: ماذا تقولون
عندما يُطرح عليكم سؤال «SQL أم NoSQL؟» في مقابلة لتصميم الأنظمة، لا تقدموا إجابة من كلمة واحدة أبدًا. بدلًا من ذلك، اتبعوا هذا التسلسل:
- حدّدوا حمل العمل: «هذا حمل عمل كثيف القراءة مع تصفية معقدة، لذا…»
- حدّدوا المتطلب: «نحتاج إلى اتساق قوي للمعاملات المالية، لذا…»
- اذكروا الاختيار: «سأستخدم PostgreSQL مع نسخ متماثلة للقراءة»
- اذكروا المفاضلة: «المفاضلة هي أن توسيع نطاق الكتابة أفقيًا يتطلب Sharding، ما يضيف تعقيدًا»
- اذكروا بديلًا: «إذا كان معدل الكتابة أعلى، فقد نضع DynamoDB في الحسبان»
# Sample answer structure for 'SQL or NoSQL?'
def answer_storage_question(workload, consistency_need, scale):
print(f'Workload: {workload}')
print(f'Consistency: {consistency_need}')
print(f'Scale: {scale}')
print()
if 'financial' in workload.lower() or consistency_need == 'strong':
choice = 'PostgreSQL (ACID, strong consistency)'
tradeoff = 'Horizontal write scaling requires sharding'
alternative = 'Google Spanner for global transactions'
elif 'event' in workload.lower() or 'log' in workload.lower():
choice = 'Cassandra (high write throughput, time-series)'
tradeoff = 'Eventual consistency; queries limited to partition key'
alternative = 'Kafka + S3 for long-term event archival'
else:
choice = 'DynamoDB (managed, auto-scale, low latency)'
tradeoff = 'Limited query flexibility; cross-item transactions limited'
alternative = 'PostgreSQL if complex queries emerge'
print(f'Choice: {choice}\nTrade-off: {tradeoff}\nAlternative: {alternative}')
answer_storage_question('Social media feed', 'eventual', '10M users')اختبار سريع
اختبروا فهمكم لمفاهيم Data Structures & Algorithms — Coding Interview Prep الواردة في هذا الدرس.
مراجعة الدرس
في هذا الدرس تعلمتم أن قواعد بيانات SQL توفر معاملات ACID واستعلامات معقدة، لكنها تواجه صعوبة في توسيع نطاق الكتابة، بينما تضحي قواعد بيانات NoSQL بالاتساق أو مرونة الاستعلامات مقابل التوسع والتوافر الهائلين، وأن نظرية CAP تجبر الأنظمة الموزعة على الاختيار بين الاتساق والتوافر أثناء انقسامات الشبكة، وأن أنظمة الإنتاج تستخدم عادةً التخزين متعدد التقنيات — فتطابق كل حمل عمل مع محرك التخزين المناسب. بعد ذلك سنستكشف طبقات التخزين المؤقت وشبكات CDN وموازنة الأحمال لمواصلة توسيع نطاق الأنظمة الكثيفة القراءة.
الأسئلة الشائعة
هل درس «تخزين البيانات القابل للتوسّع: SQL مقابل NoSQL» مجاني؟
نعم — نص درس «تخزين البيانات القابل للتوسّع: SQL مقابل NoSQL» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة Coding Interview Prep، انتقل إلى CoddyKit PRO. تتضمن دورة Coding Interview Prep 4 دروس في المجموع.
ماذا ستتعلم في «تخزين البيانات القابل للتوسّع: SQL مقابل NoSQL»؟
اختر بين قواعد البيانات العلائقية، ومخازن المفتاح-القيمة، وقواعد بيانات المستندات، والمخازن ذات الأعمدة العريضة، بناءً على أنماط الوصول ومتطلبات الاتساق والتوسّع. تتمرن على Coding Interview Prep مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.
هل أحتاج إلى خبرة سابقة لأبدأ Coding Interview Prep؟
لا تُشترط خبرة سابقة. Coding Interview Prep على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 2 من أصل 4.
كم من الوقت يستغرق درس «تخزين البيانات القابل للتوسّع: SQL مقابل NoSQL»؟
معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.
هل يمكنني كتابة وتشغيل أكواد في درس Coding Interview Prep هذا؟
نعم. كل درس في Coding Interview Prep يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.
جميع الدروس في هذه الدورة
- إطار مقابلة تصميم الأنظمة
- تخزين البيانات القابل للتوسّع: SQL مقابل NoSQL
- التخزين المؤقت وشبكات CDN وموازنة الحمل
- تصميم محدِّد معدل الطلبات وتصميم موجز Twitter