Extracting exactly what you need, nothing more, nothing less.
Modern applications interact with relational databases using SQL (Structured Query Language). A poorly optimized SQL query can bring down an entire web server by consuming too much memory or locking critical tables. Efficient data access means understanding how the database engine executes your queries.
A common mistake when using ORMs (Object Relational Mappers) is fetching a list of items, and then looping through them to fetch related data, resulting in 1 query + N additional queries.
# VULNERABLE: The N+1 Problem (101 Database Queries)
users = User.objects.all() # 1 Query
for user in users:
print(user.profile.bio) # 100 Queries! (1 for each user)
# SECURE: Eager Loading (1 Database Query)
# Uses a SQL JOIN under the hood
users = User.objects.select_related('profile').all()
for user in users:
print(user.profile.bio) # 0 Queries! Data is already in memory.
An API endpoint `GET /api/orders` takes 10 seconds to load. You look at the logs and see it executing 5,000 separate SQL queries. The ORM is fetching the orders, and then running a separate `SELECT` query for each order's shipping address. By changing the code to `orders = db.query(Order).joinedload(Address)`, it drops to a single query taking 40ms.
Why is it dangerous to run `SELECT count(*) FROM massive_table` in Postgres?