| name | query-expert |
| description | Master SQL and database queries across multiple systems. Generate optimized queries, analyze performance, design indexes, and troubleshoot slow queries for PostgreSQL, MySQL, MongoDB, and more. |
Query Expert
Master database queries across SQL and NoSQL systems. Generate optimized queries, analyze performance with EXPLAIN plans, design effective indexes, and troubleshoot slow queries.
What This Skill Does
Helps you write efficient, performant database queries:
- Generate Queries - SQL, MongoDB, GraphQL queries
- Optimize Queries - Performance tuning and refactoring
- Design Indexes - Index strategies for faster queries
- Analyze Performance - EXPLAIN plans and query analysis
- Troubleshoot - Debug slow queries and bottlenecks
- Best Practices - Query patterns and anti-patterns
Supported Databases
SQL Databases
- PostgreSQL - Advanced features, CTEs, window functions
- MySQL/MariaDB - InnoDB optimization, replication
- SQLite - Embedded database optimization
- SQL Server - T-SQL, execution plans, DMVs
- Oracle - PL/SQL, partitioning, hints
NoSQL Databases
- MongoDB - Aggregation pipelines, indexes
- Redis - Key-value queries, Lua scripts
- Elasticsearch - Full-text search queries
- Cassandra - CQL, partition keys
Query Languages
- SQL - Standard and vendor-specific
- MongoDB Query Language - Find, aggregation
- GraphQL - Efficient data fetching
- Cypher - Neo4j graph queries
SQL Query Patterns
SELECT Queries
Basic SELECT
SELECT
user_id,
email,
created_at
FROM users
WHERE status = 'active'
AND created_at > NOW() - INTERVAL '30 days'
ORDER BY created_at DESC
LIMIT 100;
SELECT * FROM users;
JOINs
SELECT
o.order_id,
o.total,
c.name AS customer_name,
c.email
FROM orders o
INNER JOIN customers c ON o.customer_id = c.customer_id
WHERE o.created_at >= '2024-01-01';
SELECT
c.customer_id,
c.name,
COUNT(o.order_id) AS order_count,
COALESCE(SUM(o.total), 0) AS total_spent
FROM customers c
LEFT JOIN orders o ON c.customer_id = o.customer_id
GROUP BY c.customer_id, c.name;
SELECT
o.order_id,
c.name AS customer_name,
p.product_name,
oi.quantity,
oi.price
FROM orders o
INNER JOIN customers c ON o.customer_id = c.customer_id
INNER JOIN order_items oi ON o.order_id = oi.order_id
INNER JOIN products p ON oi.product_id = p.product_id
WHERE o.status = 'completed';
Subqueries
SELECT name, email
FROM customers
WHERE customer_id IN (
SELECT DISTINCT customer_id
FROM orders
WHERE total > 1000
);
SELECT
c.name,
(SELECT COUNT(*)
FROM orders o
WHERE o.customer_id = c.customer_id) AS order_count
FROM customers c;
SELECT
c.name,
COUNT(o.order_id) AS order_count
FROM customers c
LEFT JOIN orders o ON c.customer_id = o.customer_id
GROUP BY c.customer_id, c.name;
Aggregation
SELECT
category,
COUNT(*) AS product_count,
AVG(price) AS avg_price,
MIN(price) AS min_price,
MAX(price) AS max_price,
SUM(stock_quantity) AS total_stock
FROM products
GROUP BY category
HAVING COUNT(*) > 5
ORDER BY avg_price DESC;
SELECT
DATE_TRUNC('month', created_at) AS month,
category,
SUM(total) AS monthly_sales
FROM orders
GROUP BY DATE_TRUNC('month', created_at), category
ORDER BY month DESC, monthly_sales DESC;
SELECT
COALESCE(category, 'TOTAL') AS category,
COALESCE(brand, 'All Brands') AS brand,
SUM(sales) AS total_sales
FROM products
GROUP BY ROLLUP(category, brand);
Window Functions (PostgreSQL, SQL Server, MySQL 8+)
SELECT
customer_id,
order_date,
total,
ROW_NUMBER() OVER (
PARTITION BY customer_id
ORDER BY order_date DESC
) AS order_rank
FROM orders;
SELECT
order_date,
total,
SUM(total) OVER (
ORDER BY order_date
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
) AS running_total
FROM orders;
SELECT
product_name,
sales,
RANK() OVER (ORDER BY sales DESC) AS rank,
DENSE_RANK() OVER (ORDER BY sales DESC) AS dense_rank,
NTILE(4) OVER (ORDER BY sales DESC) AS quartile
FROM products;
SELECT
order_date,
total,
LAG(total, 1) OVER (ORDER BY order_date) AS prev_total,
LEAD(total, 1) OVER (ORDER BY order_date) AS next_total,
total - LAG(total, 1) OVER (ORDER BY order_date) AS change
FROM orders;
CTEs (Common Table Expressions)
WITH active_customers AS (
SELECT customer_id, name, email
FROM customers
WHERE status = 'active'
)
SELECT
ac.name,
COUNT(o.order_id) AS order_count
FROM active_customers ac
LEFT JOIN orders o ON ac.customer_id = o.customer_id
GROUP BY ac.customer_id, ac.name;
WITH
monthly_sales AS (
SELECT
DATE_TRUNC('month', order_date) AS month,
SUM(total) AS sales
FROM orders
GROUP BY DATE_TRUNC('month', order_date)
),
avg_monthly AS (
SELECT AVG(sales) AS avg_sales
FROM monthly_sales
)
SELECT
ms.month,
ms.sales,
am.avg_sales,
ms.sales - am.avg_sales AS variance
FROM monthly_sales ms
CROSS JOIN avg_monthly am
ORDER BY ms.month;
WITH RECURSIVE org_tree AS (
SELECT
employee_id,
name,
manager_id,
1 AS level,
ARRAY[employee_id] AS path
FROM employees
WHERE manager_id IS NULL
UNION ALL
SELECT
e.employee_id,
e.name,
e.manager_id,
ot.level + 1,
ot.path || e.employee_id
FROM employees e
INNER JOIN org_tree ot ON e.manager_id = ot.employee_id
)
SELECT * FROM org_tree ORDER BY path;
Query Optimization
1. Use Indexes Effectively
CREATE INDEX idx_users_email ON users(email);
CREATE INDEX idx_orders_customer_date ON orders(customer_id, order_date);
CREATE INDEX idx_orders_composite
ON orders(status, customer_id, order_date);
SELECT * FROM orders
WHERE status = 'pending'
AND customer_id = 123
AND order_date > '2024-01-01';
SELECT * FROM orders
WHERE customer_id = 123;
CREATE INDEX idx_active_users
ON users(email)
WHERE status = 'active';
CREATE INDEX idx_users_covering
ON users(email)
INCLUDE (name, created_at);
2. Avoid SELECT *
SELECT * FROM users;
SELECT user_id, email, name FROM users;
SELECT
u.user_id,
u.email,
o.order_id,
o.total
FROM users u
INNER JOIN orders o ON u.user_id = o.user_id;
3. Optimize JOINs
SELECT u.name, o.total
FROM users u
LEFT JOIN orders o ON u.user_id = o.user_id
WHERE o.status = 'completed';
SELECT u.name, o.total
FROM users u
INNER JOIN (
SELECT user_id, total
FROM orders
WHERE status = 'completed'
) o ON u.user_id = o.user_id;
SELECT u.name, o.total
FROM users u
INNER JOIN orders o ON u.user_id = o.user_id
WHERE o.status = 'completed';
4. Use EXISTS Instead of IN
SELECT name FROM customers
WHERE customer_id IN (
SELECT customer_id FROM orders WHERE total > 1000
);
SELECT name FROM customers c
WHERE EXISTS (
SELECT 1 FROM orders o
WHERE o.customer_id = c.customer_id
AND o.total > 1000
);
5. Avoid Functions on Indexed Columns
SELECT * FROM users
WHERE LOWER(email) = 'john@example.com';
CREATE INDEX idx_users_email_lower ON users(LOWER(email));
SELECT * FROM users
WHERE email = 'john@example.com' COLLATE utf8_general_ci;
6. Limit Result Sets
SELECT * FROM orders
ORDER BY created_at DESC
LIMIT 20 OFFSET 0;
SELECT * FROM orders
WHERE created_at > NOW() - INTERVAL '7 days'
ORDER BY created_at DESC;
7. Batch Operations
INSERT INTO users (name, email) VALUES ('User1', 'user1@example.com');
INSERT INTO users (name, email) VALUES ('User2', 'user2@example.com');
INSERT INTO users (name, email) VALUES
('User1', 'user1@example.com'),
('User2', 'user2@example.com'),
('User3', 'user3@example.com');
UPDATE products
SET price = price * 1.1
WHERE category IN ('Electronics', 'Computers');
EXPLAIN Plans
PostgreSQL
EXPLAIN
SELECT * FROM orders WHERE customer_id = 123;
EXPLAIN ANALYZE
SELECT
c.name,
COUNT(o.order_id) AS order_count
FROM customers c
LEFT JOIN orders o ON c.customer_id = o.customer_id
GROUP BY c.customer_id, c.name;
MySQL
EXPLAIN
SELECT * FROM orders WHERE customer_id = 123;
EXPLAIN ANALYZE
SELECT * FROM orders WHERE customer_id = 123;
Indexing Strategies
When to Index
✅ Index these columns:
- Primary keys (automatic)
- Foreign keys
- Columns in WHERE clauses
- Columns in JOIN conditions
- Columns in ORDER BY
- Columns in GROUP BY
❌ Don't index:
- Small tables (< 1000 rows)
- Columns with low cardinality (few distinct values)
- Frequently updated columns
- Large text/blob columns
Index Types
CREATE INDEX idx_users_email ON users(email);
CREATE INDEX idx_users_email_hash ON users USING HASH(email);
CREATE INDEX idx_posts_content_gin
ON posts USING GIN(to_tsvector('english', content));
CREATE INDEX idx_locations_gist
ON locations USING GIST(coordinates);
CREATE INDEX idx_orders_pending
ON orders(customer_id)
WHERE status = 'pending';
CREATE INDEX idx_users_email_domain
ON users((email ~~ '%@gmail.com%'));
Composite Index Order
CREATE INDEX idx_orders_search
ON orders(status, customer_id, created_at);
WHERE status = 'completed'
WHERE status = 'completed' AND customer_id = 123
WHERE status = 'completed'
AND customer_id = 123
AND created_at > '2024-01-01'
WHERE customer_id = 123
WHERE created_at > '2024-01-01'
MongoDB Queries
Find Queries
db.users.find({ status: 'active' })
db.users.find(
{ status: 'active' },
{ name: 1, email: 1, _id: 0 }
)
db.orders.find({
total: { $gt: 100, $lt: 1000 },
status: { $in: ['pending', 'processing'] },
'customer.city': 'New York'
})
db.products.find({ category: 'Electronics' })
.sort({ price: -1 })
.limit(10)
db.users.countDocuments({ status: 'active' })
Aggregation Pipeline
db.orders.aggregate([
{ $match: { status: 'completed' } },
{ $group: {
_id: '$customer_id',
total_orders: { $sum: 1 },
total_spent: { $sum: '$total' },
avg_order: { $avg: '$total' }
}},
{ $sort: { total_spent: -1 } },
{ $limit: 10 }
])
db.orders.aggregate([
{ $lookup: {
from: 'customers',
localField: 'customer_id',
foreignField: '_id',
as: 'customer'
}},
{ $unwind: '$customer' },
{ $project: {
order_id: 1,
total: 1,
'customer.name': 1,
'customer.email': 1
}}
])
db.sales.aggregate([
{ $match: {
date: { $gte: ISODate('2024-01-01') }
}},
{ $addFields: {
month: { $month: '$date' },
year: { $year: '$date' }
}},
{ $group: {
_id: { year: '$year', month: '$month' },
total_sales: { $sum: '$amount' },
order_count: { $sum: 1 },
avg_sale: { $avg: '$amount' }
}},
{ $sort: { '_id.year': 1, '_id.month': 1 } },
{ $project: {
_id: 0,
date: {
$concat: [
{ $toString: '$_id.year' },
'-',
{ $toString: '$_id.month' }
]
},
total_sales: 1,
order_count: 1,
avg_sale: { $round: ['$avg_sale', 2] }
}}
])
MongoDB Indexes
db.users.createIndex({ email: 1 })
db.orders.createIndex({ customer_id: 1, created_at: -1 })
db.users.createIndex({ email: 1 }, { unique: true })
db.orders.createIndex(
{ customer_id: 1 },
{ partialFilterExpression: { status: 'active' } }
)
db.products.createIndex({ name: 'text', description: 'text' })
db.sessions.createIndex(
{ created_at: 1 },
{ expireAfterSeconds: 3600 }
)
db.users.getIndexes()
db.orders.find({ customer_id: 123 }).explain('executionStats')
GraphQL Queries
query {
users {
id
name
email
}
}
query {
user(id: "123") {
name
email
orders {
id
total
status
}
}
}
query GetUser($userId: ID!) {
user(id: $userId) {
name
email
orders(limit: 10, status: COMPLETED) {
id
total
createdAt
}
}
}
fragment UserFields on User {
id
name
email
createdAt
}
query {
user(id: "123") {
...UserFields
orders {
id
total
}
}
}
query {
orders {
id
total
customer {
name
email
}
}
}
Common Anti-Patterns
❌ N+1 Query Problem
SELECT * FROM customers;
SELECT * FROM orders WHERE customer_id = ?;
SELECT
c.customer_id,
c.name,
o.order_id,
o.total
FROM customers c
LEFT JOIN orders o ON c.customer_id = o.customer_id;
❌ Using OR on Different Columns
SELECT * FROM products
WHERE name = 'iPhone' OR category = 'Electronics';
SELECT * FROM products WHERE name = 'iPhone'
UNION
SELECT * FROM products WHERE category = 'Electronics';
❌ Implicit Type Conversion
SELECT * FROM users WHERE user_id = '123';
SELECT * FROM users WHERE user_id = 123;
Query Performance Checklist
Resources
"Premature optimization is the root of all evil, but slow queries are the root of all frustration."