递归Python函数削弱Django站点性能
我有一个Django站点,它有一个递归Python函数削弱Django站点性能,python,mysql,django,recursion,Python,Mysql,Django,Recursion,我有一个Django站点,它有一个类别模型,每个实例可以容纳零到n子类别 class Category(models.Model): ... parent = models.ForeignKey('self', on_delete=models.CASCADE, blank=True, null=True, related_name='subcategories') 这些类别存储在MySQL数据库中。我需要建立一个所有类别的嵌套HTML列表 class Category(mod
类别
模型,每个实例可以容纳零到n
子类别
class Category(models.Model):
...
parent = models.ForeignKey('self', on_delete=models.CASCADE, blank=True, null=True, related_name='subcategories')
这些类别存储在MySQL数据库中。我需要建立一个所有类别的嵌套HTML列表
class Category(models.Model):
...
parent = models.ForeignKey('self', on_delete=models.CASCADE, blank=True, null=True, related_name='subcategories')
作为一种简单而肮脏的方法,我最初是通过递归函数实现的
这在一开始运行得很好,但现在有800多个类别,这导致请求急剧放缓。运行开发服务器时,每次运行至少需要60秒
以下是稍微简化的函数:
def get_category_map(categories, root=False):
category_map = ''
if categories:
if root:
category_map += '<ul id="root">'
else:
category_map += '<ul>'
for category in categories:
category_map += '<li>'
subcategories = category.subcategories.all()
if subcategories.count() == 0:
category_map += '<a class="category-link" href="' + reverse('my_app:category_page', args=(category.pk, category.slug)) + '">' + category.title + '</a>'
else:
category_map += '<span class="category-drop-down">' + category.title + '</span>'
# Recursive call here cripples performance.
category_map += get_category_map(subcategories)
category_map += '</li>'
category_map += '</ul>'
return category_map
它产生了我想要的结果,但以牺牲效率和时间为代价
我理解Python和递归的基本性能问题,但这是可以补救的,还是需要一种根本不同的方法?这是一个有根据的猜测:您遇到的性能问题很可能是由于访问数据库的查询数量太多,不向递归函数生成模板
subcategories=category.subcategories.all()
由于您没有使用任何预取,上面的一行将触发对您递归访问的每个类别的查询,因此,对于800个顶级类别,您将获得800个。此外,还将对每一项执行计数查询:
if subcategories.count()==0:
通过使用Django内置的模型关系急切加载,您可以稍微改进一下。
考虑一下,在关系数据库中高效地存储和查询树结构需要一些巧妙的算法。
因此,我建议使用(或至少从中汲取灵感)这个Django软件包:
Wagtail是一种流行的Django CMS,支持嵌套类别
class Category(models.Model):
...
parent = models.ForeignKey('self', on_delete=models.CASCADE, blank=True, null=True, related_name='subcategories')
此包实现了三种不同的策略来存储和查询树结构:
- 邻接表
- 物化路径
- 嵌套集
另一个流行的选择是:
我建议您不要使用“自制”解决方案,因为您已经有相当多的类别需要处理,因此性能在您的案例中已经很重要)。自己从头开始实现这些算法一点也不简单。这是一个有根据的猜测:您遇到的性能问题很可能是由于命中数据库的查询数量,而不是生成模板的递归函数
subcategories=category.subcategories.all()
由于您没有使用任何预取,上面的一行将触发对您递归访问的每个类别的查询,因此,对于800个顶级类别,您将获得800个。此外,还将对每一项执行计数查询:
if subcategories.count()==0:
通过使用Django内置的模型关系急切加载,您可以稍微改进一下。
考虑一下,在关系数据库中高效地存储和查询树结构需要一些巧妙的算法。
因此,我建议使用(或至少从中汲取灵感)这个Django软件包:
Wagtail是一种流行的Django CMS,支持嵌套类别
class Category(models.Model):
...
parent = models.ForeignKey('self', on_delete=models.CASCADE, blank=True, null=True, related_name='subcategories')
此包实现了三种不同的策略来存储和查询树结构:
- 邻接表
- 物化路径
- 嵌套集
另一个流行的选择是:
我建议您不要使用“自制”解决方案,因为您已经有相当多的类别需要处理,因此性能在您的案例中已经很重要)。从头开始自己实现这些算法一点也不简单。三点意见:1。不要从python编写HTML。这就是django拥有模板的原因。2.定义最大深度。3.使用ORM返回第一个。。。Python递归并不特别慢(与Python的其余部分相比)。可能的罪魁祸首是多个数据库查询以及伴随而来的Python对象实例化。会有帮助的。但一般来说,在一个查询中获取所有类别(特别是使用
值\u list
,但这可能是一个过早的微优化),然后在Python中将它们缝合到一个层次结构中,会大大加快查询速度。@Amadan是的,似乎是大量的数据库查询在快速连续进行。三条评论:1。不要从python编写HTML。这就是django拥有模板的原因。2.定义最大深度。3.使用ORM返回第一个。。。Python递归并不特别慢(与Python的其余部分相比)。可能的罪魁祸首是多个数据库查询以及伴随而来的Python对象实例化。会有帮助的。但一般来说,在一个查询中获取所有类别(特别是使用值\u list
,但这可能是一个过早的微优化),然后将它们缝合到Python的层次结构中,会大大加快查询速度。@Amadan是的,似乎是大量的数据库查询在快速连续进行。另一个流行的替代方案是django mptt。我集成了django mptt
,到目前为止,性能似乎很好,因此,当我在live数据库上运行迁移时,希望这将改善情况。另一个流行的替代方案是django mptt。我集成了django mptt
,到目前为止性能似乎很好,所以希望这将改善我在live数据库上运行迁移时的情况。