数据迁移脚本优化过程:从 MySQL 到 Django 模型表

本文涉及的产品
RDS AI 助手,专业版
RDS MySQL DuckDB 分析主实例,集群系列 4核8GB
RDS MySQL DuckDB 分析主实例,基础系列 4核8GB
简介: 在大规模的数据迁移过程中,性能问题往往是开发者面临的主要挑战之一。本文将分析一个数据迁移脚本的优化过程,展示如何从 MySQL 数据库迁移数据到 Django 模型表,并探讨优化前后的性能差异。

在大规模的数据迁移过程中,性能问题往往是开发者面临的主要挑战之一。本文将分析一个数据迁移脚本的优化过程,展示如何从 MySQL 数据库迁移数据到 Django 模型表,并探讨优化前后的性能差异。

优化前的脚本分析

优化前的脚本按批次从 MySQL 数据库中读取数据,并将其插入到 Django 模型表中。每次读取的数据量由 batch_size 确定。以下是优化前的关键部分:

fetch_sql = f"""
    SELECT search_rank, search_term,  `period`, report_date 
    FROM hot_search_terms_table 
    WHERE period = '{period}' 
    LIMIT %s OFFSET %s;
"""

每次查询使用 LIMITOFFSET 子句,OFFSET 指定从哪一行开始读取。然而,随着数据量的增加,OFFSET 会导致性能显著下降,因为数据库必须扫描更多行来确定结果集的起点。

优化后的脚本分析

优化后的脚本通过使用递增的主键 ID 进行分页查询,避免了 OFFSET 带来的性能问题。以下是优化后的关键部分:

fetch_sql = f"""
    SELECT id, search_rank, search_term,`period`, report_date 
    FROM hot_search_terms_table 
    WHERE period = %s AND id > %s 
    ORDER BY id ASC 
    LIMIT %s;
"""

通过 WHERE id > %sORDER BY id ASC,我们可以确保每次查询的结果集都是按主键 ID 排序的,性能大大提高,因为数据库可以直接从上一次查询结束的地方开始读取数据。

优化前后的性能比较

优化前的性能问题

  1. 查询性能下降:随着 OFFSET 值的增加,查询性能会显著下降。数据库需要扫描所有的行,直到达到指定的偏移量,然后返回后续的行。
  2. 长时间等待:当数据量较大时,随着偏移量的增加,每次查询所需的时间会变得越来越长。

优化后的性能改进

  1. 高效的分页查询:使用递增的主键 ID 进行分页查询,避免了扫描大量无关行的数据。
  2. 稳定的查询时间:每次查询都只需读取新的数据,无需扫描之前已经处理过的数据行,查询时间稳定且较快。

实施细节

优化前的实现

优化前的实现通过读取偏移量文件来记录上次处理的位置,每次查询都从该位置开始,读取一批数据并插入到 Django 模型表中:

class Command(BaseCommand):
    # 省略部分代码...

    def handle(self, *args, **kwargs):
        try:
            # 连接数据库
            mysql_conn = mysql.connector.connect(**mysql_config)
            mysql_cursor = mysql_conn.cursor()
            # 批次处理
            while True:
                self.stdout.write(self.style.SUCCESS(f"正在获取 {offset} -  {offset + batch_size} 行的数据"))
                zhilin_cursor.execute(fetch_sql, (batch_size, offset))
                batch_data = zhilin_cursor.fetchall()
                if not batch_data:
                    break

                # 转换并插入数据
                objects = [HotSearchTermsReportABA(...) for row in batch_data]
                with transaction.atomic():
                    HotSearchTermsReportABA.objects.bulk_create(objects)
                    offset += batch_size
                    total_rows_transferred += len(batch_data)
                    self.update_last_offset(offset)

        except Error as e:
            # 错误处理
            self.stdout.write(self.style.ERROR(f"传输过程中出现异常:{e}"))

优化后的实现

优化后的实现使用主键 ID 进行分页查询,并记录上次处理的最大 ID:

class Command(BaseCommand):
    # 省略部分代码...

    def handle(self, *args, **kwargs):
        try:
            # 连接数据库
            mysql_conn = mysql.connector.connect(**mysql_config)
            mysql_cursor = mysql_conn.cursor()
            # 批次处理
            while True:
                self.stdout.write(self.style.SUCCESS(f"正在获取 ID 大于 {last_id}{self.batch_size} 行数据"))
                zhilin_cursor.execute(fetch_sql, (period, last_id, self.batch_size))
                batch_data = zhilin_cursor.fetchall()
                if not batch_data:
                    break

                # 转换并插入数据
                objects = [HotSearchTermsReportABA(...) for row in batch_data]
                with transaction.atomic():
                    HotSearchTermsReportABA.objects.bulk_create(objects)
                    last_id = batch_data[-1][0]
                    total_rows_transferred += len(batch_data)
                    self.update_last_id(last_id)

        except Error as e:
            # 错误处理
            self.stdout.write(self.style.ERROR(f"传输过程中出现异常:{e}"))

总结

通过上述优化过程解决了数据量增大导致的查询性能下降问题。具体优化策略包括:

  1. 使用主键 ID 进行分页查询,避免 OFFSET 带来的性能问题。
  2. 确保每次查询只读取新的数据,减少数据库扫描的行数。
相关实践学习
每个IT人都想学的“Web应用上云经典架构”实战
本实验从Web应用上云这个最基本的、最普遍的需求出发,帮助IT从业者们通过“阿里云Web应用上云解决方案”,了解一个企业级Web应用上云的常见架构,了解如何构建一个高可用、可扩展的企业级应用架构。
MySQL数据库入门学习
本课程通过最流行的开源数据库MySQL带你了解数据库的世界。   相关的阿里云产品:云数据库RDS MySQL 版 阿里云关系型数据库RDS(Relational Database Service)是一种稳定可靠、可弹性伸缩的在线数据库服务,提供容灾、备份、恢复、迁移等方面的全套解决方案,彻底解决数据库运维的烦恼。 了解产品详情: https://www.aliyun.com/product/rds/mysql 
相关文章
|
11月前
|
关系型数据库 MySQL Shell
MySQL 备份 Shell 脚本:支持远程同步与阿里云 OSS 备份
一款自动化 MySQL 备份 Shell 脚本,支持本地存储、远程服务器同步(SSH+rsync)、阿里云 OSS 备份,并自动清理过期备份。适用于数据库管理员和开发者,帮助确保数据安全。
|
6月前
|
SQL 存储 数据库
Django模型查询与性能调优:告别N+1问题
本文详解Django数据库查询基础与优化技巧,涵盖QuerySet使用、关联查询(一对多/多对多)、N+1查询问题及解决方案(select_related、prefetch_related)、高级查询方法及项目实战中的数据权限控制实现。
278 0
|
7月前
|
存储 数据库 Python
Django模型关系:从一对多到多对多全解析
本文详解Django模型关系:一对多(ForeignKey)及多对多(ManyToManyField)关系的定义、操作与优化技巧。同时探讨外键约束的使用场景与权衡策略。
398 0
|
7月前
|
存储 关系型数据库 MySQL
Django模型开发:模型字段、元数据与继承全方位讲解
本文将全面介绍 Django 模型的关键知识点,包括模型字段类型、映射、常用配置选项以及模型继承等高级特性,帮助开发者快速掌握模型设计与使用技巧。
247 0
|
9月前
|
关系型数据库 MySQL Linux
实现MySQL数据库的定时自动备份脚本。
拿走,不谢,这个脚本配方(指引)保证你的数据库数据像蛋糕店一样地天天更新,还能确保老旧的蛋糕(数据)不会堆积满仓库。这下可好,数据安全有保障,数据库管理员也能轻松一点,偶尔闲下来的时候,煮杯咖啡,看个剧岂不美哉?别忘了偶尔检查一下你的自动备份是否正常工作,以防万一蛋糕机器出了点小差错。
458 20
|
9月前
|
SQL 数据采集 关系型数据库
实现MySQL与SQL Server之间数据迁移的有效方法
总的来说,从MySQL到SQL Server的数据迁移是一个涉及到很多步骤的过程,可能会遇到各种问题和挑战。但只要精心规划、仔细执行,这个任务是完全可以完成的。
645 18
|
SQL 关系型数据库 MySQL
|
机器学习/深度学习 前端开发 网络架构
Django如何调用机器学习模型进行预测
Django如何调用机器学习模型进行预测
350 5
|
机器学习/深度学习 监控 数据挖掘
基于Django和百度飞桨模型的情感识别Web系统
基于Django和百度飞桨模型的情感识别Web系统
276 5
|
机器学习/深度学习 算法 搜索推荐
django调用矩阵分解推荐算法模型做推荐系统
django调用矩阵分解推荐算法模型做推荐系统
213 4