第二十五篇 SQL优化杀手锏:用分析函数让你的查询快如闪电

目录

    • 一、初识分析函数:外卖骑手的一天
      • 1.1 真实工作场景
    • 二、分析函数三板斧(超直观对比表)
    • 三、手把手教学:5大核心函数详解 ️
      • 3.1 排名三剑客(班级成绩单案例)
        • 3.1.1 ROW_NUMBER():唯一学号式排名
        • 3.1.2 RANK():运动会颁奖式排名
        • 3.1.3 DENSE_RANK():电梯楼层式排名
      • 3.2 时间旅行函数(股票分析案例)
      • 3.3 滑动窗口函数(疫情数据分析)
    • 四、性能优化三大绝招(让老板眼前一亮)
      • 4.1 黄金法则
      • 4.2 实战性能对比
    • 五、闯关练习:检验学习成果 ️
      • 5.1 基础题
      • 5.2 进阶题
      • 5.3 参考答案
    • 六、学习路线图(从小白到专家) ️

本文能帮你解决什么问题?

  • 告别复杂嵌套查询,1行代码实现累计计算
  • 报表性能提升10倍的秘密武器
  • 轻松应对排名、对比、滑动窗口等高级分析需求

一、初识分析函数:外卖骑手的一天

1.1 真实工作场景

假设你是外卖平台的数据工程师,老板突然要:

  • 实时看板:每个骑手最近3单的平均配送时长
  • 运营报表:统计每个商圈销售额Top3的商家

传统写法需要写多层子查询,而用分析函数只需一个SQL!

-- 骑手移动平均配送时长
SELECT rider_id, order_time,
       AVG(delivery_time) OVER (
         PARTITION BY rider_id 
         ORDER BY order_time 
         ROWS BETWEEN 2 PRECEDING AND CURRENT ROW
       ) AS avg_3_orders
FROM delivery_records;

-- 商圈商家销售额排名
SELECT mall_id, shop_name, sales,
       RANK() OVER (PARTITION BY mall_id ORDER BY sales DESC) AS top3
FROM shop_sales;

二、分析函数三板斧(超直观对比表)

功能 传统写法 分析函数写法 优势对比
计算部门平均 需要GROUP BY + JOIN回原表 直接OVER计算 保留原始明细数据
累计销售额 多重自连接 一个SUM+窗口帧搞定 执行速度快10倍+
数据对比 复杂子查询 LAG/LEAD一行搞定 代码量减少80%

三、手把手教学:5大核心函数详解 ️

3.1 排名三剑客(班级成绩单案例)

-- 建表语句
CREATE TABLE class (
  student_id INT PRIMARY KEY,
  name VARCHAR(20),
  math_score INT
);

-- 插入数据
INSERT INTO class VALUES 
(1, '小明', 90),
(2, '小红', 90),
(3, '小刚', 85);
3.1.1 ROW_NUMBER():唯一学号式排名
SELECT name, math_score,
       ROW_NUMBER() OVER (ORDER BY math_score DESC) as row_num
FROM class;

结果

姓名 数学成绩 排名
小明 90 1
小红 90 2
小刚 85 3
3.1.2 RANK():运动会颁奖式排名
SELECT name, math_score,
       RANK() OVER (ORDER BY math_score DESC) as rank
FROM class;

结果

姓名 数学成绩 排名
小明 90 1
小红 90 1
小刚 85 3
3.1.3 DENSE_RANK():电梯楼层式排名
SELECT name, math_score,
       DENSE_RANK() OVER (ORDER BY math_score DESC) as dense_rank
FROM class;

结果

姓名 数学成绩 排名
小明 90 1
小红 90 1
小刚 85 2

避坑指南

  • 需要连续排名用DENSE_RANK
  • 必须唯一序号用ROW_NUMBER

3.2 时间旅行函数(股票分析案例)

-- 查看股价波动
SELECT 
  trade_date,
  closing_price,
  LAG(closing_price, 1) OVER (ORDER BY trade_date) as 昨日收盘价,
  closing_price - LAG(closing_price, 1) OVER (ORDER BY trade_date) as 涨跌幅
FROM stock;

3.3 滑动窗口函数(疫情数据分析)

-- 计算7日平均新增
SELECT 
  report_date,
  new_cases,
  AVG(new_cases) OVER (
    ORDER BY report_date 
    ROWS BETWEEN 6 PRECEDING AND CURRENT ROW
  ) as 7日移动平均
FROM covid_data;

四、性能优化三大绝招(让老板眼前一亮)

4.1 黄金法则

  1. 索引先行:为PARTITION BY和ORDER BY字段建索引
  2. 窗口精控:ROWS BETWEEN比RANGE快10倍
  3. 拒绝浪费:无排序需求时去掉ORDER BY

4.2 实战性能对比

慢查询(3.2秒)

SELECT user_id, 
       (SELECT AVG(score) FROM logs WHERE user_id = l.user_id) 
FROM logs l;

优化后(0.4秒)

SELECT user_id, 
       AVG(score) OVER (PARTITION BY user_id) 
FROM logs;

五、闯关练习:检验学习成果 ️

5.1 基础题

需求:计算每个员工的薪资在部门内的占比
表结构:employees(dept, name, salary)

5.2 进阶题

需求:找出连续3天登录的用户(提示:用日期差值法)

5.3 参考答案

-- 基础题答案
SELECT 
  dept, name, salary,
  salary / SUM(salary) OVER (PARTITION BY dept) AS ratio
FROM employees;

-- 进阶题答案
WITH login_series AS (
  SELECT 
    user_id,
    login_date - ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY login_date) AS grp
  FROM user_logins
)
SELECT user_id
FROM login_series
GROUP BY user_id, grp
HAVING COUNT(*) >= 3;

六、学习路线图(从小白到专家) ️

阶段 学习重点 推荐资源
新手 基础语法 《SQL必知必会》
进阶 复杂查询 LeetCode数据库题库
高手 执行计划优化 《高性能MySQL》第6章

下期预告:《SQL优化之分析需求》
互动话题:你在学习SQL时遇到过哪些坑?欢迎评论区留言讨论!
️温馨提示:我是[随缘而动,随遇而安], 一个喜欢用生活案例讲技术的开发者。如果觉得有帮助,点赞关注不迷路

你可能感兴趣的:(SQL之道——从入门到精通,数据库,sql)