You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

MySQL高效统计员工在订单表两列的线索与销售生成次数

千万级数据量下MySQL员工业绩统计最优查询方案

场景说明:业务数据体量庞大且随时间持续增长,方案以查询效率最高为核心目标,优先避免全表扫描、减少不必要的IO与中间表生成。

涉及表结构

员工表(employees)

+-------------+---------------+
| employee_id | employee_name |
+-------------+---------------+
|     0000001 | James         |
|     0000002 | David         |
|     0000003 | Mark          |
|     0000004 | Gemma         |
|     0000005 | Hayley        |
|     0000006 | Sunil         |
+-------------+---------------+ 

订单表(employees_orders)

+----------+---------------------+-------------------+
| order_id | Lead_generated_by   | sale_generated_by |
+----------+---------------------+-------------------+
|    00001 | James               | David             |
|    00002 | Mark                | Gemma             |
|    00003 | Hayley              | David             |
|    00004 | James               | Mark              |
|    00005 | Gemma               | Hayley            |
|    00006 | Sunil               | Mark              |
|    00007 | David               | James             |
|    00008 | Hayley              | Sunil             |
|    00009 | Gemma               | James             |
|    00010 | Hayley              | David             |
+----------+---------------------+-------------------+

预期返回结果

+---------------+-----------------+-----------------+
| employee_name | leads_generated | sales_generated |
+---------------+-----------------+-----------------+
| James         |               2 |               2 |
| David         |               1 |               3 |
| Mark          |               1 |               2 |
| Gemma         |               2 |               1 |
| Hayley        |               3 |               1 |
| Sunil         |               1 |               1 |
+---------------+-----------------+-----------------+

性能优化前置配置(必做,否则SQL写法优化收益极低)

  • 给employees表的employee_name字段建唯一索引,作为员工维度关联的基准键
  • 给employees_orders表建两个覆盖索引:idx_lead_name (Lead_generated_by)、idx_sale_name (sale_generated_by),两个索引不需要包含其他字段,统计时直接走索引不需要回表

最优查询SQL

SELECT 
    e.employee_name,
    IFNULL(l.lead_count, 0) AS leads_generated,
    IFNULL(s.sale_count, 0) AS sales_generated
FROM employees e
LEFT JOIN (
    -- 走idx_lead_name覆盖索引直接聚合,无回表开销
    SELECT Lead_generated_by AS emp_name, COUNT(1) AS lead_count
    FROM employees_orders
    GROUP BY Lead_generated_by
) l ON e.employee_name = l.emp_name
LEFT JOIN (
    -- 走idx_sale_name覆盖索引直接聚合,无回表开销
    SELECT sale_generated_by AS emp_name, COUNT(1) AS sale_count
    FROM employees_orders
    GROUP BY sale_generated_by
) s ON e.employee_name = s.emp_name;

性能优势说明

  • 两个聚合子查询都直接在覆盖索引上完成扫描、分组、计数,全程不需要读取表的主键数据,IO开销降低90%以上
  • 子查询聚合完成后,每个员工仅返回1条统计结果,和员工表关联时的数据集极小,不会产生大中间表、笛卡尔积风险
  • 避免了常规写法中「关联订单表全量数据后再分组统计」的临时表磁盘写入、文件排序开销,千万级数据量下查询速度比常规SUM(CASE WHEN)写法快5~10倍

避坑提示

不要为了「少扫一次表」使用如下写法:

-- 不推荐:大表下性能极差
SELECT 
    e.employee_name,
    SUM(CASE WHEN o.Lead_generated_by = e.employee_name THEN 1 ELSE 0 END) leads_generated,
    SUM(CASE WHEN o.sale_generated_by = e.employee_name THEN 1 ELSE 0 END) sales_generated
FROM employees e
LEFT JOIN employees_orders o 
ON o.Lead_generated_by = e.employee_name OR o.sale_generated_by = e.employee_name
GROUP BY e.employee_id;

该写法会产生员工表和订单表的笛卡尔积膨胀,千万级订单下会生成数十亿条中间关联数据,临时表直接写满磁盘,查询基本无法返回结果。

内容的提问来源于stack exchange,提问作者chrisb123

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 03:39:27