问卷表与题目表应通过questionnaire_id外键关联,题目表中该字段非空并设on delete cascade,同时添加索引;若需题目复用则引入中间表。
问卷表和题目表如何用外键关联才不翻车
问卷系统最常崩在「一对多」关系设计上。别把所有题目硬塞进一张表,也别让 questionnaire_id 在题目表里允许为 NULL——这会导致查问卷时漏题或关联失败。
正确做法是两张主表加一张中间表(如果支持题目复用);若题目只归属单个问卷,直接在题目表设 questionnaire_id 外键并加索引:
CREATE TABLE questionnaire (
id INT PRIMARY KEY AUTO_INCREMENT,
title VARCHAR(255) NOT NULL,
status TINYINT DEFAULT 1 -- 1=启用, 0=停用
);
<p>CREATE TABLE question (
id INT PRIMARY KEY AUTO_INCREMENT,
questionnaire_id INT NOT NULL,
content TEXT NOT NULL,
type ENUM('single', 'multiple', 'text') NOT NULL,
sort_order TINYINT DEFAULT 0,
FOREIGN KEY (questionnaire_id) REFERENCES questionnaire(id) ON DELETE CASCADE
);</p><p>-- 给外键字段加索引(InnoDB 外键自动建索引,但显式声明更稳妥)
CREATE INDEX idx_question_qid ON question(questionnaire_id);
-
ON DELETE CASCADE能避免删问卷后残留“孤儿题目”,但上线前务必确认业务是否真允许级联删除 - 别用
TEXT存选项内容(如单选的 A/B/C),应拆到option表,否则改选项时要字符串替换,极易出错 -
sort_order用TINYINT足够(最多 255 题),比用INT节省空间且排序更快
用户答题记录怎么存才查得快又不锁表
答题记录是写多读少、但偶尔要按用户/问卷聚合统计的场景。别用一张大宽表存所有答案,更别把 JSON 字符串塞进一个字段里——后期想统计“第3题选A的人数”就得全表扫描+JSON 解析,慢且无法走索引。
推荐三张表分层存储: