如何在Django中正确遍历大量QuerySet?
我需要找出5个符合某种复杂条件的对象,但我不想把这个条件放在WHERE子句里(在Django中就是过滤条件),所以我需要遍历结果,检查每一条记录是否符合条件,直到找到5个对象为止。找到后,我想把这个查询结果丢掉,不想再看到它。
在大多数情况下,我需要的记录会在查询结果的前面,最糟糕的情况是在最后面。这个表的数据量很大,而我只需要5条记录。所以我的问题是:我该如何遍历查询结果,而不让Django缓存这些结果?这必须以一种方式进行,确保SQL引擎和Django都不在任何地方存储或缓存这些结果。
2 个回答
Django没有全局缓存(参见票据#14)。这意味着,只要你不保留任何数据,这些数据就会消失,不再被缓存。到那时,垃圾回收器会在下次清理时释放这些内存。因此,像这样的代码:
my_objects = [obj for obj in MyModel.objects.all() if my_complex_condition(obj)]
在这里,Django唯一的缓存就是在上面的特定实例中,而在这一行之后,任何对缓存的引用都会消失。需要注意的是,如果Django根本没有缓存,内存还是会以同样的方式被填满,垃圾回收器也会以同样的方式逐个收集这些数据。
你为什么要担心缓存呢?让Django或者MySQL去做它们该做的事情吧。
如果你真的想要这样做,可以在你的项目的settings.py文件里关闭Django的缓存,这个操作非常简单。
对于MySQL,你需要执行一些查询来禁用查询缓存。
可以在你的查询中使用SQL_NO_CACHE
选项,像这样:
SELECT SQL_NO_CACHE * FROM TABLE
这样做会阻止MySQL缓存结果,但要注意,其他操作系统和磁盘缓存也可能会影响性能,这些问题比较难解决。
这个方法的一个问题是,它似乎只会阻止你的查询结果被缓存。但是,如果你查询的数据库正在被其他人使用,那么其他客户端可能会缓存你的查询,这样会影响你的结果。我还在继续研究解决这个问题的方法,如果找到了解决方案会更新这篇文章。
或者
你也可以使用RESET QUERY CACHE
。
或者
FLUSH QUERY CACHE
不过有一点需要注意,我建议让MySQL处理WHERE
子句,因为它有查询优化层,如果你正确地为字段建立了索引,这样会非常有效。如果你把所有结果都取出来,然后再自己处理WHERE
子句的功能,可能会因为查询集的大小而导致速度变慢。这是值得考虑的事情。我想适当的基准测试应该能给你一些指引。