0

学年レベルに基づいてカリキュラムを提供する教育サイトを持っています。

  1. GradeLevel テーブルには、可能なすべてのグレード レベルが格納されます。次に、LessonCategories と LessonCurriculum テーブルがあります。

  2. GradeLevel テーブルには、カリキュラム テーブルとカテゴリ テーブルとの逆の関係が確立されています。

  3. GradeLevel テーブルの各学年 (8 つの学年) をループ処理し、途中でそれぞれのカリキュラムとカテゴリを取得します。

  4. 完了したら、収集したすべてのカリキュラムとカテゴリをリストに詰め込み、それをテンプレートに渡します。

ここでの問題は、Django が各クエリを少なくとも 2 回評価していることです。1 回目は最初のリクエストで、2 回目はリストに追加したときです。(私は itertools を使用して結果を連鎖させています。Itertools がクエリを再度実行させています。) これにより、サーバーの速度が低下してクロールが発生するという悪影響が生じています。

私の質問は、誰かが私のモデルとクエリを見て、この主要なパフォーマンスのボトルネックを回避および/または軽減するためのクエリのより良い方法について提案できるかどうかです.

学年モデル:

class GradeLevel(models.Model):
    title = models.CharField('Grade',max_length=10, null=True, blank=True, db_index=True)
    fullname = models.CharField('Description',max_length=100, null=True, blank=True, db_index=True)

LessonCategory モデル:

class LessonCategory(models.Model):
    title = models.CharField(max_length=255, null=True, blank=True, db_index=True)
    ...
    gradelevel = models.ManyToManyField(GradeLevel, related_name='grade_cats', null=True, blank=True)

レッスンカリキュラム:

class LessonCurriculum(models.Model):         
    title = models.CharField(max_length=255, null=True, blank=True, db_index=True)
    ...
    gradelevel = models.ManyToManyField(GradeLevel, related_name='grade_curriculum', null=True, blank=True)

私の見解:

from itertools import chain
from operator import attrgetter

def my_view(request):
    grade_pk =  GradeLevel.objects.prefetch_related().get(title='pre-k')
    grade_pk_categories = grade_pk.grade_cats.filter(active=True,featured=True)
    grade_pk_galleries = grade_pk.grade_curriculum.filter(active=True,featured=True)

    grade_k =  GradeLevel.objects.prefetch_related().get(title='k')
    grade_k_categories = grade_k.grade_cats.filter(active=True,featured=True)
    grade_k_galleries = grade_k.grade_curriculum.filter(active=True,featured=True)

    grade_1 =  GradeLevel.objects.prefetch_related().get(title='1')
    grade_1_categories = grade_1.grade_cats.filter(active=True,featured=True)
    grade_1_galleries = grade_1.grade_curriculum.filter(active=True,featured=True)

    grade_2 =  GradeLevel.objects.prefetch_related().get(title='2')
    grade_2_categories = grade_2.grade_cats.filter(active=True,featured=True)
    grade_2_galleries = grade_2.grade_curriculum.filter(active=True,featured=True)

    grade_3 =  GradeLevel.objects.prefetch_related().get(title='3')
    grade_3_categories = grade_3.grade_cats.filter(active=True,featured=True)
    grade_3_galleries = grade_3.grade_curriculum.filter(active=True,featured=True)

    grade_4 =  GradeLevel.objects.prefetch_related().get(title='4')
    grade_4_categories = grade_4.grade_cats.filter(active=True,featured=True)
    grade_4_galleries = grade_4.grade_curriculum.filter(active=True,featured=True)

    grade_5 =  GradeLevel.objects.prefetch_related().get(title='5')
    grade_5_categories = grade_5.grade_cats.filter(active=True,featured=True)
    grade_5_galleries = grade_5.grade_curriculum.filter(active=True,featured=True)

    grade_6 =  GradeLevel.objects.prefetch_related().get(title='6')
    grade_6_categories = grade_6.grade_cats.filter(active=True,featured=True)
    grade_6_galleries = grade_6.grade_curriculum.filter(active=True,featured=True)

    grade_7 =  GradeLevel.objects.prefetch_related().get(title='7')
    grade_7_categories = grade_7.grade_cats.filter(active=True,featured=True)
    grade_7_galleries = grade_7.grade_curriculum.filter(active=True,featured=True)

    grade_8 =  GradeLevel.objects.prefetch_related().get(title='8')
    grade_8_categories = grade_8.grade_curriculum.filter(active=True,featured=True)
    grade_8_galleries = grade_8.grade_curriculum.filter(active=True,featured=True)

    gallery_list = list(set(sorted(chain(grade_pk_categories,grade_pk_galleries,grade_k_categories,grade_k_galleries,grade_1_categories,grade_1_galleries,grade_2_categories,grade_2_galleries,grade_3_categories,grade_3_galleries,grade_4_categories,grade_4_galleries,grade_5_categories,grade_5_galleries,grade_6_categories,grade_6_galleries,grade_7_categories,grade_7_galleries,grade_8_categories,grade_8_galleries), key=attrgetter('display_order'))))
4

2 に答える 2

4

私は少し先に進み、@NathanVillaescusaの答えをもう少し最適化します

grade_titles = ['pre-k', 'k', '1', '2', '3', '4', '5', '6', '7', '8']

# Turn list into list of Q items
queries = [models.Q(title=grade_title) for grade_title in grade_titles]

# Take one item of the list
query = queries.pop()

# OR the Q objects with the ones remaining in the list
for item in queries:
    query |= item

grades = GradeLevel.objects.prefetch_related().filter(query)
# grades should have everything you need and operation is more CPU
# and less DB bound now
于 2012-10-29T19:07:21.333 に答える
1

使用したいのはchain.from_iterableです。これにより、クエリが複数回実行されるのを防ぐことができます。

gallery_list = tuple(chain.from_iterable(grade_pk_categories,grade_pk_galleries,grade_k_categories,grade_k_galleries,grade_1_categories,grade_1_galleries,grade_2_categories,grade_2_galleries,grade_3_categories,grade_3_galleries,grade_4_categories,grade_4_galleries,grade_5_categories,grade_5_galleries,grade_6_categories,grade_6_galleries,grade_7_categories,grade_7_galleries,grade_8_categories,grade_8_galleries))

また、アイテムを実行するset前ではなく、実行した後にソートする必要があります。

gallery_list = list(sorted(frozenset(gallery_list), key=attrgetter('display_order')))

このすべてのデータをどのように取得するのかを再考します。すべてのデータに対して1つまたは2つのクエリに置き換えることができる場合は、グレードレベルごとに2つのクエリを実行しています。

少なくとも、を使用しfor loopて、持っているコードの量を減らすことができます。

grade_titles = ['pre-k', 'k', '1', '2', '3', '4', '5', '6', '7', '8']
gallery_list = []
for grade_title in grade_titles:
    grade = GradeLevel.objects.prefetch_related().get(title=grade_title)
    grade_categories = grade_pk.grade_cats.filter(active=True,featured=True)
    grade_galleries = grade_pk.grade_curriculum.filter(active=True,featured=True)
    gallery_list.extend(grade_categories)
    gallery_list.extend(grade_galleries)
gallery_list = list(sorted(frozenset(gallery_list), key=attrgetter('display_order')))
于 2012-10-29T18:38:16.883 に答える