数据库中处理同一实体多类型的最佳方案:以线上/线下课程为例
数据库设计最优方案:类表继承结构
表结构设计
1. 基础公共表
首先定义两张全量公共表,存储两类课程、课时共有的通用字段:
- 课程主表
courses
存储所有课程通用属性,用于区分课程类型:id:主键course_type:枚举值,固定为online/offline,标记课程类型,非空- 其余通用字段:课程名称、简介、上下架状态、创建时间等
- 课时基础表
course_lessons
存储所有课时通用属性,统一维护和课程的关联关系:id:主键course_id:外键关联courses.id,非空lesson_type:枚举值,固定为online/offline,和所属课程的course_type保持一致,非空,建议加索引sort:课时排序序号title:课时名称- 其余两类课时共有的通用字段
2. 类型专属扩展表
分别为两类课时创建独立扩展表,仅存储对应类型的专属字段,无冗余空值:
- 线上课时扩展表
online_lesson_details
存储线上课专属的日期时间类字段:id:主键lesson_id:外键关联course_lessons.id,加唯一索引,保证一个基础课时仅对应一条线上扩展记录start_time:开课/直播时间end_time:课程结束时间live_room_id:直播间ID- 其余线上课时专属字段
- 线下课时扩展表
offline_lesson_details
存储线下课专属的视频、观看状态类字段:id:主键lesson_id:外键关联course_lessons.id,加唯一索引,保证一个基础课时仅对应一条线下扩展记录video_url:视频文件存储地址chapter_info:章节相关信息is_watched:用户观看状态标记- 其余线下课时专属字段
方案优势
- 无数据冗余:所有字段仅存储一次,不存在大量空值占用存储空间的问题
- 关联关系统一:课程和课时的关联仅通过
course_lessons.course_id维护,不需要定义两套独立关联 - 扩展性强:后续如果新增其他类型课程,仅需要新增对应的扩展表即可,不需要修改原有表结构
高效访问字段方案
1. 公共字段查询(课时列表等场景)
直接查询course_lessons基础表即可,不需要关联任何扩展表,性能最优,示例SQL:
SELECT id, title, sort FROM course_lessons WHERE course_id = 123 ORDER BY sort ASC;
2. 详情字段查询(单课时详情等场景)
根据业务性能要求二选一即可:
- 单次关联查询:一次SQL拿到所有需要的字段,无需应用层判断类型
SELECT cl.*, old.start_time, old.end_time, old.live_room_id, ofd.video_url, ofd.chapter_info, ofd.is_watched FROM course_lessons cl LEFT JOIN online_lesson_details old ON cl.lesson_type = 'online' AND cl.id = old.lesson_id LEFT JOIN offline_lesson_details ofd ON cl.lesson_type = 'offline' AND cl.id = ofd.lesson_id WHERE cl.id = 456;
查询结果中,对应类型的扩展字段自动有值,另一类的扩展字段为null,业务层直接取值即可,不需要额外判断课程类型。
- 按需分层查询:适合扩展字段多、性能要求高的场景,先查询基础表拿到
lesson_type和id,再对应查询对应类型的扩展表,避免关联不必要的表,减少IO开销。
3. 写入逻辑
创建课时时,先写入course_lessons基础表拿到lesson_id,再根据课程类型写入对应的扩展表即可,两类课时的写入逻辑完全隔离,不会互相干扰。
内容的提问来源于stack exchange,提问作者Hosein Shendabadi
相关产品推荐
相关产品推荐

