双外键场景下未匹配员工查询及性能优化技术问询
针对Companies与Employees表的查询优化方案
针对你提出的两个查询需求,我整理了高效的SQL写法和性能优化建议,帮你解决之前性能不佳的问题:
需求1:获取所有在Companies表中列出的公司任职的员工
即员工的CompId或FilId至少有一个关联到Companies表中的记录。
高效SQL写法
推荐使用UNION替代OR(避免OR导致索引失效的问题):
SELECT e.* FROM Employees e JOIN Companies c ON c.Id = e.CompId UNION SELECT e.* FROM Employees e JOIN Companies c ON c.Id = e.FilId;
如果你的数据库优化器对OR的支持较好,也可以用更简洁的EXISTS写法:
SELECT e.* FROM Employees e WHERE EXISTS (SELECT 1 FROM Companies c WHERE c.Id = e.CompId) OR EXISTS (SELECT 1 FROM Companies c WHERE c.Id = e.FilId);
性能优化关键
- 确保
Companies.Id是主键(默认自带聚簇索引,查询效率最高) - 给
Employees表的CompId和FilId分别创建独立的非聚簇索引:
这两个索引能让数据库快速定位到关联Companies的员工记录,避免全表扫描。CREATE INDEX idx_employees_compid ON Employees(CompId); CREATE INDEX idx_employees_filid ON Employees(FilId);
需求2:获取所有未在Companies表中列出的公司任职的员工
即员工的CompId和FilId均未在Companies表中存在。
高效SQL写法
推荐使用NOT EXISTS(比NOT IN更安全,不会因Companies.Id存在NULL值导致结果异常):
SELECT e.* FROM Employees e WHERE NOT EXISTS (SELECT 1 FROM Companies c WHERE c.Id = e.CompId) AND NOT EXISTS (SELECT 1 FROM Companies c WHERE c.Id = e.FilId);
也可以用LEFT JOIN + IS NULL的写法,性能和NOT EXISTS相近:
SELECT e.* FROM Employees e LEFT JOIN Companies c1 ON c1.Id = e.CompId LEFT JOIN Companies c2 ON c2.Id = e.FilId WHERE c1.Id IS NULL AND c2.Id IS NULL;
性能优化关键
- 复用需求1中创建的
idx_employees_compid和idx_employees_filid索引,数据库能快速过滤掉已关联Companies的员工 - 如果只需要查询员工的部分字段,可以创建覆盖索引,避免回表查询(比如只需要员工ID和姓名):
CREATE INDEX idx_employees_compid_covering ON Employees(CompId) INCLUDE (Id, Name); CREATE INDEX idx_employees_filid_covering ON Employees(FilId) INCLUDE (Id, Name);
内容的提问来源于stack exchange,提问作者Denis Evseev
相关产品推荐
相关产品推荐

