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

职位表 jobs 怎么设计才支持快速筛选和状态流转
招聘网站的职位不是静态信息,要支撑「发布/下架/过期/暂停」多种状态,还要被搜索、排序、推荐。直接用一个 status 字符串字段会埋坑:'online'、'offline' 这类值难索引,也容易拼错。
建议用 tinyint + 注释方式定义状态码,配合 created_at、published_at、closed_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不用 enum:MySQL 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_school、edu_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_educations和resume_work_experiences等子表必须带resume_id索引,否则 JOIN 时性能断崖下跌 - 不要为「期望城市」「可接受加班强度」等低频字段提前预留一堆
extra_1~extra_10:真有需要时再加表或用宽表异步聚合
职位与简历怎么匹配 —— 关键不是 LIKE,而是倒排索引思路
用户搜“Java 后端 上海”,后台不能简单写 WHERE title LIKE '%Java%' AND city = '上海'。这种写法无法利用索引,更没法支持「Java 或 Python」、「3 年经验以上」、「熟悉 Spring Cloud」等组合条件。
SmartB2B 是一款基于PHP、MySQL、Smarty的B2B行业电子商务网站管理系统,系统提供了供求模型、企业模型、产品模型、人才招聘模型、资讯模型等模块,适用于想在行业里取得领先地位的企业快速假设B2B网站,可以运行于Linux与Windows等多重服务器环境,安装方便,使用灵活。 系统使用当前流行的PHP语言开发,以MySQL为数据库,采用B/S架构,MVC模式开发。融入了模型化、模板
实际可行的做法是:把职位和简历都转成「标签向量」,存在独立匹配表中,用整数位运算或预计算提升效率:
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_id、resume_id、status、score、interviewer_id、feedback、next_step_at……看着完整,但很快会出问题。
真实流程中,一次申请可能经历「投递→HR 初筛→技术面试→HR 复谈→Offer→拒签」,每个环节产生新数据(面试纪要、评分细则、录音摘要链接),不是简单改一个 status 就完事。
- 把流程动作拆成事件表
application_events:每行记录一次状态变更、一次反馈提交、一次提醒发送,带operator_id和created_at -
job_applications主表只保留最简态:id、job_id、resume_id、current_status、created_at,用于列表页快速展示 - 历史操作、附件、评分明细全部下沉,避免主表越来越大、备份越来越慢、某个字段改类型牵一发而动全身
复杂度藏在关联关系里,不在单表字段多寡上。字段越多的表,越早遇到 ALTER COLUMN 锁表超时、从库延迟飙升、ORM 映射臃肿的问题。









