我有一个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,发现列表页速度正常了。
两种分页方式:强烈建议用第二种
mysql select count慢的问题
使用位图索引的计数最快,使用B+数索引(普通索引)的次之,性能相差可达1个数量级以上。