You need to enable JavaScript to run this app. 如何优化查询在职员工入职与当前薪资差Top10、末10的SQL语句
优惠活动
大模型
产品
解决方案
定价
更多

如何优化查询在职员工入职与当前薪资差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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.16 05:15:07