ジャンゴRestfarmworkクエリインターフェイスの最適化

ループの中1.避けデータベースクエリ

関連するコード例:

# 优化前写法:
students = get_training_team_student_info(data.get('resource_id'))

for student in students:
    student_name = student.get('user_name')
    # 获取参训人员分数
    student_score_obj = get_training_team_score_first(
            training_team=data.get('resource_id'), 
            user=student.get('user_id')
            )
    if not student_score_obj:
        student_score = 0
    else:
        student_score = student_score_obj

# 优化后写法:
students = get_training_team_student_info(data.get('resource_id'))
# 查出所有学员成绩数据
student_score_lists = get_training_team_score(training_team=data['resource_id'])
student_score_dict = {}
for student_score in student_score_lists:
    student_score_dict[student_score.user_id] = student_score.final_score

for student in students:
    student_name = student.get('user_name')
    # 获取参训人员分数
    student_score_obj = student_score_dict.get(student.get('user_id'))

    if not student_score_obj:
        student_score = 0
    else:
        student_score = student_score_obj

説明:最初の実際の状況を見つけることは、すべてのデータマッピング関係のループ動作のための値からなります

式のフィールド導出のリストを生成するリストを使用してクエリ結果フィールド法を得るvalues_list 2.、

関連するコード例:

# 优化前相关代码:
# 获取角色下已下发的任务hash列表
send_missions = model_api.get_training_team_mission(
    training_team=training_team_hash,
    training_role=training_role.resource_id
).values_list('mission_resource_id', flat=True)

"""优化前SQL执行
此sql对应上面代码的 send_missions = model_api.get_training_team_mission(training_team=training_team_hash,training_role=training_role.resource_id)
SELECT `ce_training_team_trainingteammission`.`id`, `ce_training_team_trainingteammission`.`resource_id`, `ce_training_team_trainingteammission`.`training_team`, `ce_training_team_trainingteammission`.`training_role`, `ce_training_team_trainingteammission`.`mission_resource_id`, `ce_training_team_trainingteammission`.`user_id`, `ce_training_team_trainingteammission`.`mission_status`, `ce_training_team_trainingteammission`.`user_answer`, `ce_training_team_trainingteammission`.`release_time`, `ce_training_team_trainingteammission`.`reporting_time`, `ce_training_team_trainingteammission`.`start_mission_time`, `ce_training_team_trainingteammission`.`status` FROM `ce_training_team_trainingteammission` WHERE (NOT (`ce_training_team_trainingteammission`.`status` = 0) AND `ce_training_team_trainingteammission`.`training_role` = 'ce66d38a3b0784ddd9074cecbc9bc288' AND `ce_training_team_trainingteammission`.`training_team` = 'ceb99b9d1677016bd09b38295422ee89'); args=(0, 'ce66d38a3b0784ddd9074cecbc9bc288', 'ceb99b9d1677016bd09b38295422ee89')

此sql对应上面代码的.values_list('mission_resource_id', flat=True)
SELECT `ce_training_team_trainingteammission`.`mission_resource_id` FROM `ce_training_team_trainingteammission` WHERE (NOT (`ce_training_team_trainingteammission`.`status` = 0) AND `ce_training_team_trainingteammission`.`training_role` = 'ce66d38a3b0784ddd9074cecbc9bc288' AND `ce_training_team_trainingteammission`.`training_team` = 'ceb99b9d1677016bd09b38295422ee89')  LIMIT 21; args=(0, 'ce66d38a3b0784ddd9074cecbc9bc288', 'ceb99b9d1677016bd09b38295422ee89')

执行get_training_team_mission()函数时会进行一次数据库查询,执行.values_list时会再一次进行数据库查询
"""
# 优化后相关代码:
send_missions = model_api.get_training_team_mission(
    training_team=training_team_hash,
    training_role=training_role.resource_id
)
mission_resource_id_list = [mission.mission_resource_id for mission in send_missions]
"""优化前SQL执行
SELECT `ce_training_team_trainingteammission`.`id`, `ce_training_team_trainingteammission`.`resource_id`, `ce_training_team_trainingteammission`.`training_team`, `ce_training_team_trainingteammission`.`training_role`, `ce_training_team_trainingteammission`.`mission_resource_id`, `ce_training_team_trainingteammission`.`user_id`, `ce_training_team_trainingteammission`.`mission_status`, `ce_training_team_trainingteammission`.`user_answer`, `ce_training_team_trainingteammission`.`release_time`, `ce_training_team_trainingteammission`.`reporting_time`, `ce_training_team_trainingteammission`.`start_mission_time`, `ce_training_team_trainingteammission`.`status` FROM `ce_training_team_trainingteammission` WHERE (NOT (`ce_training_team_trainingteammission`.`status` = 0) AND `ce_training_team_trainingteammission`.`training_role` = 'ce66d38a3b0784ddd9074cecbc9bc288' AND `ce_training_team_trainingteammission`.`training_team` = 'ceb99b9d1677016bd09b38295422ee89'); args=(0, 'ce66d38a3b0784ddd9074cecbc9bc288', 'ceb99b9d1677016bd09b38295422ee89')
 只会在执行get_training_team_mission()函数时时进行一次数据库查询
"""

ページデータ取得インタフェースリスト3.、唯一の必要データは不要なデータのクエリを削減することをページのリストを返します。

関連するコード例:

# 优化前返回字段:
fields = ("resource_id", "name", "description", "category", "pre_skill", "train_skill", "start_time", "end_time",
            "template", "scene", "difficult", "scene_config_data", "training_role_data", "duration_time",
            "scene_config", "scene_start_time", "scene_end_time", "training_status", "scene_data", "roles_data")

# 优化后针对列表页接口返回指定字段
def get_serializer(self, *args, **kwargs):
    """
    获取序列化器

    :param args: 位置参数
    :param kwargs: 不定长字典参数
    :return: 序列化器
    """
    if self.action == 'list':
        kwargs['fields'] = (
            "resource_id", "name", "description", "category", "pre_skill", "train_skill", "start_time", "end_time",
            "template", "difficult", "scene_config", "training_role_data", "duration_time",
            "scene_start_time", "scene_end_time", "training_status"
        )
    return super().get_serializer(*args, **kwargs)

prefetch_relatedプリロードを使用することで、多くの関連クエリ4.、

関連するコード例:

# 优化前相关代码:
role_list = get_training_role(
        training_team=data['resource_id']
    ).exclude(users__id=user_id)

for role in role_list:
    role_name = role.name
    users = role.users.all()
    user_names = [user.username for user in users]
    role_info_list.append({
        'role_name': role_name,
        'users': user_names
    })
"""优化前执行sql
此sql对应上面代码的 role_list = get_training_role(training_team=data['resource_id'])
SELECT `ce_training_team_trainingrole`.`id`, `ce_training_team_trainingrole`.`resource_id`, `ce_training_team_trainingrole`.`training_team`, `ce_training_team_trainingrole`.`name`, `ce_training_team_trainingrole`.`description`, `ce_training_team_trainingrole`.`role_group`, `ce_training_team_trainingrole`.`missions_scheme`, `ce_training_team_trainingrole`.`nodes` FROM `ce_training_team_trainingrole` WHERE `ce_training_team_trainingrole`.`training_team` = 'a0b8cda8d219f5a4af005e73c542ef54'; args=('a0b8cda8d219f5a4af005e73c542ef54',)

此sql对应上面代码的 .exclude(users__id=user_id)
SELECT `ce_training_team_trainingrole`.`id`, `ce_training_team_trainingrole`.`resource_id`, `ce_training_team_trainingrole`.`training_team`, `ce_training_team_trainingrole`.`name`, `ce_training_team_trainingrole`.`description`, `ce_training_team_trainingrole`.`role_group`, `ce_training_team_trainingrole`.`missions_scheme`, `ce_training_team_trainingrole`.`nodes` FROM `ce_training_team_trainingrole` WHERE (`ce_training_team_trainingrole`.`training_team` = 'a0b8cda8d219f5a4af005e73c542ef54' AND NOT (`ce_training_team_trainingrole`.`id` IN (SELECT U1.`trainingrole_id` FROM `ce_training_team_trainingrole_users` U1 WHERE U1.`user_id` = 7))); args=('a0b8cda8d219f5a4af005e73c542ef54', 7)

此sql对应上面代码的 users = role.users.all()
SELECT `sv_auth_user`.`id`, `sv_auth_user`.`password`, `sv_auth_user`.`last_login`, `sv_auth_user`.`is_superuser`, `sv_auth_user`.`username`, `sv_auth_user`.`first_name`, `sv_auth_user`.`last_name`, `sv_auth_user`.`email`, `sv_auth_user`.`is_staff`, `sv_auth_user`.`is_active`, `sv_auth_user`.`date_joined`, `sv_auth_user`.`resource_id`, `sv_auth_user`.`logo`, `sv_auth_user`.`nickname`, `sv_auth_user`.`name`, `sv_auth_user`.`organization_id`, `sv_auth_user`.`status` FROM `sv_auth_user` INNER JOIN `ce_training_team_trainingrole_users` ON (`sv_auth_user`.`id` = `ce_training_team_trainingrole_users`.`user_id`) WHERE `ce_training_team_trainingrole_users`.`trainingrole_id` = 235; args=(235,)
SELECT `sv_auth_user`.`id`, `sv_auth_user`.`password`, `sv_auth_user`.`last_login`, `sv_auth_user`.`is_superuser`, `sv_auth_user`.`username`, `sv_auth_user`.`first_name`, `sv_auth_user`.`last_name`, `sv_auth_user`.`email`, `sv_auth_user`.`is_staff`, `sv_auth_user`.`is_active`, `sv_auth_user`.`date_joined`, `sv_auth_user`.`resource_id`, `sv_auth_user`.`logo`, `sv_auth_user`.`nickname`, `sv_auth_user`.`name`, `sv_auth_user`.`organization_id`, `sv_auth_user`.`status` FROM `sv_auth_user` INNER JOIN `ce_training_team_trainingrole_users` ON (`sv_auth_user`.`id` = `ce_training_team_trainingrole_users`.`user_id`) WHERE `ce_training_team_trainingrole_users`.`trainingrole_id` = 236; args=(236,)
SELECT `sv_auth_user`.`id`, `sv_auth_user`.`password`, `sv_auth_user`.`last_login`, `sv_auth_user`.`is_superuser`, `sv_auth_user`.`username`, `sv_auth_user`.`first_name`, `sv_auth_user`.`last_name`, `sv_auth_user`.`email`, `sv_auth_user`.`is_staff`, `sv_auth_user`.`is_active`, `sv_auth_user`.`date_joined`, `sv_auth_user`.`resource_id`, `sv_auth_user`.`logo`, `sv_auth_user`.`nickname`, `sv_auth_user`.`name`, `sv_auth_user`.`organization_id`, `sv_auth_user`.`status` FROM `sv_auth_user` INNER JOIN `ce_training_team_trainingrole_users` ON (`sv_auth_user`.`id` = `ce_training_team_trainingrole_users`.`user_id`) WHERE `ce_training_team_trainingrole_users`.`trainingrole_id` = 237; args
"""

# 优化后相关代码
role_list = model_api.get_training_role(
        training_team=data['resource_id']
    ).exclude(users__id=user_id).prefetch_related('users')

for role in role_list:
    role_name = role.name
    users = role.users.all()
    user_names = [user.username for user in users]
    role_info_list.append({
        'role_name': role_name,
        'users': user_names
    })

"""优化后执行sql
此sql对应上面代码的 role_list = get_training_role(training_team=data['resource_id'])
SELECT `ce_training_team_trainingrole`.`id`, `ce_training_team_trainingrole`.`resource_id`, `ce_training_team_trainingrole`.`training_team`, `ce_training_team_trainingrole`.`name`, `ce_training_team_trainingrole`.`description`, `ce_training_team_trainingrole`.`role_group`, `ce_training_team_trainingrole`.`missions_scheme`, `ce_training_team_trainingrole`.`nodes` FROM `ce_training_team_trainingrole` WHERE `ce_training_team_trainingrole`.`training_team` = 'a0b8cda8d219f5a4af005e73c542ef54'; args=('a0b8cda8d219f5a4af005e73c542ef54',)

此sql对应上面代码的 .exclude(users__id=user_id)
SELECT `ce_training_team_trainingrole`.`id`, `ce_training_team_trainingrole`.`resource_id`, `ce_training_team_trainingrole`.`training_team`, `ce_training_team_trainingrole`.`name`, `ce_training_team_trainingrole`.`description`, `ce_training_team_trainingrole`.`role_group`, `ce_training_team_trainingrole`.`missions_scheme`, `ce_training_team_trainingrole`.`nodes` FROM `ce_training_team_trainingrole` WHERE (`ce_training_team_trainingrole`.`training_team` = 'a0b8cda8d219f5a4af005e73c542ef54' AND NOT (`ce_training_team_trainingrole`.`id` IN (SELECT U1.`trainingrole_id` FROM `ce_training_team_trainingrole_users` U1 WHERE U1.`user_id` = 7))); args=('a0b8cda8d219f5a4af005e73c542ef54', 7)

此sql对应上面代码的 .prefetch_related('users')
SELECT (`ce_training_team_trainingrole_users`.`trainingrole_id`) AS `_prefetch_related_val_trainingrole_id`, `sv_auth_user`.`id`, `sv_auth_user`.`password`, `sv_auth_user`.`last_login`, `sv_auth_user`.`is_superuser`, `sv_auth_user`.`username`, `sv_auth_user`.`first_name`, `sv_auth_user`.`last_name`, `sv_auth_user`.`email`, `sv_auth_user`.`is_staff`, `sv_auth_user`.`is_active`, `sv_auth_user`.`date_joined`, `sv_auth_user`.`resource_id`, `sv_auth_user`.`logo`, `sv_auth_user`.`nickname`, `sv_auth_user`.`name`, `sv_auth_user`.`organization_id`, `sv_auth_user`.`status` FROM `sv_auth_user` INNER JOIN `ce_training_team_trainingrole_users` ON (`sv_auth_user`.`id` = `ce_training_team_trainingrole_users`.`user_id`) WHERE `ce_training_team_trainingrole_users`.`trainingrole_id` IN (235, 236, 237); args=(235, 236, 237)

相对来说此例子只是少了一个sql,但是如果这个角色下的人员有很多的话,每一个人都会进行一次sql查询,
而优化后不管有多少人,只是进行了一次sql查询
"""

開発::関連((select_related)とprefetch_related)の操作は、参照することができhttps://www.cnblogs.com/tuifeideyouran/p/4232028.html

キャッシュ機能の後に可能な他の操作とわずかの添加、例えば1次回()、。)(除外。values_list()。値()および他の関連する操作

関連するコード例:

# 优化后相关代码
@func_cache(ce_training_team_teacher_cache)
def get_training_role(**kwargs):
    """
    获取团队训练实战角色
    :param kwargs:参数
    :return: 团队训练实战角色obj
    """
    return TrainingRole.objects.filter(**kwargs)


@func_cache(ce_training_team_teacher_cache)
def get_training_role_first(**kwargs):
    """
    获取团队训练实战角色
    :param kwargs:参数
    :return: 团队训练实战角色obj
    """
    return TrainingRole.objects.filter(**kwargs).first()


@func_cache(ce_training_team_teacher_cache)
def get_training_role_prefetch(**kwargs):
    """
    获取团队训练实战角色预加载角色信息
    :param kwargs: 参数
    :return: 团队训练实战角色obj
    """
    return TrainingRole.objects.filter(**kwargs).prefetch_related('users')

単一のデータフィールドをフェッチ不要データベースクエリ条件の前に負論理によってパイソン、例えばvalues_list(前)は、代わりにforループを用いてもよい。
以上の使用の場合には、単一のキャッシュは、機能条件のために提供されてもよいです上記実施get_training_role_prefetch()関数。
各追加一つの追加の動作時間は、特に実際のコードに応じて調整することが、この機能のSQLクエリを増加させます

リリース6元記事 ウォンの賞賛0 ビュー49

おすすめ

転載: blog.csdn.net/Hongfei_ma/article/details/105004855