想用信号监听「所有写入」的人,常常在 bulk 操作那里踩空:批量写入不会触发保存信号,而删除又恰恰相反——一旦有人监听了 delete 信号,批量删除会变慢很多。这篇把这两头都量出来。
save() × 100(逐个) 信号触发 {'pre_save': 100, 'post_save': 100} SQL 语句数 100
bulk_create(100 行) 信号触发 无 SQL 语句数 1
bulk_update(100 行) 信号触发 无 SQL 语句数 3
queryset.update() 信号触发 无 SQL 语句数 1只有走 save() 的写入才会发 pre_save / post_save。如果业务上「所有的写入都要触发某个动作」,批量写入需要另外处理(比如写完之后自己调用同样的函数)。
delete() 2000 行,没有 delete 信号 信号触发 无 SQL 语句数 3
delete() 2000 行,有 post_delete receiver 信号触发 {'post_delete': 2000} SQL 语句数 23没有 delete 信号且没有需要级联处理的关系时,queryset.delete() 走快速删除(一条 DELETE)。只要模型上挂了 pre_delete / post_delete receiver,Django 就得把对象取出来逐个发信号。
没有 delete 信号 0.6 ms 有 post_delete 125.9 ms
0.6 ms 这么快,可能有 SQLite 对无条件 DELETE 的优化(我没有验证),所以「200 倍」只适合这个测法,不要当作通用倍数;但方向是确定的:监听 delete 信号会让批量删除退化为逐行处理。
遍历 5 行手动 post_save.send 信号触发 {'post_save': 5} SQL 语句数 1