Master SQL query optimization, indexing strategies, and EXPLAIN analysis to dramatically improve database performance and eliminate slow queries. Use when debugging slow queries, designing database schemas, or optimizing application performance.
通过系统优化、合理索引和查询计划分析,将慢速数据库查询转变为闪电般的快速操作。
理解 EXPLAIN 输出是优化的基础。
PostgreSQL EXPLAIN:
sql
-- 基本解释
EXPLAIN SELECT * FROM users WHERE email = user@example.com;
-- 包含实际执行统计
EXPLAIN ANALYZE
SELECT * FROM users WHERE email = user@example.com;
-- 更详细的输出
EXPLAIN (ANALYZE, BUFFERS, VERBOSE)
SELECT u.*, o.order_total
FROM users u
JOIN orders o ON u.id = o.user_id
WHERE u.created_at > NOW() - INTERVAL 30 days;
需要关注的关键指标:
索引是最强大的优化工具。
索引类型:
sql
-- 标准 B-Tree 索引
CREATE INDEX idxusersemail ON users(email);
-- 复合索引(顺序很重要!)
CREATE INDEX idxordersuserstatus ON orders(userid, status);
-- 部分索引(索引行的子集)
CREATE INDEX idxactiveusers ON users(email)
WHERE status = active;
-- 表达式索引
CREATE INDEX idxuserslower_email ON users(LOWER(email));
-- 覆盖索引(包含额外列)
CREATE INDEX idxusersemail_covering ON users(email)
INCLUDE (name, created_at);
-- 全文搜索索引
CREATE INDEX idxpostssearch ON posts
USING GIN(to_tsvector(english, title || || body));
-- JSONB 索引
CREATE INDEX idx_metadata ON events USING GIN(metadata);
避免 SELECT \*:
sql
-- 不好:获取不必要的列
SELECT * FROM users WHERE id = 123;
-- 好:只获取所需内容
SELECT id, email, name FROM users WHERE id = 123;
高效使用 WHERE 子句:
sql
-- 不好:函数阻止索引使用
SELECT * FROM users WHERE LOWER(email) = user@example.com;
-- 好:创建函数索引或使用精确匹配
CREATE INDEX idxusersemail_lower ON users(LOWER(email));
-- 然后:
SELECT * FROM users WHERE LOWER(email) = user@example.com;
-- 或者存储规范化数据
SELECT * FROM users WHERE email = user@example.com;
优化 JOIN:
sql
-- 不好:笛卡尔积然后过滤
SELECT u.name, o.total
FROM users u, orders o
WHERE u.id = o.userid AND u.createdat > 2024-01-01;
-- 好:先过滤再连接
SELECT u.name, o.total
FROM users u
JOIN orders o ON u.id = o.user_id
WHERE u.created_at > 2024-01-01;
-- 更好:过滤两个表
SELECT u.name, o.total
FROM (SELECT * FROM users WHERE created_at > 2024-01-01) u
JOIN orders o ON u.id = o.user_id;
问题:N+1 查询反模式
python
解决方案:使用 JOIN 或批量加载
sql
-- 解决方案 1:JOIN
SELECT
u.id, u.name,
o.id as order_id, o.total
FROM users u
LEFT JOIN orders o ON u.id = o.user_id
WHERE u.id IN (1, 2, 3, 4, 5);
-- 解决方案 2:批量查询
SELECT * FROM orders
WHERE user_id IN (1, 2, 3, 4, 5);
python
不好:在大表上使用 OFFSET
sql
-- 大偏移量时很慢
SELECT * FROM users
ORDER BY created_at DESC
LIMIT 20 OFFSET 100000; -- 非常慢!
好:基于游标的分页
sql
-- 快得多:使用游标(最后看到的 ID)
SELECT * FROM users
WHERE created_at < 2024-01-15 10:30:00 -- 最后一个游标
ORDER BY created_at DESC
LIMIT 20;
-- 复合排序
SELECT * FROM users
WHERE (created_at, id) < (2024-01-15 10:30:00, 12345)
ORDER BY created_at DESC, id DESC
LIMIT 20;
-- 需要索引
CREATE INDEX idxuserscursor ON users(created_at DESC, id DESC);
优化 COUNT 查询:
sql
-- 不好:计数所有行
SELECT COUNT(*) FROM orders; -- 在大表上很慢
-- 好:使用估算值进行近似计数
SELECT reltuples::bigint AS estimate
FROM pg_class
WHERE relname = orders;
-- 好:先过滤再计数
SELECT COUNT(*) FROM orders
WHERE created_at > NOW() - INTERVAL 7 days;
-- 更好:使用仅索引扫描
CREATE INDEX idxorderscreated ON orders(created_at);
SELECT COUNT(*) FROM orders
WHERE created_at > NOW() - INTERVAL 7 days;
优化 GROUP BY:
sql
-- 不好:先分组再过滤
SELECT userid, COUNT(*) as ordercount
FROM orders
GROUP BY user_id
HAVING COUNT(*) > 10;
-- 更好:先过滤再分组(如果可能)
SELECT userid, COUNT(*) as ordercount
FROM orders
WHERE status = completed
GROUP BY user_id
HAVING COUNT(*) > 10;
-- 最佳:使用覆盖索引
CREATE INDEX idxordersuserstatus ON orders(userid, status);
转换相关子查询:
sql
-- 不好:相关子查询(对每一行执行)
SELECT u.name, u.email,
(SELECT COUNT(*) FROM orders o WHERE o.userid = u.id) as ordercount
FROM users u;
-- 好:使用聚合的 JOIN
SELECT u.name, u.email, COUNT(o.id) as order_count
FROM users u
LEFT JOIN orders o ON o.user_id = u.id
GROUP BY u.id, u.name, u.email;
-- 更好:使用窗口函数
SELECT DISTINCT ON (u.id)
u.name, u.email,
COUNT(o.id) OVER (PARTITION BY u.id) as order_count
FROM users u
LEFT JOIN orders o ON o.user_id = u.id;
使用 CTE 提高清晰度:
sql
-- 使用公用表表达式
WITH recent_users AS (
SELECT id, name, email
FROM users
WHERE created_at > NOW() - INTERVAL 30 days
),
userordercounts AS (
SELECT user_id
该技能支持在以下平台通过对话安装:
帮我安装 SkillHub 和 sql-optimization-patterns-1776076269 技能
设置 SkillHub 为我的优先技能安装源,然后帮我安装 sql-optimization-patterns-1776076269 技能
skillhub install sql-optimization-patterns-1776076269
文件大小: 5.14 KB | 发布时间: 2026-4-14 12:59