【发布时间】:2012-01-18 17:02:54
【问题描述】:
我们有一个应用程序具有高度相关的数据,即在很多情况下,两个对象可能通过关系引用同一个对象。据我所知,如果您尝试通过不同的、以前未评估的关系获取已获取对象的引用,Django 不会尝试返回对它的引用。
例如:
class Customer( Model ):
firstName = CharField( max_length = 64 )
lastName = CharField( max_length = 64 )
class Order( Model ):
customer = ForeignKey( Customer, related_name = "orders" )
然后假设我们有一个客户在数据库中有两个订单:
order1, order2 = Order.objects.all()
print order1.customer # (1) One DB fetch here
print order2.customer # (2) Another DB fetch here
print order1.customer == order2.customer # (3) True, because PKs match
print id( order1.customer ) == id( order2.customer ) # (4) False, not the same object
当您拥有高度相关的数据时,访问对象关系的程度会导致数据库重复查询相同数据的程度增加并成为问题。
我们还为 iOS 编程,CoreData 的优点之一是它维护 context,因此在给定的上下文中,给定模型只有一个实例。在上面给出的示例中,CoreData 不会在 (2) 处进行第二次提取,因为它会使用内存中已经存在的客户来解析关系。
即使第 (2) 行被替换为旨在强制另一个数据库提取的虚假示例(如 print Order.objects.exclude( pk = order1.pk ).get( customer = order1.customer )),CoreData 也会意识到第二次提取的结果解析为内存中的模型并返回现有模型一个新的(即 (4) 将在 CoreData 中打印 True,因为它们实际上是同一个对象)。
为了对冲 Django 的这种行为,我们编写了所有这些可怕的东西,试图通过它们的 (type, pk) 将模型缓存在内存中,然后检查与 _id 后缀的关系,以尝试将它们从缓存中拉出盲目地用另一个 fetch 击中数据库。这会降低数据库吞吐量,但如果通过属性的正常关系查找意外发生在我们无法控制的某些 contrib 框架或中间件中,则感觉非常脆弱并且可能会导致问题。
Django 是否有任何最佳实践或框架来帮助避免这个问题?有没有人尝试在 Django 的 ORM 中安装某种线程本地上下文以避免重复查找并将多个内存中实例映射到同一个数据库模型?
我知道像 JohnnyCache 这样的查询缓存已经存在(并有助于降低数据库吞吐量),但是即使采取了这些措施,仍然存在多个实例映射到同一底层模型的问题。
【问题讨论】: