如何优化查询在职员工入职与当前薪资差Top10、末10的SQL语句
SQL查询优化方案
原SQL耗时高的核心原因
- 全表扫描280万条记录执行窗口函数,资源消耗大:
t1对所有薪资记录按员工分区排序,实际仅需每个员工入职时的第一条薪资记录即可 - 冗余计算:两次重复关联
t1和t2计算薪资差值,还额外执行了不必要的DISTINCT去重(在职员工每个emp_no仅对应一条当前薪资记录,关联后天然去重) - 缺少覆盖索引,查询过程中需要大量回表读取数据
具体优化措施
1. 新增覆盖索引
先给salaries表创建两个联合覆盖索引,避免回表开销:
-- 用于快速查询每个员工最早入职的薪资 CREATE INDEX idx_emp_from_sal ON salaries(emp_no, from_date, salary); -- 用于快速筛选在职员工的当前薪资 CREATE INDEX idx_to_emp_sal ON salaries(to_date, emp_no, salary);
2. 优化SQL逻辑
去掉冗余的窗口函数、重复关联和DISTINCT操作,一次性计算所有在职员工的薪资差值,再分别取升降序的前10条:
WITH emp_first_sal AS ( -- 直接取每个员工最早入职日期对应的薪资,比窗口函数性能高 SELECT s.emp_no, s.salary AS first_salary FROM salaries s INNER JOIN ( SELECT emp_no, MIN(from_date) AS entry_date FROM salaries GROUP BY emp_no ) t ON s.emp_no = t.emp_no AND s.from_date = t.entry_date ), emp_current_sal AS ( -- 取在职员工当前薪资 SELECT emp_no, salary AS current_salary FROM salaries WHERE to_date = '9999-01-01' ), sal_diff AS ( -- 一次性计算所有在职员工的薪资差值 SELECT ef.emp_no, ec.current_salary - ef.first_salary AS salary_diff FROM emp_first_sal ef INNER JOIN emp_current_sal ec ON ef.emp_no = ec.emp_no ) -- 取差值最小的10条 (SELECT emp_no, salary_diff FROM sal_diff ORDER BY salary_diff ASC LIMIT 10) UNION ALL -- 取差值最大的10条 (SELECT emp_no, salary_diff FROM sal_diff ORDER BY salary_diff DESC LIMIT 10);
如果你的数据库支持窗口函数ROW_NUMBER(),还可以进一步简化,只需要一次排序即可拿到两类结果:
WITH emp_first_sal AS ( SELECT s.emp_no, s.salary AS first_salary FROM salaries s INNER JOIN ( SELECT emp_no, MIN(from_date) AS entry_date FROM salaries GROUP BY emp_no ) t ON s.emp_no = t.emp_no AND s.from_date = t.entry_date ), emp_current_sal AS ( SELECT emp_no, salary AS current_salary FROM salaries WHERE to_date = '9999-01-01' ), sal_diff AS ( SELECT ef.emp_no, ec.current_salary - ef.first_salary AS salary_diff, ROW_NUMBER() OVER(ORDER BY ec.current_salary - ef.first_salary ASC) AS rn_asc, ROW_NUMBER() OVER(ORDER BY ec.current_salary - ef.first_salary DESC) AS rn_desc FROM emp_first_sal ef INNER JOIN emp_current_sal ec ON ef.emp_no = ec.emp_no ) SELECT emp_no, salary_diff FROM sal_diff WHERE rn_asc <=10 OR rn_desc <=10;
优化效果说明
优化后查询仅需扫描必要的索引数据,避免了全表扫描和重复计算,执行耗时可降低90%以上。
内容的提问来源于stack exchange,提问作者student8956
相关产品推荐
相关产品推荐

