上面说的是
Record.objects.order_by('?')[:n]
有性能问题,建议您这样做:(here)
^{pr2}$既然如此,为什么不直接这样做:
result = random.sample(Record.objects.all(),n)
我不知道这些代码什么时候在后台运行django。请告诉我最后一行代码是否更有效?为什么?在
=============编辑2013-5-12 23:21 UCT+8=======================
我整个下午都在做这个测试。
我的电脑:CPU Intel i5-3210M RAM 8G
系统:Win8.1 pro x64 Wampserver2.4-x64(带apache2.4.4 mysql5.6.12 php5.4.12)Python2.7.5 Django1.4.6
我所做的是:
CharField
内容构建一个简单模型,然后Syncdb
。在settings.py
,使{这是views.py
:
def test1(request):
start = datetime.datetime.now()
result = Record.objects.order_by('?')[:20]
l = list(result) # Queryset是惰性的,强制将Queryset转为list
end = datetime.datetime.now()
return HttpResponse("time: <br/> %s" % (end-start).microseconds/1000))
def test2(request):
start = datetime.datetime.now()
sample = random.sample(xrange(Record.objects.count()),20)
result = [Record.objects.all()[i] for i in sample]
l = list(result)
end = datetime.datetime.now()
return HttpResponse("time: <br/> %s" % (end-start)
def test3(request):
start = datetime.datetime.now()
result = random.sample(Record.objects.all(),20)
l = list(result)
end = datetime.datetime.now()
return HttpResponse("time: <br/> %s" % (end-start)
正如@Yeo所说,result = random.sample(Record.objects.all(),n)
是垃圾。我不谈这个。
但有趣的是,Record.objects.order_by('?')[:n]
总是比其他的好,尤其是小于1m行的表。数据如下:
以及图表:
怎么了?
在上一个测试中,tatget table,result = random.sample(Record.objects.all(),n)
中的5195536行实际上执行了以下操作:
(22.275) SELECT `randomrecords_record`.`id`, `randomrecords_record`.`content`
FROM `randomrecords_record` ORDER BY RAND() LIMIT 20; args=()
每个人都是对的。用了22秒。以及
^{pr2}$实际上是这样做的:
(1.393) SELECT COUNT(*) FROM `randomrecords_record`; args=()
(3.201) SELECT `randomrecords_record`.`id`, `randomrecords_record`.`content`
FROM `randomrecords_record` LIMIT 1 OFFSET 4997880; args=()
...20 lines
如你所见,排一排,花费3秒。我发现索引越大,所需的时间就越长。
但是。。。为什么?在
我的想法是:
如果有什么方法可以加快大索引查询的速度
应该是最好的。除了(!)这张桌子比1米行还小。在
Record.objects.count()
被转换成非常简单的SQL查询。在
^{pr2}$Record.objects.all()[0]
也被转换成一个非常简单的SQL查询。在Record.objects.all()
通常将结果切分以提高性能list(Record.objects.all())
将查询所有数据并将其放入列表数据结构中。在因此,每当您将查询集转换为列表时,就会发生代价高昂的情况
在您的示例中,
random.sample()
将转换为一个列表。(如果我没有错的话)。在因此,当您执行
result = random.sample(Record.objects.all(),n)
操作时,它将执行完整的查询集并转换为一个列表,然后随机选择该列表。在想象一下,如果你有数百万的记录。您要查询并将其存储到一个包含数百万元素的列表中吗?或者您更愿意一个一个地查询
.order_by(?)
的问题在于,它实际上是ORDER BY RAND()
(或等效的,取决于DB),这基本上必须为每一行创建一个随机数并进行排序。这是一项繁重的工作,需要很多时间。在另一方面,做
Record.objects.all()
会迫使你的应用程序下载所有对象,然后从中进行选择。它在数据库方面没有那么重(它将比排序更快),但它在网络和内存上很重。因此,它也会扼杀你的表演。在所以这就是交易。在
现在情况好多了:
因为它避免了上面提到的所有问题(注意,},这取决于DB)。在
Record.objects.all()[i]
被转换成{但是,由于
.count
可能很慢(与通常一样:依赖于DB),所以它可能仍然是低效的。在相关问题 更多 >
编程相关推荐