应使用DENSE_RANK() OVER (PARTITION BY job_id ORDER BY matching_score DESC)实现同分同名次且不跳号的岗位内匹配度排名,必须配合PARTITION BY按岗位分组,匹配度字段需预计算并建立索引以保障性能。

窗口函数怎么给求职者按匹配度排序
直接用 ROW_NUMBER()、RANK() 或 DENSE_RANK() 就能对同一岗位下的求职者按匹配度打排名,但必须配合 PARTITION BY 按岗位分组,否则全表排成一列就失去业务意义。匹配度字段通常是预计算好的数值(比如简历关键词重合率、技能加权得分),不能在窗口函数里实时算模糊匹配——那会拖慢查询且无法索引加速。
常见错误是漏写 PARTITION BY job_id,结果所有求职者被混在一起排名,HR看到“张三在全部候选人中排第2”毫无参考价值;另一个坑是用了 ROW_NUMBER() 但业务上要求同分同名次,这时得换 RANK(),否则两个95分的候选人会被强行拆成第1和第2名。
-
RANK():相同匹配度并列,跳过后续名次(95,95,87 → 1,1,3) -
DENSE_RANK():相同匹配度并列,不跳名次(95,95,87 → 1,1,2) - 排序字段建议用
matching_score DESC,避免升序导致高分排末尾
匹配度分数怎么从简历字段动态生成
窗口函数本身不负责算匹配度,它只排序。真正要动脑的是怎么把非结构化简历转成可比数字。别在 SELECT 里写一堆 CASE WHEN 去匹配“Java”“Spring”“分布式”,效率低还难维护。推荐提前在 ETL 阶段或物化视图里固化:skills_weighted_score(技能权重和)、years_of_experience(年限校准值)、edu_match(学历门槛达标为1否则0)——这些字段存进候选人快照表,窗口函数只读它们。
如果真要临时算,至少用 ts_vector + ts_rank(PostgreSQL)或 CONTAINS(SQL Server)这类带索引支持的文本匹配,而不是 LIKE '%Java%' 全表扫描。实测某招聘库用 LIKE 算匹配度,10万简历查一个岗位平均 8.2 秒;换成预计算字段后压到 120ms 内。
- 避免在
ORDER BY子句里调用 UDF 或复杂表达式,窗口函数会反复执行 - MySQL 8.0+ 支持窗口函数,但不支持
ts_rank,得靠应用层或前置计算 - 匹配度字段务必设为
NOT NULL,否则NULL候选人会排最前或最后,取决于数据库默认行为
如何让HR看到“本岗位前3名”而不暴露全部数据
直接 WHERE rank 会报错——窗口函数不能在 WHERE 里引用。必须套一层子查询或 CTE。CTE 更清晰,也方便后续加筛选(比如只看已投递未拒信的候选人)。
status = 'applied'
- 别依赖数据库自动分页,尤其当匹配度分布不均时(大量85–88分扎堆)
- PostgreSQL 的
OFFSET在大偏移量下性能差,用游标分页(WHERE rank_in_job > last_seen_rank)更靠谱 - MySQL 8.0 的窗口函数不支持在子查询里嵌套窗口,CTE 是唯一安全写法
实际跑起来最易忽略的,是匹配度字段的更新延迟——简历解析服务和招聘库同步有 lag,窗口函数永远读的是快照时刻的分数。如果 HR 刚点开页面就刷新,看到的可能是 15 分钟前的排名。











