CHAPTER 14
Intermediate
Database and Query Best Practices
Updated: May 16, 2026
35 min read
# CHAPTER 14
Database and Query Best Practices
1. Introduction
The database is the beating heart of most software applications. It is also the most common source of catastrophic performance bottlenecks and tight architectural coupling. If you write raw SQL queries directly inside your UI rendering logic, a simple change to a database column name will break the entire application. Clean Code demands that the database be treated as a "Detail," hidden behind layers of abstraction. In this chapter, we will master Clean Database Architecture. We will explore the Repository Pattern to decouple our code from the database, learn the limits and best practices of Object-Relational Mappers (ORMs), and discuss how to write clean, optimized queries.2. Learning Objectives
By the end of this chapter, you will be able to:- Understand why mixing business logic with database queries is a violation of SRP.
- Implement the "Repository Pattern" to abstract data access.
- Differentiate between Active Record and Data Mapper ORM patterns.
- Avoid the "N+1 Query Problem" (the most common ORM performance killer).
- Write clean, parameterized SQL queries to prevent security vulnerabilities.
3. The Repository Pattern
To achieve Dependency Inversion (from Chapter 9), your business logic (Service Layer) must not know that MySQL exists.-
The Problem:
UserServicecallsDB::query("SELECT * FROM users"). The service is tightly coupled to SQL.
-
The Repository: Create an interface
IUserRepository. Create a classMySQLUserRepositorythat implements it. The Service Layer only asks the Interface for data:$user = $userRepository->findById(5).
-
The Benefit: You can switch from MySQL to MongoDB tomorrow by writing one new class, and the
UserServicecode doesn't change a single line. It also allows you to easily Mock the database during Unit Testing.
4. ORM Best Practices (Object-Relational Mapping)
ORMs (like Eloquent in Laravel, Doctrine in Symfony, or Hibernate in Java) are tools that let you query the database using object-oriented syntax instead of raw SQL.- The Good: They massively speed up development for basic CRUD operations and handle security (SQL Injection prevention) automatically.
- The Bad: Developers treat ORMs like magic and forget that real SQL is happening underneath. This leads to horrific performance issues.
5. The N+1 Query Problem
This is the #1 performance killer in modern ORM-driven applications.- The Mistake: You query 100 users. Then, in a loop, you ask the ORM for each user's profile.
php
*Total Queries: 101.* This will crash the server under heavy load.
- The Clean Solution (Eager Loading): Tell the ORM to fetch everything up front.
php
6. Clean SQL Queries
Sometimes an ORM is too slow for massive reporting queries, and you must write raw SQL. Clean SQL follows the same formatting rules as Clean Code.- Formatting: Do not write a massive query on one line. Capitalize SQL keywords, indent clauses, and use line breaks.
select id, name, email from users join orders on users.id = orders.user_id where status='active'
*Clean:*
sql
7. Diagrams/Visual Suggestions
*Database Abstraction Flow*
txt
8. Best Practices
-
Never Trust Input (Parameterization): When writing raw SQL, NEVER concatenate user input directly into the query string (
"SELECT * FROM users WHERE name = '" . $input . "'"). This causes catastrophic SQL Injection attacks. Always use Parameterized Queries (Prepared Statements).
9. Common Mistakes
-
Database Logic Leakage: A developer uses an ORM to query data, but adds
->where('status', 'active')directly inside the Frontend HTML View template. The View now contains business logic and database knowledge. All data retrieval logic MUST remain in the Repository or Service layer. The View should only be handed a finalized array of data to render.
10. Mini Project: Build a Repository
Scenario: Abstract this tight coupling. *Before (Tightly Coupled Service):*
php
*After (Repository Pattern):*
php
11. Practice Exercises
- 1. Define the "N+1 Query Problem." Explain how Eager Loading solves this severe performance issue.
- 2. Why is the Repository Pattern crucial for adhering to the Dependency Inversion Principle (DIP)?
12. MCQs with Answers
Question 1
What is the primary architectural benefit of implementing the Repository Pattern?
Question 2
A developer writes a raw SQL query by directly concatenating a user's form input into the string. What catastrophic security vulnerability does this violate?
13. Interview Questions
-
Q: You are reviewing code and notice an ORM is being called inside a
foreachloop to fetch relational data. Explain the performance implications of this to the junior developer and how to refactor it.
- Q: Explain the difference between the "Active Record" ORM pattern (e.g., Laravel Eloquent) and the "Data Mapper" ORM pattern (e.g., Doctrine). Which one enforces stricter separation of concerns?
- Q: Why does Robert C. Martin state that "The Database is a Detail"? How should high-level business policies treat the database?