使用 select_related 进行 SQL 性能优化

本周处理了一个远古接口的性能调优。

最终结果:

在 python manage.py runserver 环境下,query: 358 –> 252, query_time: 1528ms –> 2427ms

线上环境 300ms 左右。

优化过程

工具

使用 django-debug-toolbar 作为性能分析工具。服务开启 debug 模式。

首先请求一次接口,查看到 debug-toolbar 中的 SQL 耗时很高,同时存在大量 similar query 以及 duplicates。

根据 SQL 性能分析提供的分析数据。可以找到具体到哪一行的 ORM 操作了多少次。

经过观察发现有大量的外键查询。一般情况下由外键查询会产生 N+1 问题。这里可以使用 Queryset 自带的 select_related 来解决外键产生的 N+1 问题。

看一下官网文档的解释。

Returns a QuerySet that will “follow” foreign-key relationships, selecting additional related-object data when it executes its query. This is a performance booster which results in a single more complex query but means later use of foreign-key relationships won’t require database queries.

举个例子吧。

# before
query = OrderStatus.objects.filter(order__in=ord_org_list)
# after
query = OrderStatus.objects.filter(order__in=ord_org_list).select_related('order')
# 使用

这样在之后使用 queryset 调用外键的时候就可以减少一次查询。提高了性能。

当然,select_related 只适合一对多的关系。如果用到的字段是多对多,可以使用 prefetch_related。

本文参考