yashandb教程FG027-YashanDB窗口函数实战
本文档风哥主要介绍YashanDB窗口函数的实战应用,包括YashanDB窗口函数的概念、类型、执行原理,以及排名函数、聚合窗口函数、分析函数的具体实现和性能优化,风哥教程参考YashanDB官方文档SQL语言参考手册内容,适合DBA和开发人员在学习和测试中使用。更多视频教程www.fgedu.net.cn
Part01-基础概念与理论知识
1.1 YashanDB窗口函数概念
YashanDB窗口函数是一种特殊的函数,它在查询结果集的一个子集(窗口)上执行计算,而不是在整个结果集上执行。窗口函数可以用于计算排名、移动平均值、累计总和等分析型计算。学习交流加群风哥微信: itpux-com
- 在查询结果集的一个子集上执行计算
- 可以保留原始数据的所有行
- 可以使用PARTITION BY子句分组
- 可以使用ORDER BY子句排序
- 可以使用FRAME子句定义窗口范围
1.2 YashanDB窗口函数类型
YashanDB支持以下类型的窗口函数:
– 排名函数:ROW_NUMBER、RANK、DENSE_RANK、NTILE
– 聚合窗口函数:SUM、AVG、COUNT、MAX、MIN
– 分析函数:LEAD、LAG、FIRST_VALUE、LAST_VALUE
– 分布函数:PERCENT_RANK、CUME_DIST
– 逆分布函数:PERCENTILE_CONT、PERCENTILE_DISC
1.3 YashanDB窗口函数执行原理
YashanDB窗口函数的执行原理:
- 分区:根据PARTITION BY子句将结果集划分为多个分区
- 排序:根据ORDER BY子句对每个分区内的数据排序
- 窗口定义:根据FRAME子句定义每个行的窗口范围
- 计算:对每个行的窗口执行函数计算
- 返回:返回计算结果,保留原始数据
Part02-生产环境规划与建议
2.1 YashanDB窗口函数规划
在生产环境中使用YashanDB窗口函数时,需要进行以下规划:
– 明确窗口函数的业务需求
– 确定使用哪种类型的窗口函数
– 评估窗口函数对性能的影响
# 窗口函数设计
– 选择合适的窗口函数
– 合理设置PARTITION BY子句
– 合理设置ORDER BY子句
– 合理设置FRAME子句
# 窗口函数权限规划
– 确保用户拥有必要的查询权限
– 遵循最小权限原则
– 避免使用不必要的权限
# 窗口函数监控
– 监控窗口函数的执行性能
– 识别慢窗口函数查询
– 定期分析执行计划
2.2 YashanDB窗口函数性能考虑
YashanDB窗口函数的性能考虑:
- 数据量:处理的数据量越大,执行时间越长
- 分区数:分区数越多,执行时间可能越长
- 排序:排序操作会影响性能
- 窗口大小:窗口越大,执行时间越长
- 函数复杂度:复杂的窗口函数执行时间更长
2.3 YashanDB窗口函数最佳实践
YashanDB窗口函数最佳实践:
- 使用适当的分区:根据数据分布选择合适的分区列
- 优化排序:为排序列创建索引
- 限制窗口大小:只使用必要的窗口大小
- 避免复杂计算:简化窗口函数的计算逻辑
- 监控性能:定期监控窗口函数的执行性能
Part03-生产环境项目实施方案
3.1 YashanDB排名函数实现
3.1.1 YashanDB ROW_NUMBER函数
CREATE TABLE fgedu_employees (
emp_id NUMBER PRIMARY KEY,
emp_name VARCHAR2(100),
department VARCHAR2(100),
salary NUMBER,
hire_date DATE
);
— 插入测试数据
INSERT INTO fgedu_employees VALUES (1, ‘张三’, ‘技术部’, 5000, SYSDATE – 365);
INSERT INTO fgedu_employees VALUES (2, ‘李四’, ‘销售部’, 6000, SYSDATE – 180);
INSERT INTO fgedu_employees VALUES (3, ‘王五’, ‘技术部’, 7000, SYSDATE – 90);
INSERT INTO fgedu_employees VALUES (4, ‘赵六’, ‘销售部’, 8000, SYSDATE – 30);
INSERT INTO fgedu_employees VALUES (5, ‘孙七’, ‘技术部’, 9000, SYSDATE);
INSERT INTO fgedu_employees VALUES (6, ‘周八’, ‘销售部’, 7000, SYSDATE – 60);
INSERT INTO fgedu_employees VALUES (7, ‘吴九’, ‘技术部’, 6000, SYSDATE – 270);
— ROW_NUMBER函数
SELECT
emp_id,
emp_name,
department,
salary,
ROW_NUMBER() OVER (ORDER BY salary DESC) AS “总排名”,
ROW_NUMBER() OVER (PARTITION BY department ORDER BY salary DESC) AS “部门排名”
FROM fgedu_employees;
EMP_ID EMP_NAME DEPARTMENT SALARY 总排名 部门排名
—— ——– ———- —— —— ——–
5 孙七 技术部 9000 1 1
4 赵六 销售部 8000 2 1
3 王五 技术部 7000 3 2
6 周八 销售部 7000 4 2
2 李四 销售部 6000 5 3
7 吴九 技术部 6000 6 3
1 张三 技术部 5000 7 4
3.1.2 YashanDB RANK和DENSE_RANK函数
SELECT
emp_id,
emp_name,
department,
salary,
RANK() OVER (ORDER BY salary DESC) AS “RANK排名”,
DENSE_RANK() OVER (ORDER BY salary DESC) AS “DENSE_RANK排名”
FROM fgedu_employees;
EMP_ID EMP_NAME DEPARTMENT SALARY RANK排名 DENSE_RANK排名
—— ——– ———- —— —— ———–
5 孙七 技术部 9000 1 1
4 赵六 销售部 8000 2 2
3 王五 技术部 7000 3 3
6 周八 销售部 7000 3 3
2 李四 销售部 6000 5 4
7 吴九 技术部 6000 5 4
1 张三 技术部 5000 7 5
3.1.3 YashanDB NTILE函数
SELECT
emp_id,
emp_name,
department,
salary,
NTILE(3) OVER (ORDER BY salary DESC) AS “薪资分桶”
FROM fgedu_employees;
EMP_ID EMP_NAME DEPARTMENT SALARY 薪资分桶
—— ——– ———- —— ——–
5 孙七 技术部 9000 1
4 赵六 销售部 8000 1
3 王五 技术部 7000 1
6 周八 销售部 7000 2
2 李四 销售部 6000 2
7 吴九 技术部 6000 2
1 张三 技术部 5000 3
3.2 YashanDB聚合窗口函数实现
3.2.1 YashanDB SUM窗口函数
SELECT
emp_id,
emp_name,
department,
salary,
SUM(salary) OVER () AS “总工资”,
SUM(salary) OVER (PARTITION BY department) AS “部门总工资”,
SUM(salary) OVER (ORDER BY salary) AS “累计工资”
FROM fgedu_employees;
EMP_ID EMP_NAME DEPARTMENT SALARY 总工资 部门总工资 累计工资
—— ——– ———- —— —— ———- ——–
1 张三 技术部 5000 48000 27000 5000
7 吴九 技术部 6000 48000 27000 11000
2 李四 销售部 6000 48000 21000 17000
3 王五 技术部 7000 48000 27000 24000
6 周八 销售部 7000 48000 21000 31000
4 赵六 销售部 8000 48000 21000 39000
5 孙七 技术部 9000 48000 27000 48000
3.2.2 YashanDB AVG窗口函数
SELECT
emp_id,
emp_name,
department,
salary,
AVG(salary) OVER () AS “平均工资”,
AVG(salary) OVER (PARTITION BY department) AS “部门平均工资”,
AVG(salary) OVER (ORDER BY salary ROWS BETWEEN 2 PRECEDING AND CURRENT ROW) AS “移动平均工资”
FROM fgedu_employees;
EMP_ID EMP_NAME DEPARTMENT SALARY 平均工资 部门平均工资 移动平均工资
—— ——– ———- —— ——– ———- ————
1 张三 技术部 5000 6857.14 6750 5000
7 吴九 技术部 6000 6857.14 6750 5500
2 李四 销售部 6000 6857.14 7000 5666.67
3 王五 技术部 7000 6857.14 6750 6333.33
6 周八 销售部 7000 6857.14 7000 6666.67
4 赵六 销售部 8000 6857.14 7000 7333.33
5 孙七 技术部 9000 6857.14 6750 8000
3.2.3 YashanDB MAX和MIN窗口函数
SELECT
emp_id,
emp_name,
department,
salary,
MAX(salary) OVER (PARTITION BY department) AS “部门最高工资”,
MIN(salary) OVER (PARTITION BY department) AS “部门最低工资”
FROM fgedu_employees;
EMP_ID EMP_NAME DEPARTMENT SALARY 部门最高工资 部门最低工资
—— ——– ———- —— ———— ————
1 张三 技术部 5000 9000 5000
7 吴九 技术部 6000 9000 5000
3 王五 技术部 7000 9000 5000
5 孙七 技术部 9000 9000 5000
2 李四 销售部 6000 8000 6000
6 周八 销售部 7000 8000 6000
4 赵六 销售部 8000 8000 6000
3.3 YashanDB分析函数实现
3.3.1 YashanDB LEAD和LAG函数
SELECT
emp_id,
emp_name,
department,
salary,
LEAD(salary) OVER (PARTITION BY department ORDER BY salary) AS “下一个工资”,
LAG(salary) OVER (PARTITION BY department ORDER BY salary) AS “上一个工资”
FROM fgedu_employees;
EMP_ID EMP_NAME DEPARTMENT SALARY 下一个工资 上一个工资
—— ——– ———- —— ———- ———-
1 张三 技术部 5000 6000 (null)
7 吴九 技术部 6000 7000 5000
3 王五 技术部 7000 9000 6000
5 孙七 技术部 9000 (null) 7000
2 李四 销售部 6000 7000 (null)
6 周八 销售部 7000 8000 6000
4 赵六 销售部 8000 (null) 7000
3.3.2 YashanDB FIRST_VALUE和LAST_VALUE函数
SELECT
emp_id,
emp_name,
department,
salary,
FIRST_VALUE(salary) OVER (PARTITION BY department ORDER BY salary) AS “部门最低工资”,
LAST_VALUE(salary) OVER (PARTITION BY department ORDER BY salary ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) AS “部门最高工资”
FROM fgedu_employees;
EMP_ID EMP_NAME DEPARTMENT SALARY 部门最低工资 部门最高工资
—— ——– ———- —— ———— ————
1 张三 技术部 5000 5000 9000
7 吴九 技术部 6000 5000 9000
3 王五 技术部 7000 5000 9000
5 孙七 技术部 9000 5000 9000
2 李四 销售部 6000 6000 8000
6 周八 销售部 7000 6000 8000
4 赵六 销售部 8000 6000 8000
3.3.3 YashanDB PERCENT_RANK和CUME_DIST函数
SELECT
emp_id,
emp_name,
department,
salary,
PERCENT_RANK() OVER (ORDER BY salary) AS “百分比排名”,
CUME_DIST() OVER (ORDER BY salary) AS “累积分布”
FROM fgedu_employees;
EMP_ID EMP_NAME DEPARTMENT SALARY 百分比排名 累积分布
—— ——– ———- —— ———- ——–
1 张三 技术部 5000 0 0.1429
7 吴九 技术部 6000 0.1667 0.4286
2 李四 销售部 6000 0.1667 0.4286
3 王五 技术部 7000 0.5 0.7143
6 周八 销售部 7000 0.5 0.7143
4 赵六 销售部 8000 0.8333 0.8571
5 孙七 技术部 9000 1 1
Part04-生产案例与实战讲解
4.1 YashanDB排名函数实战案例
在生产环境中,使用排名函数解决业务问题:
WITH ranked_employees AS (
SELECT
emp_id,
emp_name,
department,
salary,
ROW_NUMBER() OVER (PARTITION BY department ORDER BY salary DESC) AS “部门排名”
FROM fgedu_employees
)
SELECT *
FROM ranked_employees
WHERE “部门排名” <= 2; EMP_ID EMP_NAME DEPARTMENT SALARY 部门排名 ------ -------- ---------- ------ -------- 5 孙七 技术部 9000 1 3 王五 技术部 7000 2 4 赵六 销售部 8000 1 6 周八 销售部 7000 2 -- 案例:根据薪资水平将员工分为3个等级 SELECT emp_id, emp_name, department, salary, NTILE(3) OVER (ORDER BY salary DESC) AS "薪资等级", CASE NTILE(3) OVER (ORDER BY salary DESC) WHEN 1 THEN '高薪资' WHEN 2 THEN '中等薪资' WHEN 3 THEN '低薪资' END AS "薪资等级描述" FROM fgedu_employees; EMP_ID EMP_NAME DEPARTMENT SALARY 薪资等级 薪资等级描述 ------ -------- ---------- ------ -------- ---------- 5 孙七 技术部 9000 1 高薪资 4 赵六 销售部 8000 1 高薪资 3 王五 技术部 7000 1 高薪资 6 周八 销售部 7000 2 中等薪资 2 李四 销售部 6000 2 中等薪资 7 吴九 技术部 6000 2 中等薪资 1 张三 技术部 5000 3 低薪资
4.2 YashanDB聚合窗口函数实战案例
在生产环境中,使用聚合窗口函数分析数据:
SELECT
emp_id,
emp_name,
department,
salary,
SUM(salary) OVER (PARTITION BY department) AS “部门总工资”,
ROUND(salary / SUM(salary) OVER (PARTITION BY department) * 100, 2) AS “部门薪资占比”,
SUM(salary) OVER () AS “公司总工资”,
ROUND(salary / SUM(salary) OVER () * 100, 2) AS “公司薪资占比”
FROM fgedu_employees
ORDER BY department, salary DESC;
EMP_ID EMP_NAME DEPARTMENT SALARY 部门总工资 部门薪资占比 公司总工资 公司薪资占比
—— ——– ———- —— ———- ———- ———- ———-
5 孙七 技术部 9000 27000 33.33 48000 18.75
3 王五 技术部 7000 27000 25.93 48000 14.58
7 吴九 技术部 6000 27000 22.22 48000 12.5
1 张三 技术部 5000 27000 18.52 48000 10.42
4 赵六 销售部 8000 21000 38.1 48000 16.67
6 周八 销售部 7000 21000 33.33 48000 14.58
2 李四 销售部 6000 21000 28.57 48000 12.5
— 案例:计算移动平均工资
SELECT
emp_id,
emp_name,
department,
salary,
AVG(salary) OVER (ORDER BY hire_date ROWS BETWEEN 2 PRECEDING AND CURRENT ROW) AS “最近3人平均工资”
FROM fgedu_employees
ORDER BY hire_date;
EMP_ID EMP_NAME DEPARTMENT SALARY 最近3人平均工资
—— ——– ———- —— ————–
1 张三 技术部 5000 5000
7 吴九 技术部 6000 5500
2 李四 销售部 6000 5666.67
6 周八 销售部 7000 6333.33
3 王五 技术部 7000 6666.67
4 赵六 销售部 8000 7333.33
5 孙七 技术部 9000 8000
4.3 YashanDB分析函数实战案例
在生产环境中,使用分析函数解决业务问题:
SELECT
emp_id,
emp_name,
department,
salary,
LEAD(salary) OVER (PARTITION BY department ORDER BY salary) AS “下一个工资”,
LEAD(salary) OVER (PARTITION BY department ORDER BY salary) – salary AS “与下一个的差异”,
LAG(salary) OVER (PARTITION BY department ORDER BY salary) AS “上一个工资”,
salary – LAG(salary) OVER (PARTITION BY department ORDER BY salary) AS “与上一个的差异”
FROM fgedu_employees;
EMP_ID EMP_NAME DEPARTMENT SALARY 下一个工资 与下一个的差异 上一个工资 与上一个的差异
—— ——– ———- —— ———- ————– ———- ————–
1 张三 技术部 5000 6000 1000 (null) (null)
7 吴九 技术部 6000 7000 1000 5000 1000
3 王五 技术部 7000 9000 2000 6000 1000
5 孙七 技术部 9000 (null) (null) 7000 2000
2 李四 销售部 6000 7000 1000 (null) (null)
6 周八 销售部 7000 8000 1000 6000 1000
4 赵六 销售部 8000 (null) (null) 7000 1000
— 案例:获取部门最高和最低工资
SELECT
emp_id,
emp_name,
department,
salary,
FIRST_VALUE(salary) OVER (PARTITION BY department ORDER BY salary) AS “部门最低工资”,
LAST_VALUE(salary) OVER (PARTITION BY department ORDER BY salary ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) AS “部门最高工资”
FROM fgedu_employees;
EMP_ID EMP_NAME DEPARTMENT SALARY 部门最低工资 部门最高工资
—— ——– ———- —— ———— ————
1 张三 技术部 5000 5000 9000
7 吴九 技术部 6000 5000 9000
3 王五 技术部 7000 5000 9000
5 孙七 技术部 9000 5000 9000
2 李四 销售部 6000 6000 8000
6 周八 销售部 7000 6000 8000
4 赵六 销售部 8000 6000 8000
Part05-风哥经验总结与分享
5.1 YashanDB窗口函数使用经验
YashanDB窗口函数使用经验总结:
- 排名函数:适用于需要排名的场景,如Top N查询、分桶等
- 聚合窗口函数:适用于需要在保留原始数据的同时进行聚合计算的场景
- 分析函数:适用于需要比较相邻行数据的场景,如差异分析、趋势分析等
- 分区和排序:合理设置PARTITION BY和ORDER BY子句
- 窗口定义:根据需要设置合适的FRAME子句
- 性能考虑:窗口函数可能影响性能,需要优化
5.2 YashanDB窗口函数故障排除
## 1. 窗口函数执行缓慢
– 症状:窗口函数执行时间长
– 原因:数据量过大、排序操作复杂、窗口定义不合理
– 解决:优化窗口定义,为排序列创建索引,限制数据量
## 2. 窗口函数结果不正确
– 症状:窗口函数返回错误的结果
– 原因:PARTITION BY或ORDER BY子句设置不正确,FRAME子句定义错误
– 解决:检查PARTITION BY和ORDER BY子句,正确定义FRAME子句
## 3. 内存不足
– 症状:窗口函数执行时报错”ORA-04030: out of process memory”
– 原因:窗口函数需要大量内存
– 解决:优化窗口定义,减少数据量,增加内存
## 4. 排序操作性能差
– 症状:窗口函数中的排序操作执行缓慢
– 原因:排序列没有索引
– 解决:为排序列创建索引
## 5. 分区数过多
– 症状:窗口函数执行缓慢
– 原因:PARTITION BY子句导致分区数过多
– 解决:减少分区数,优化分区策略
5.3 YashanDB窗口函数使用建议
YashanDB窗口函数使用建议:
- 选择合适的窗口函数:根据业务需求选择合适的窗口函数
- 优化窗口定义:合理设置PARTITION BY、ORDER BY和FRAME子句
- 使用索引:为排序列创建索引,提高排序性能
- 限制数据量:只处理必要的数据,避免处理过多数据
- 监控性能:定期监控窗口函数的执行性能
- 测试充分:在测试环境充分测试窗口函数,确保性能满足要求
本文由风哥教程整理发布,仅用于学习测试使用,转载注明出处:http://www.fgedu.net.cn/10327.html
