面试题答案
一键面试查询语句
SELECT sub.employee_id, sub.employee_name, sub.manager_id, sub.hire_date
FROM (
SELECT
o.employee_id,
o.employee_name,
o.manager_id,
o.hire_date,
ROW_NUMBER() OVER (PARTITION BY top_manager.employee_id ORDER BY o.hire_date) AS rn
FROM
organization o
JOIN
(
SELECT
employee_id
FROM
organization
WHERE
manager_id IS NULL
) top_manager
ON
o.manager_id = top_manager.employee_id OR o.employee_id = top_manager.employee_id
) sub
WHERE sub.rn = 1;
解释
- 首先通过子查询
top_manager
找到所有顶层领导(即manager_id
为NULL
的员工)。 - 然后将
organization
表与top_manager
子查询进行连接,连接条件是当前员工的manager_id
等于顶层领导的employee_id
或者当前员工本身就是顶层领导。 - 使用
ROW_NUMBER()
窗口函数,按照每个顶层领导分区,并根据hire_date
(假设表中有这个字段,题目未提及,这里假设为入职时间字段)进行排序,为每个分区内的员工生成一个序号。 - 最后在最外层查询中选择序号为1的员工,即每个部门中入职时间最早的员工。
大数据量下的优化
索引设计
- 单列索引:
- 在
organization
表的manager_id
字段上创建索引,因为连接条件中使用到了这个字段,在大数据量下,索引可以加快连接的速度。
CREATE INDEX idx_manager_id ON organization(manager_id);
- 如果
hire_date
字段没有索引,也创建一个索引,以加快ROW_NUMBER()
函数中排序操作的速度。
CREATE INDEX idx_hire_date ON organization(hire_date);
- 在
- 复合索引:
- 考虑创建复合索引
(manager_id, hire_date)
,这样在连接和排序时可以利用到该复合索引,提高查询效率。
CREATE INDEX idx_manager_hire ON organization(manager_id, hire_date);
- 考虑创建复合索引
查询改写
- CTE(公共表表达式):
- 将顶层领导的查询部分使用CTE来改写,使查询结构更清晰,并且某些数据库系统对CTE有更好的优化策略。
WITH top_manager AS ( SELECT employee_id FROM organization WHERE manager_id IS NULL ) SELECT sub.employee_id, sub.employee_name, sub.manager_id, sub.hire_date FROM ( SELECT o.employee_id, o.employee_name, o.manager_id, o.hire_date, ROW_NUMBER() OVER (PARTITION BY top_manager.employee_id ORDER BY o.hire_date) AS rn FROM organization o JOIN top_manager ON o.manager_id = top_manager.employee_id OR o.employee_id = top_manager.employee_id ) sub WHERE sub.rn = 1;
- 避免笛卡尔积:
- 在大数据量下,确保连接条件尽可能准确,避免产生笛卡尔积。这里的连接条件已经相对准确,但在复杂查询场景下,要注意这一点。
- 分区表:
- 如果数据量非常大,可以考虑对
organization
表进行分区,例如按照入职时间分区,这样在查询时可以减少扫描的数据量。具体的分区方式和实现依赖于所使用的数据库系统。例如在MySQL中,可以使用RANGE
分区:
CREATE TABLE organization ( employee_id INT, employee_name VARCHAR(255), manager_id INT, hire_date DATE ) PARTITION BY RANGE (YEAR(hire_date)) ( PARTITION p0 VALUES LESS THAN (2010), PARTITION p1 VALUES LESS THAN (2015), PARTITION p2 VALUES LESS THAN (2020), PARTITION p3 VALUES LESS THAN (2025), PARTITION p4 VALUES LESS THAN (MAXVALUE) );
- 如果数据量非常大,可以考虑对
这样在查询入职时间最早的员工时,数据库可以根据分区快速定位到相应的数据。