如何让Directus在PostgreSQL子表创建项时执行BULK INSERT优化性能
解决Directus子表批量创建时的单条INSERT性能问题
针对你提到的Directus处理子表items.create时逐个执行INSERT导致的性能瓶颈,以下是几个可行的优化方案:
1. 改用Directus批量创建API接口
Directus原生支持批量创建条目,无需额外扩展。你只需要调整API调用方式:
- 原本单次调用
POST /items/your_child_collection传入单个对象,现在改为传入对象数组 - 示例请求体:
[ {"session_id": "sess_001", "value": "foo"}, {"session_id": "sess_001", "value": "bar"}, {"session_id": "sess_001", "value": "baz"} ] - 这样Directus会自动生成PostgreSQL的
BULK INSERT语句,而非逐条执行INSERT
如果是通过工作流触发的创建逻辑,需要修改工作流:不要循环调用单条创建接口,而是先收集所有待插入的数据,最后一次性调用批量接口。
2. 自定义Hook实现底层批量插入
如果工作流或业务逻辑无法直接改用批量API,可以通过Directus的自定义Hook拦截创建请求,手动执行批量插入:
- 创建一个
items.create的before hook,判断传入的是否为批量数据(或主动收集批量数据) - 使用Directus内置的Knex客户端执行批量插入,示例代码:
export default defineHook(({ action, database }) => { action('items.create', async (payload, meta) => { // 仅针对目标子表执行逻辑 if (meta.collection !== 'sessions_child') return; // 处理批量数据(如果payload是数组) const rows = Array.isArray(payload) ? payload : [payload]; // 执行批量插入 await database.insert(rows).into('sessions_child'); // 跳过Directus默认的单条插入逻辑 return { skipDefault: true }; }); }); - 注意:需要确保Hook的权限足够,同时处理事务和字段验证逻辑,避免数据不一致。
3. 数据库层面辅助优化
除了Directus端的调整,还可以优化PostgreSQL配置提升批量插入性能:
- 批量插入期间临时关闭
autovacuum(插入完成后恢复) - 调整
work_mem和maintenance_work_mem参数,提升内存分配 - 批量插入前禁用目标表的非必要索引,插入完成后重新创建(如果业务允许短暂的索引不可用)
关键注意事项
- 批量操作必须包裹在事务中,确保数据原子性
- 验证所有待插入数据符合Directus的字段规则(必填项、数据类型等)
- 确保调用批量接口的用户拥有目标子表的创建权限
内容的提问来源于stack exchange,提问作者Philippe PERON
相关产品推荐
相关产品推荐

