慢查询排查
场景描述
BI 看板页面加载需要 30 秒,排查后发现底层 SQL 查询需要扫描全表 2 亿行数据。
排查流程
常见慢查询场景及优化
1. 全表扫描
-- ❌ 慢:WHERE 条件无索引
SELECT * FROM orders WHERE user_name = '张三';
-- ✅ 优化:添加索引
ALTER TABLE orders ADD INDEX idx_user_name (user_name);
2. 深分页
-- ❌ 慢:OFFSET 100万
SELECT * FROM orders ORDER BY id LIMIT 10 OFFSET 1000000;
-- ✅ 优化:游标分页
SELECT * FROM orders WHERE id > 1000000 ORDER BY id LIMIT 10;
3. 大表 JOIN
-- ❌ 慢:两个大表直接 JOIN
SELECT a.*, b.*
FROM order_detail a -- 10亿行
JOIN product b ON a.product_id = b.id; -- 500万行
-- ✅ 优化:小表广播(Spark)
SELECT /*+ BROADCAST(b) */ a.*, b.*
FROM order_detail a
JOIN product b ON a.product_id = b.id;
4. 不合理的子查询
-- ❌ 慢:相关子查询每行执行一次
SELECT user_id, (SELECT COUNT(*) FROM orders WHERE orders.user_id = u.id) AS order_cnt
FROM users u;
-- ✅ 优化:改写为 JOIN
SELECT u.id AS user_id, COALESCE(o.cnt, 0) AS order_cnt
FROM users u
LEFT JOIN (SELECT user_id, COUNT(*) AS cnt FROM orders GROUP BY user_id) o
ON u.id = o.user_id;
5. 窗口函数滥用
-- ❌ 慢:全量数据上开窗
SELECT *, ROW_NUMBER() OVER (ORDER BY created_at) AS rn FROM orders;
-- ✅ 优化:先过滤再开窗
SELECT *, ROW_NUMBER() OVER (ORDER BY created_at) AS rn
FROM orders WHERE dt = '2024-01-15';
EXPLAIN 关键字段解读
| 字段 | 含义 | 优化信号 |
|---|---|---|
| type | 访问类型 | ALL(全表扫描) → range(范围) → ref(索引) → const |
| key | 使用的索引 | NULL = 未用索引 |
| rows | 预估扫描行数 | 越少越好 |
| Extra | 附加信息 | Using filesort / Using temporary 需优化 |
常见面试问题
Q1: 数据分析师需要关注 SQL 性能吗?
答案:
需要。数据分析师写的 SQL 经常在大数据集上执行,不注意性能会导致:
- 查询超时影响分析效率
- 占用集群资源影响他人
- BI 看板加载慢影响用户体验
核心关注:避免全表扫描、用好分区、控制数据量。
Q2: Hive / Spark SQL 慢查询如何排查?
答案:
- 看 Spark UI 的 Stage 和 Task 执行时间
- 检查 Shuffle 数据量(Shuffle Read/Write)
- 检查是否有数据倾斜(某个 Task 特别慢)
- 检查分区裁剪是否生效(Partition Pruning)
- 检查是否触发了小文件问题