记一次django admin列表页慢问题的解决过程

背景

我有一个mysql表,8490579条记录,发现加载列表页的时候很慢。

解决过程

列表页的url为 http://xlawyer.aegis-info.com/admin/laws/lawsmodel/?code_id=d54e794d011bbf9837ea3422268202c6,一开始我以为是通过code_id查询表导致的慢,我就对code_id这个字段建立索引,但是建完索引后,发现列表页还是很慢。
没有什么办法,我就开始看django admin的源码
先是找路由,发现了 django.contrib.admin.site.get_urls 这个方法里面有一段代码

图片: https://images-cdn.shimo.im/AqNA3pNCWcUwmxJh/django_admin.png.png
这段代码意思是django 启动后会从所有register的ModelAdmin获取urls并注册到路由,所以就去找ModelAdmin的urls。
找到父类ModelAdmin的 get_urls方法:
图片: https://images-cdn.shimo.im/r2KXwuY45NsN1DPG/django_admin1.png
其中有一行代码:

url(r'^$', wrap(self.changelist_view), name='%s_%s_changelist' % info),

这下就知道了列表页url对应的处理view了,是 ModelAdmin类的 changelist_view方法。

在changelist_view中设置断点调试,发现

cl = ChangeList(
    request, self.model, list_display,
    list_display_links, list_filter, self.date_hierarchy,
    search_fields, list_select_related, self.list_per_page,
    self.list_max_show_all, self.list_editable, self,
)

在这边卡住了,找到ChangeList类的实例化方法,设置断点继续调试

最终找到了 django.contrib.admin.views.main.get_results 这个方法,发现了如下这段代码

# Get the total number of objects, with no admin filters applied.
if self.model_admin.show_full_result_count:
    full_result_count = self.root_queryset.count()
else:
    full_result_count = None
can_show_all = result_count <= self.list_max_show_all
multi_page = result_count > self.list_per_page

总结

通过之前对mysql的测试,发现 selelct count(*) from lawsearch_laws; 这条语句执行很耗时。原因就是在这里!通过在 LawsAdmin中设置实例变量 show_full_result_count=False避免加载列表页的时候计算total,发现列表页速度正常了。

延伸

两种分页方式:强烈建议用第二种

  • 算total,然后根据page 和page_size 分页
  • 根据page, 和page_size获取下一批数据,并比较获取的数据条数和page_size

mysql select count慢的问题
使用位图索引的计数最快,使用B+数索引(普通索引)的次之,性能相差可达1个数量级以上。

你可能感兴趣的:(记一次django admin列表页慢问题的解决过程)