+----+-------------+---------------+---------------------+----+-----------+----------+-------------+-----------+ | id | customer_id | orderinfo | time | id | firstname | lastname | hometown_id | living_id | +----+-------------+---------------+---------------------+----+-----------+----------+-------------+-----------+ | 1 | 1 | Info of Order | 2014-08-10 17:05:48 | 1 | 张 | 三 | 3 | 1 | +----+-------------+---------------+---------------------+----+-----------+----------+-------------+-----------+ 1 row in set (0.00 sec) +-----------------------+----+--------+-------------+ | _prefetch_related_val | id | name | province_id | +-----------------------+----+--------+-------------+ | 1 | 1 | 武汉市 | 1 | | 1 | 2 | 广州市 | 2 | | 1 | 3 | 十堰市 | 1 | +-----------------------+----+--------+-------------+ 3 rows in set (0.00 sec) +----+--------+ | id | name | +----+--------+ | 1 | 湖北省 | | 2 | 广东省 | +----+--------+ 2 rows in set (0.00 sec)
值得注意的是,可以在调用prefetch_related之前调用select_related,并且Django会按照你想的去做:先select_related,然后利用缓存到的数据prefetch_related。然而一旦prefetch_related已经调用,select_related将不起作用。
小结
因为select_related()总是在单次SQL查询中解决问题,而prefetch_related()会对每个相关表进行SQL查询,因此select_related()的效率通常比后者高。鉴于第一条,尽可能的用select_related()解决问题。只有在select_related()不能解决问题的时候再去想prefetch_related()。你可以在一个QuerySet中同时使用select_related()和prefetch_related(),从而减少SQL查询的次数。只有prefetch_related()之前的select_related()是有效的,之后的将会被无视掉。关于这两个函数,我能想到的东西目前只有这么多。不过基于一些个人原因,写第三篇时间比较短,写的有些仓促。如果什么时候又想起了什么,我会在这篇博文中添加。