CQRS: איך הפרדת פקודות משאילתות פותרת בעיות סקייל אמיתיות
מאת צוות מדיה דיל · 30.08.2026 · טכנולוגיה · 6 דק׳
CQRS מפריד בין הדרך שבה כותבים נתונים לדרך שבה קוראים אותם. הנה מתי ההפרדה הזו שווה את המורכבות הנוספת, ומתי היא סתם עומס מיותר.
ברוב המערכות, אותו מודל נתונים משמש גם לכתיבה וגם לקריאה — טבלה אחת, שאילתה אחת, מבנה אחד. CQRS (Command Query Responsibility Segregation) שובר את ההנחה הזו: מודל כתיבה נפרד לגמרי ממודל קריאה, כל אחד מותאם למה שהוא צריך לעשות באמת.
הבעיה שהאדריכלות הרגילה יוצרת
מודל נתונים אחד שמשרת גם כתיבה וגם קריאה נאלץ לפשר: מבנה שנוח לעדכון בודד לא בהכרח נוח לשאילתות דוחות מורכבות, ולהפך. ככל שהמערכת גדלה, הפשרה הזו הופכת יקרה יותר — שאילתות קריאה כבדות מאטות את הכתיבה, ואופטימיזציה לכתיבה פוגעת בביצועי הקריאה.
Command: צד הכתיבה
בצד הפקודות, כל שינוי במערכת עובר דרך מודל שמתמקד באכיפת חוקים עסקיים ותקינות נתונים — לא בנוחות קריאה. המבנה כאן יכול להיות מנורמל ומדויק, כי אף אחד לא שואל ממנו שאילתות דוחות מורכבות.
Query: צד הקריאה
מודל הקריאה, לעומת זאת, יכול להיות מוכפל ומותאם בדיוק לצורה שבה המסך צריך להציג את המידע — כולל שדות מחושבים מראש, טבלאות לא מנורמלות, ואפילו מסד נתונים שונה לגמרי המותאם לשאילתות מהירות. השינוי בצד הכתיבה מתעדכן למודל הקריאה באופן א-סינכרוני.
עקביות סופית: המחיר של הגמישות
מכיוון שמודל הקריאה מתעדכן באופן א-סינכרוני, יש חלון זמן קצר שבו הקריאה עדיין לא משקפת את הכתיבה האחרונה — עקביות סופית (Eventual Consistency) במקום עקביות מיידית. זה מקובל לגמרי ברוב המקרים (כמו עדכון מונה לייקים), אבל לא מתאים למקרים שדורשים דיוק מיידי מוחלט כמו יתרת חשבון בנק.
מתי CQRS דווקא לא מתאים
מערכת CRUD פשוטה, עם עומס נמוך וסביר, לא צריכה את המורכבות הנוספת של שני מודלים נפרדים וסנכרון ביניהם. CQRS פותר בעיה אמיתית — אבל רק כשהבעיה קיימת. הטמעה מוקדמת מדי מוסיפה מורכבות תפעולית בלי תמורה אמיתית, בדיוק כמו כל דפוס ארכיטקטוני חזק מדי שמוחל על בעיה קטנה.
שילוב עם Event Sourcing
CQRS משתלב טבעי עם Event Sourcing — שמירת רצף האירועים שהובילו למצב הנוכחי, במקום שמירת המצב הסופי בלבד. השילוב מאפשר לבנות מודלי קריאה חדשים בכל רגע פשוט על ידי "הרצה מחדש" של האירועים, יכולת שלא קיימת במערכת CRUD רגילה. עקרון דומה של הפרדת אחריות מופיע גם בארכיטקטורת Event-Driven שסקרנו במדריך נפרד.
מדידה לפני החלטה
לפני שמאמצים CQRS, כדאי למדוד בפועל איפה הצוואר בקבוק — האם שאילתות הקריאה באמת מתחרות עם הכתיבה על אותם משאבים, או שהבעיה במקום אחר לגמרי (אינדקסים חסרים, שאילתות לא יעילות). הטמעת CQRS כפתרון לבעיה שלא אובחנה נכון היא בזבוז מורכבות.
סנכרון בין המודלים בפועל
ברוב היישומים, השינוי בצד הכתיבה משודר כאירוע לתור הודעות, ומעדכן (Projector) שמאזין לאירועים בונה או מעדכן את מודל הקריאה בהתאם. הפרדה זו מאפשרת גם להריץ כמה מודלי קריאה שונים במקביל מאותם אירועים בדיוק — למשל מודל אחד לדשבורד ניהולי ומודל אחר לאפליקציית לקוח, בלי לשכפל לוגיקת כתיבה.
בדיקות ואבחון תקלות
מערכת עם שני מודלים נפרדים דורשת אסטרטגיית בדיקה שונה: בדיקות על צד הפקודות מוודאות שהחוקים העסקיים נאכפים נכון; בדיקות על צד הקריאה מוודאות שהמודל מוצג נכון לאחר עדכון. כשמשהו משתבש, השאלה הראשונה היא תמיד באיזה צד — כתיבה שנכשלה בשקט, או פרויקציה שלא התעדכנה כראוי.
מודלי קריאה מרובים מאותו מקור
יתרון נוסף שלא תמיד בולט מיד: אפשר לבנות כמה מודלי קריאה שונים במקביל מאותו זרם אירועים בדיוק — אחד מותאם לדוח ניהולי, אחר מותאם לחיפוש מהיר, שלישי מותאם ל-API חיצוני. כל שינוי במקור מתעדכן אוטומטית לכל המודלים, בלי לשכפל לוגיקת עדכון בכל אחד מהם בנפרד.
מתלבטים אם CQRS מתאים למערכת שלכם? מוזמנים לפתוח שיחה בוואטסאפ.
תגיות: CQRS · Command Query Responsibility Segregation · ארכיטקטורת תוכנה · סקייל