mysql在招聘网站中的职位和简历数据库设计

16次阅读

职位表应使用tinyint状态码+独立时间戳字段(published_at/closed_at)并建立联合索引,简历表需拆分教育/工作等子表避免字段爆炸,匹配采用标签倒排索引而非LIKE,申请记录须用事件表分离流程动作。

mysql在招聘网站中的职位和简历数据库设计

职位表 jobs 怎么设计才支持快速筛选和状态流转

招聘网站的职位不是静态信息,要支撑「发布/下架/过期/暂停」多种状态,还要被搜索、排序、推荐。直接用一个 status 字符串字段会埋坑:'online''offline' 这类值难索引,也容易拼错。

建议用 tinyint + 注释方式定义状态码,配合 created_atpublished_atclosed_at 三个时间戳字段,而不是只靠一个 updated_at 推断业务阶段:

CREATE TABLE `jobs` (   `id` bigint unsigned NOT NULL AUTO_INCREMENT,   `title` varchar(128) NOT NULL,   `company_id` bigint unsigned NOT NULL,   `status` tinyint NOT NULL DEFAULT 1 COMMENT '1=草稿, 2=已发布, 3=已关闭, 4=已过期',   `published_at` datetime NULL DEFAULT NULL,   `closed_at` datetime NULL DEFAULT NULL,   `created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,   `updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,   PRIMARY KEY (`id`),   KEY `idx_company_status_published` (`company_id`, `status`, `published_at`) ) ENGINE=InnoDB;
  • status 不用 enummysql enum 在 ALTER 时锁表且不易迁移;tinyint 更易写条件查询,比如 WHERE status IN (2,3)
  • 单独建 published_at:避免用 status = 2 AND updated_at > DATE_SUB(NOW(), INTERVAL 7 DAY) 这种模糊逻辑判断“最近发布的职位”
  • 联合索引 idx_company_status_published 覆盖高频查询:HR 查自己公司所有「已发布」职位,或运营查某状态下的最新职位

简历resumes 如何避免字段爆炸又保留扩展性

候选人填的信息五花八门:教育经历可能有 3 段,工作经历可能有 5 段,证书可能有 N 个。如果全在主表加 edu_1_schooledu_2_school……后期改字段、写查询、做统计全是灾难。

主表只存「快照式」核心字段,结构化数据拆到关联表:

CREATE TABLE `resumes` (   `id` bigint unsigned NOT NULL AUTO_INCREMENT,   `user_id` bigint unsigned NOT NULL,   `name` varchar(64) NOT NULL,   `phone` varchar(20) NULL,   `email` varchar(128) NULL,   `current_salary` decimal(10,2) NULL,   `expected_salary_min` decimal(10,2) NULL,   `expected_salary_max` decimal(10,2) NULL,   `job_status` tinyint NOT NULL DEFAULT 1 COMMENT '1=在职, 2=离职, 3=应届',   `updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,   PRIMARY KEY (`id`),   UNIQUE KEY `uk_user_id` (`user_id`) );  CREATE TABLE `resume_educations` (   `id` bigint unsigned NOT NULL AUTO_INCREMENT,   `resume_id` bigint unsigned NOT NULL,   `school` varchar(128) NOT NULL,   `degree` varchar(32) NULL,   `major` varchar(64) NULL,   `start_year` smallint NULL,   `end_year` smallint NULL,   `is_current` tinyint NOT NULL DEFAULT 0,   PRIMARY KEY (`id`),   KEY `idx_resume_id` (`resume_id`) );
  • 主表不存数组型字段(如 jsON 存多段经历):虽然 MySQL 5.7+ 支持 json,但无法高效按「某段教育经历的学校名」做索引查询,也难做范围统计(例如“近 3 年毕业的硕士人数”)
  • resume_educationsresume_work_experiences 等子表必须带 resume_id 索引,否则 JOIN 时性能断崖下跌
  • 不要为「期望城市」「可接受加班强度」等低频字段提前预留一堆 extra_1extra_10:真有需要时再加表或用宽表异步聚合

职位与简历怎么匹配 —— 关键不是 LIKE,而是倒排索引思路

用户搜“java 后端 上海”,后台不能简单写 WHERE title LIKE '%Java%' AND city = '上海'。这种写法无法利用索引,更没法支持「Java 或 python」、「3 年经验以上」、「熟悉 spring Cloud」等组合条件。

实际可行的做法是:把职位和简历都转成「标签向量」,存在独立匹配表中,用整数位运算或预计算提升效率:

CREATE TABLE `job_tags` (   `job_id` bigint unsigned NOT NULL,   `tag_id` int unsigned NOT NULL,   PRIMARY KEY (`job_id`, `tag_id`),   KEY `idx_tag_id` (`tag_id`) );  CREATE TABLE `tags` (   `id` int unsigned NOT NULL AUTO_INCREMENT,   `name` varchar(64) NOT NULL,   `category` varchar(32) NOT NULL COMMENT 'skill/company/degree/location',   PRIMARY KEY (`id`),   UNIQUE KEY `uk_name_cat` (`name`, `category`) );
  • 插入职位时,解析 description 提取关键词(如“spring boot”、“docker”),查 tags 表获取 tag_id,批量写入 job_tags
  • 查“Java + 上海 + 3年经验”的简历,就变成:先查出 tag_id 列表,再用 select resume_id FROM resume_tags WHERE tag_id IN (101,205,311) GROUP BY resume_id HAVING count(DISTINCT tag_id) = 3
  • 别依赖全文索引(FULLTEXT):对中文分词支持弱,且无法和结构化字段(如薪资范围、学历要求)做混合过滤

为什么不要用单表存储「职位申请记录」

有人把 job_applications 设计成大宽表:job_idresume_idstatusscoreinterviewer_idfeedbacknext_step_at……看着完整,但很快会出问题。

真实流程中,一次申请可能经历「投递→HR 初筛→技术面试→HR 复谈→Offer→拒签」,每个环节产生新数据(面试纪要、评分细则、录音摘要链接),不是简单改一个 status 就完事。

  • 把流程动作拆成事件表 application_events:每行记录一次状态变更、一次反馈提交、一次提醒发送,带 operator_idcreated_at
  • job_applications 主表只保留最简态:idjob_idresume_idcurrent_statuscreated_at,用于列表页快速展示
  • 历史操作、附件、评分明细全部下沉,避免主表越来越大、备份越来越慢、某个字段改类型牵一发而动全身

复杂度藏在关联关系里,不在单表字段多寡上。字段越多的表,越早遇到 ALTER column 锁表超时、从库延迟飙升、ORM 映射臃肿的问题。

text=ZqhQzanResources