Skip to content

Database Antipatterns

Database antipatterns lead to poor performance, data integrity issues, and security vulnerabilities.

A single table with hundreds of columns trying to store everything.

Building queries by concatenating user input.

Fetching related data in loops instead of joins.



AntipatternProblemSolution
God TableUnmaintainable, sparse dataProper normalization
SQL InjectionData breach, data lossParameterized queries
N+1 QueriesPerformance disasterEager loading, joins

-- Bad: Everything in one table
CREATE TABLE everything (
user_id INT,
user_name VARCHAR,
order_id INT,
order_date DATE,
product_id INT,
product_name VARCHAR,
-- 200 more columns...
)
-- Good: Separate, related tables
CREATE TABLE users (id, name, email)
CREATE TABLE orders (id, user_id, date)
CREATE TABLE products (id, name, price)
CREATE TABLE order_items (order_id, product_id, quantity)
// Bad - SQL injection
const sql = `SELECT * FROM users WHERE id = ${userId}`
// Good - parameterized
const sql = `SELECT * FROM users WHERE id = ?`
db.query(sql, [userId])
// Bad - N+1 queries
const users = await db.query('SELECT * FROM users')
for (const user of users) {
user.orders = await db.query(
'SELECT * FROM orders WHERE user_id = ?',
[user.id]
)
}
// Good - single query with join
const users = await db.query(`
SELECT u.*, o.*
FROM users u
LEFT JOIN orders o ON o.user_id = u.id
`)