0% found this document useful (0 votes)
21 views

introducing-a-separate-database-for-queries-slides

introducing-a-separate-database-for-queries-slides

Uploaded by

lounes.lou20
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
21 views

introducing-a-separate-database-for-queries-slides

introducing-a-separate-database-for-queries-slides

Uploaded by

lounes.lou20
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 31

Introducing a Separate Database for

Queries

Vladimir Khorikov

@vkhorikov www.enterprisecraftsmanship.com
Meet Scalability

App Domain
API
services model

Client App Domain


API
services model
App Domain
API
services model

Database
Simplicity Performance

Scalability
Meet Scalability

Scalability vs. Performance

Enables utilization of Bound to a


a number of servers single server
Meet Scalability

Create Read Update Delete

Independent scaling
Meet Scalability

Create

Update Read

Delete

Command side Query side

1 server 10 servers
Meet Scalability
Commands Queries

Single
machine

Writes Reads
Client
Meet Scalability

Need sharding to scale


commands

It’s a rare requirement


Separation at the Data Level in the Real World

Separate databases
for reads and writes

Indexed view

Database replication
Separation at the Data Level in the Real World

Replica 2

Master Replica 1

Master is for writes


Replica 3

Replicas are for reads


Separation at the Data Level in the Real World

Separate databases
for reads and writes

Indexed view

Database replication
Designing a Database for Queries

Master Replica

Replicas have the same structure


Designing a Database for Queries

SELECT s.*, e.Grade, c.Name CourseName, c.Credits


FROM dbo.Student s
LEFT JOIN (
SELECT e.StudentID, COUNT(*) Number
FROM dbo.Enrollment e
GROUP BY e.StudentID) t ON s.StudentID = t.StudentID
LEFT JOIN dbo.Enrollment e ON e.StudentID = s.StudentID
LEFT JOIN dbo.Course c ON e.CourseID = c.CourseID
WHERE (c.Name = @Course OR @Course IS NULL)
AND (ISNULL(t.Number, 0) = @Number OR @Number IS NULL)
ORDER BY s.StudentID ASC
Designing a Database for Queries

Commands Queries
Designing a Database for Queries

Why denormalize the


queries database?
Designing a Database for Queries
Designing a Database for Queries
SELECT s.*, e.Grade, c.Name CourseName, c.Credits
FROM dbo.Student s
LEFT JOIN (
SELECT e.StudentID, COUNT(*) Number
FROM dbo.Enrollment e
GROUP BY e.StudentID) t ON s.StudentID = t.StudentID
LEFT JOIN dbo.Enrollment e ON e.StudentID = s.StudentID
LEFT JOIN dbo.Course c ON e.CourseID = c.CourseID
WHERE (c.Name = @Course OR @Course IS NULL)
AND (ISNULL(t.Number, 0) = @Number OR @Number IS NULL)
ORDER BY s.StudentID ASC

SELECT s.*
FROM dbo.Student s
WHERE (s.FirstCourseName = @Course
OR s.SecondCourseName = @Course OR @Course IS NULL)
AND (s.NumberOfEnrollments = @Number OR @Number IS NULL)
ORDER BY s.StudentID ASC
Recap: Creating a Database for Queries

Created a separate database


for queries and re-targeted
the query handler
Recap: Creating a Database for Queries
public List<StudentDto> Handle(GetListQuery query) {
string sql = @"
SELECT *
FROM dbo.Student s
WHERE (s.FirstCourseName = @Course
OR s.SecondCourseName = @Course
OR @Course IS NULL)
AND (s.NumberOfEnrollments = @Number
OR @Number IS NULL)
ORDER BY s.StudentID ASC";

using (SqlConnection connection = new SqlConnection(_connectionString.Value)) {


List<StudentDto> students = connection
.Query<StudentDto>(sql, new {
Course = query.EnrolledIn,
Number = query.NumberOfCourses
})
.ToList();

return students;
}
}
Recap: Creating a Database for Queries

App Domain
API
services model

Client

App Domain
API
services model

Applied different architectural approaches


to the read and write models
Recap: Creating a Database for Queries

3rd normal form 1st normal form


High normal forms are good
for commands; low normal
forms are good for queries.
Recap: Creating a Database for Queries

App Domain
API
services model

Client

App Domain
API
services model

Replace with a
document database
Scalability

Simplicity

Performance

Scalability
Scalability

Client

Commands Queries

Sync

Immutable
Scalability

Application

Write model

Read model : Web client

Read model 2 : Mobile client


A Word of Caution Regarding the Database
for Reads

Be prudent when applying


the CQRS pattern
A Word of Caution Regarding the Database
for Reads

App Domain
API
services model

Client

App Domain
API
services model

Maintainability costs are manageable

Synchronization introduces a lot of complexity

Eventual consistency is confusing for users


A Word of Caution Regarding the Database
for Reads

Eventual consistency and maintaining a


separate database are significant costs

In most cases, you are just fine without


a separate database for reads

CQRS can be just as effective with a


only a single database.
Introduced a separate database for queries
- Completed implementing the CQRS
pattern
- Reads and writes are separated at each
Summary level: API, app services, domain model, DB
- Adjusted the read database for the needs
of the query model
- Can scale the reads indefinitely

Scalability: utilizing the resources of more


than one server
Examples of the separation at the data level:
- Indexed views
- Database replication
- ElasticSearch
Designed the database for reads
- Denormalized and thus adjusted it to the
needs of the read model
- Minimized the number of joins and the
Summary amount of post-processing
The 3rd normal relational form is for
commands; the 1st form for queries

Might need a separate read database for


each client

Maintaining the synchronization is costly;


eventual consistency is confusing
- In many cases, a single database is
enough
In the Next Module

Synchronizing the commands and


queries databases

You might also like