优化 Django 管理后台 SQL
我有以下的数据库结构:
class Book(models.Model):
id = models.AutoField(primary_key=True, db_column='id')
name = models.CharField(max_length=255, db_column='name')
author = models.ForeignKey('Author', to_field='id', db_column='author_id')
class Author(models.Model):
id = models.AutoField(primary_key=True, db_column='id')
fio = models.CharField(max_length=255, db_column='fio')
def __unicode__(self):
return self.name
还有这个用于书籍的Admin类:
class BookAdmin(admin.ModelAdmin):
list_display = ('id', 'name',)
fields = ('id', 'name', 'author',)
readonly_fields = ('id',)
raw_id_fields = ('author',)
当书籍记录在500到1000条的时候,一切都运行得很好,但当记录达到100万到200万条时,页面会卡住几分钟才显示内容。性能分析工具告诉我,django在连接书籍和作者时,最后只取了100条记录。
SELECT ••• FROM `books` INNER JOIN `authors` ON ( `books`.`author_id` = `authors`.`id` ) ORDER BY `books`.`id` DESC LIMIT 100
我该如何优化django,让它在从数据库中选择书籍后再连接作者?或者使用类似的方式:
select * from (SELECT * FROM books ORDER BY books.id DESC LIMIT 100) t, authors a where t.author_id = a.id
1 个回答
1
你遇到了一个已知的问题:在MySQL中,慢速的INNER JOIN可以通过Django ORM来修复,但这样做是否合适呢?
有一个项目叫做django-mysql-fix
,这个项目是在2014年PyCon大会的开发活动中开始的,目的是为了解决INNER JOIN
的问题,专门为MySQL提供了一个自定义的数据库后端:
这个项目包含了针对Django ORM的MySQL优化(可以理解为一些小技巧)。
有两种非常简单的方法可以捕捉到INNER JOIN的错误:
当你在Django管理后台模型中指定了外部表的字段到列表展示时;
当你尝试按外部表的字段进行排序时。
据我了解,这个项目在后台会把所有的INNER JOIN
替换成STRAIGHT_JOIN
,引用自MySQL文档:
STRAIGHT_JOIN和JOIN类似,不同的是左边的表总是会在右边的表之前被读取。这可以用于那些(少数)情况下,连接优化器把表的顺序搞错了。
另外可以参考: