An order-history page needs the customer's name, a status label, three product thumbnails and a delivery date, joined from four tables and paged. It's slow and N+1-prone off the write model. What's the CQRS fix, and what does it actually cost to keep in sync?
The order aggregate that enforces business rules (can this be cancelled, is the total right) is the wrong shape to serve a page that just wants to display a handful of fields, sorted and paged, across four tables — querying it that way is either a tangled fetch-join or the classic N+1 problem. CQRS's answer is to build a second model, a read model, shaped exactly like the page: one row per order with exactly the columns the page needs, indexed for the query it actually runs. Writes go through the aggregate as before; reads go through this separate table via one indexed query. What that costs is keeping the two in sync — a projection that updates the read model whenever the order changes. If both live in the same database, that update can be the same transaction as the write, so nothing's ever out of sync. Once they're separate stores, the update happens via an event (the outbox pattern), and the read model becomes eventually consistent: a customer who cancels and immediately refreshes might briefly see the old status.