问题背景:
我用sqlalchemy_mptt构建了一个多级分类项目,数据库用了sqlite。随着数据条数越来越多,写入速度逐渐变慢,一棵树的插入甚至需要1分钟,远远不能满足需求
分析思路:
1. 批量插入
代码中使用的是
session.add(node)
session.commit()
我首先怀疑因数据逐条插入,导致速度慢。试图换成批量插入。
session.bulk_insert_mappings(Tree, insert_rows)
但批量插入需要手动实现一个预排序树,这样一来再用sqlalchemy_mptt就没有意义了,只会徒增系统复杂性,遂放弃。
2. 建索引
通过读sqlalchemy_mptt 的源码,我发现在数据插入(包括删改)的时候,有两个关键查找操作:
# 建一颗新的树时,需要寻找当前库中最大的tree_id func.max(table.c.tree_id) + 1 # 子节点插入时,每次都要查询父节点的rgt, lft, level等字段 table_pk == instance.parent_id
而sqlalchemy_mptt 在混入ORM对象时,只对rgt, lft, level 设置了索引,导致每次 CRUD操作都需要从头到尾查找。
解决方案:
添加两个索引:
treeid_idx = Index('treeid_idx', Tree.tree_id) treeid_idx.create(bind=engine) parent_idx = Index('parent_idx', Tree.parent_id) parent_idx.create(bind=engine)
经测试,添加tree_id索引大约能快4倍,添加parent_id大约快100倍,加起来就能够满足快速插入的需求了