Laravel 低代码表单查询优化:从 K-V 到宽表读模型
K-V 解决了字段动态变化的问题,但列表查询会变麻烦。数据量小的时候,CASE WHEN 转一下还能接受;数据多了,再叠上筛选、排序、模糊查询,SQL 就会越来越重。
一、K-V 为什么会出现
动态表单里,字段变化是常态。常见存法是一张主表保存记录,一张明细表保存字段。
CREATE TABLE form_record (
id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
form_id BIGINT UNSIGNED NOT NULL,
created_at DATETIME,
updated_at DATETIME
);
CREATE TABLE form_record_field (
id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
record_id BIGINT UNSIGNED NOT NULL,
field_key VARCHAR(100) NOT NULL,
field_value TEXT NULL,
KEY idx_record_key (record_id, field_key)
);
record_id field_key field_value
--------- --------- -----------
1 name 张三
1 mobile 13800000001
1 status paid
二、慢在哪里
列表页要的是一行一条数据,但 K-V 存出来是一行一个字段。所以查询时经常要先把字段横向展开。
SELECT
r.id,
MAX(CASE f.field_key WHEN 'name' THEN f.field_value ELSE '' END) AS name,
MAX(CASE f.field_key WHEN 'mobile' THEN f.field_value ELSE '' END) AS mobile,
MAX(CASE f.field_key WHEN 'status' THEN f.field_value ELSE '' END) AS status
FROM form_record r
LEFT JOIN form_record_field f ON f.record_id = r.id
WHERE r.form_id = 1001
GROUP BY r.id
HAVING status = 'paid';
真正麻烦的是再叠模糊查询:
HAVING name LIKE '%张%'
AND mobile LIKE '%138%'
这时候不是某一个索引没建好,而是查询形态本身就比较吃力。
三、不要急着推翻 K-V
K-V 不是坏设计。它解决的是字段动态变化的问题。低代码表单里,这个问题绕不开。
四、给表单建一张宽表
可以按表单维度拆宽表。比如表单 1001,单独有一张查询表:
form_1001_flat
CREATE TABLE form_1001_flat (
id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
record_id BIGINT UNSIGNED NOT NULL,
form_id BIGINT UNSIGNED NOT NULL,
created_at DATETIME,
updated_at DATETIME,
name LONGTEXT NULL,
mobile LONGTEXT NULL,
status LONGTEXT NULL,
remark LONGTEXT NULL,
UNIQUE KEY uk_record_id (record_id),
KEY idx_created_at (created_at)
);
原来要聚合的查询,现在可以直接查列:
SELECT record_id, name, mobile, status
FROM form_1001_flat
WHERE status = 'paid'
AND name LIKE '%张%'
ORDER BY created_at DESC;
五、写入和查询分开
写入时还是先进 K-V,然后异步同步到宽表。
form_record_field -> form_1001_flat
record_id name mobile status
--------- ---- ----------- ------
1 张三 13800000001 paid
Laravel 里可以把同步放到队列里做。新增、修改、删除表单数据时,发一个轻量任务,把当前记录重新摊平成宽表行。
六、开关要留好
宽表读模型不要一上来就全量切。更稳的是按表单控制状态。
off 未开启
building 生成中
enabled 已启用
failed 失败
1. 创建宽表
2. 补齐字段列
3. 回填历史数据
4. 校验行数
5. 切换查询入口
如果校验不过,就继续走旧的 K-V 查询。读模型是为了提速,不应该影响原始数据安全。
七、字段改名怎么办
低代码里字段改名很常见。如果只靠 field_key,会分不清老字段改名,还是删除后新建了同名字段。
所以最好给字段一个稳定身份:
field_uid
字段名可以变,字段身份不变。宽表列名可以继续用当前字段名,但内部要知道它对应的是哪个字段身份。
八、最后
K-V 适合写,宽表适合查。低代码表单的数据模型,通常不能只选一个。
K-V:保存原始数据
宽表:服务列表查询
队列:负责同步和回填
开关:保证可以随时退回
请先 登录后发表评论 ~