Django Loop .save()时间问题

时间:2017-01-25 14:35:02

标签: python django

我有以下代码,一切都按预期进行,每个循环的运行时间可能会有所不同。我已将其缩小到.save()函数,因为查询平均每次迭代运行时间为.008秒。 .save()需要从.008秒到1.13秒。

执行113次迭代时,1.13秒开始累加。

有什么建议可以加快速度吗? 表格大小最多为45,000行数据。

for mega, company, family, bed, sretail in beds:
    matt = FloorTracker.objects.get(showroom_number=strNum,mattress=bed)
    matt.brand = company
    matt.family = family
    matt.company = mega
    matt.suggested_retail = sretail
    matt.on_floor = 0 if request.POST.get('cb_' + bed) == None else 1
    matt.in_comparison = 0 if request.POST.get('cb_' + bed + '_comparison') == None else 1
    matt.in_vzone = 0 if request.POST.get('cb_' + bed + '_vzone') == None else 1
    matt.size = "" if request.POST.get('sz_' + bed) == 'blank' or not request.POST.get('sz_' + bed) else request.POST.get('sz_' + bed)
    matt.underbed = "" if request.POST.get('ub_' + bed) == 'blank' or not request.POST.get('ub_' + bed) else request.POST.get('ub_' + bed)
    matt.lastupdate = str(timezone.now())
    t0 = time.time()
    matt.save()
    t1 = time.time()
    total = t1-t0
    print('query 1:', matt.mattress, total)

4 个答案:

答案 0 :(得分:3)

更新而不是获取和保存

您正在获取一个对象,然后更新它的字段并将其保存回来。这是db上的两次点击。你可以在一次操作中完成。使用update

FloorTracker.objects.filter(showroom_number=strNum,mattress=bed).update(
     lastupdate = str(timezone.now(),suggested_retail = sretail ....)

这比检索和保存更快,而且更安全!这是一个原子操作,使用检索,编辑可以避免在进行编辑时另一个线程更新数据库的风险,并且数据将被破坏。

使用transcation

正如在其他答案中所建议的那样,将整个事物包装在事务中并在最后提交。这会快得多

用户数据库默认

不是在代码中为None和未找到的实例分配值,而是使用默认值。这将节省一些操作并导致一些速度。

避免重复获取同一个对象

你有多个这样的电话:

request.POST.get('ub_' + bed) 

您可以执行一次并重复使用值

ub_bed = request.POST.get('ub_' + bed) 

此处保存的规模很小。

将request.POST视为字典

如果您确信所有字段都已填充(如果您在此处使用django表单而不是依赖原始发布数据,则可能真的如此)您可以访问request.POST项目

request.POST [' CB _' +床]

但性能改善将是微不足道的

索引

最后但并非最不重要的是,在showroom_number, mattress上创建一个索引,这可能会带来很大的推动。

答案 1 :(得分:1)

Django的默认设置是在自动提交模式下运行,所以如果你还没有这样做(我假设你会提到它),precedence肯定会提高性能。

答案 2 :(得分:0)

最简单的加速是避免在每次循环迭代时进行一次查询。

bed_list = [b[3] for b in beds]
track_qs = FloorTracker.objects.filter(showroom_number=strNum, mattress__in=bed_list)
trackers = {t.mattress: t for t in track_qs}

for mega, company, family, bed, sretail in beds:
    matt = trackers[bed]
    ...

另一种方法是累积所需的更新并立即执行所有更新,而不是进行大量单项更新。

答案 3 :(得分:0)

根据e4c5的一些建议,我已经有了一些改进,但每次迭代仍然有不同的时间。大多数迭代现在需要.005秒,但其中大约四分之一仍需要1.3秒(相当可靠的1.31或1.32秒)。

时机问题是因为我从服务器主机获得超时,这对我的用户来说是失败的。我真的需要它在20秒内可靠。我们的出现时间从30秒到90秒不等。

以下是我对代码所做的更新。我不确定我是否完全理解transaction.atomic即使在阅读之后我也认为这是正确的:

def saveData(request,strNum, brand):
    #List of beds to loop through
    import time
    from django.db import transaction
    beds = bedSelect(brand)
    t3 = time.time()
    store = storeList.objects.get(storenumber=strNum)
    with transaction.atomic():
        for mega, company, family, bed, sretail in beds:
            try:
                t0 = time.time()
                FloorTracker.objects.filter(showroom_number=strNum,mattress=bed).update(
                    user = store.user,
                    showroom_number = store,
                    brand = company,
                    family = family,
                    mattress = bed,
                    company = mega,
                    suggested_retail = sretail,
                    on_floor = 0 if request.POST.get('cb_' + bed) == None else 1,
                    in_comparison = 0 if request.POST.get('cb_' + bed + '_comparison') == None else 1,
                    in_vzone = 0 if request.POST.get('cb_' + bed + '_vzone') == None else 1,
                    size = "" if request.POST.get('sz_' + bed) == 'blank' or not request.POST.get('sz_' + bed) else request.POST.get('sz_' + bed),
                    underbed = "" if request.POST.get('ub_' + bed) == 'blank' or not request.POST.get('ub_' + bed) else request.POST.get('ub_' + bed),
                    lastupdate = str(timezone.now()))
                t1 = time.time()
                total = t1-t0
                print(total)