项目是 Django Admin 的简单的后台,有一个表大概有160万左右的数据,打开一次需要将近20s,借助django-debug-toolbar 进行优化一下。
背景
Django Admin 构建的后台,使用Simpleui优化显示效果,
数据量160万左右,Admin 结构如下:
定位
-
看到加载了17s,通过Chrome Deubug 没发现网页资源 有明显问题,那就从这109个SQL查询入手
-
展开第一个慢SQL,发现有两次count,count需要走全表扫描,数据多时影响查询性能。
通过查阅文档发现一次是受show_full_result_count参数控制(控制是否应在过滤的管理页面(例如)上显示对象的全部数量。如果此选项设置为, 则显示类似的文本。99 results (103 total)False99 results (Show all) )可以在 Admin Class 里关掉。
1 | show_full_result_count = False |
-
少了一个count,速度没啥提升。继续看下面的SQL:
存在好多 DISTINCT 查询,还是会走全表扫描影响性能,StackoverFlow上说是list_filter(#过滤框导致的默认从表中取出该字段的所有字段,以支持过滤补全。可以通过自定义Filter来控制行为),这里选择使用search_fields代替list_filter。 -
现在这个sql 已经从5s多变成了2s多:
发现有很多类似的小查询,虽然每条查询不慢,但是架不住多,StackoverFlow说是因为表上有外键,每条记录都会单独查询外键表,可以通过联合查询来避免。 admin.ModelAdmin支持通过list_select_related参数(转化为数据库层面的left join 以提高查询速度)
1 | list_select_related = ["webhook", "processing_method"] |
- 现在 只剩下4个sql 查询了,整个页面用时1.6s,sql用时500ms:
- Django Admin 默认每页展示100条记录,设成20条,又快了一点。
1 | list_per_page = 20 |
扩展
- 对于大量数据的count,也是可以权衡准确性来优化速度的,详情可以参考HylaruCoder大佬的
MG的编程物语 通过返回假数据,设置缓存,利用DB特性返回大概值等方式。