【问题标题】:Runtime issues using django and sqlite - too much queries使用 django 和 sqlite 的运行时问题 - 查询太多
【发布时间】:2017-09-23 19:25:48
【问题描述】:

我在使用以下代码时遇到了运行时问题:

# filter start and end date
matches = database.objects.filter(start__gte= Start, end__lte= End)    
# iterate through matches
for Item in matches:
        # filter database again
        test = database.objects.filter(cm1=Item.cm1, cm2=Item.cm2, cm3=Item.cm3)
        # compare first item of filter with iterated Item
        if test[0] == Item:
            TrueRun = True
        else:
            TrueRun = False

我有一个大约 80k 行的数据库。在第一步中,我过滤了我想要查看的行,通常应该在 8k 左右。在第二步中,我遍历所有这些项目并检查它们是唯一的还是具有某些特定属性的第一个(cm1cm2cm3)。

现在的问题是,我执行 8k 数据库查询,总共需要大约 15 分钟。有什么方法可以加速这一点,例如在循环之前使用一个包含cm1 及其匹配行的所有可能性的字典?

感谢您的帮助!

__________________________

评论后编辑

我的模型的默认顺序与此处的使用方式不同。在程序中,我有大约 25 个模型并检查其中大约 12 个是否相等。

循环的其余部分应该没什么意思,因为之前还有另一种检查TrueRun 的方法,大约需要2 分钟。唯一改变的是里面#-----# 见这里:

equalnessList = ['cm1','cm2', 'cm3']
for idx, Item in enumerate(matches):
    #-----------------#
    TrueRun = True
    listTrue = []
    for TrueIdx,TrueItem in enumerate(listTrue):
        EqualCount = 0
        for equCrit in equalnessList:
            if getattr(Item,equCrit)!=getattr(matches[TrueItem],equCrit):
                EqualCount += 1
        if EqualCount == len(equalnessList):
            TrueRun = False
            break
    #------------------#
    # Some stuff in here, that can't be changed
    if TrueRun:
        resDict[getattr(Item,'id')] = [True]
        listTrue.append(idx)
    else:
        resDict[getattr(Item,'id')] = [False]

这里的问题是,它工作不正常,并且没有使用过滤日期之外的数据库条目进行检查。

【问题讨论】:

  • 你的模型的默认顺序是什么,你能展示你循环的其余部分吗?你是如何使用TrueRun的?
  • 更新了您的评论问题。

标签: python mysql django python-2.7 sqlite


【解决方案1】:

您可能需要对其进行调整以满足您的要求。特别是,您需要在每个 cm1, cm2, cm3 组内保持原始排序顺序。

matches = database.objects.filter(start__gte=Start, end__lte=End)
all_objects = database.objects.all().order_by('cm1', 'cm2', 'cm3', 'sequence')
# replace 'sequence' by field(s) that model is sorted on by default
results_dict = {}
cm1 = None
cm2 = None
cm3 = None
first = False
for obj in all_objects:
    if (obj.cm1 != cm1) or (obj.cm2 != cm2) or (obj.cm3 != cm3):
        cm1 = obj.cm1
        cm2 = obj.cm2
        cm3 = obj.cm3
        first = True
    if obj.start >= Start and obj.end <= End:
        results_dict[obj.id] = first
    first = False

【讨论】:

    【解决方案2】:
    # filter start and end date
    matches = database.objects.filter(start__gte=Start, end__lte=End)
    
    # iterate through matches
    for item in matches:
        # filter database again and get the id of the first element matched
        first_item = database.objects.filter(cm1=item.cm1, cm2=item.cm2, cm3=item.cm3).values('id').first()
        # compare first item id with the id of filtered "item"
        if first_item['id'] == item.id:
            TrueRun = True
        else:
            TrueRun = False
    

    【讨论】:

    • 谢谢,但有没有办法不改变“匹配”?我需要它以原始方式用于循环中的其他一些东西..
    • 不知道,更新了我的答案!但是,根据您的模型结构和您的逻辑(视图内部)是什么,可能会有更好的解决方案......
    • 模型结构如何产生影响?
    • 因为您可能(或可能没有)声明了模型之间的不必要关系。此外,根据您的视图逻辑,相同的目标可能(也可能不会)通过较少的查询来实现(避免for 循环)。
    • 型号如:cm2= models.CharField(db_column='cm2', max_length=30)
    猜你喜欢
    • 1970-01-01
    • 2010-10-11
    • 2017-09-24
    • 1970-01-01
    • 2011-04-19
    • 2017-09-21
    • 1970-01-01
    相关资源
    最近更新 更多