如何提高 django mysql 复制性能?
How can I improve django mysql copy performance?
我有一个定义了模型 (Person
) 的 django 应用程序,我还有一些没有任何模型的数据库(其中有一个 table Appointment
)已定义(并不意味着连接到 django 应用程序)。
我需要将一些数据从 Appointment
table 移到 Person
以便人们 table 需要反映约会 table 的所有信息].之所以这样,是因为有多个独立的数据库,例如 Appointment,需要复制到 Person table(所以我不想对其设置方式进行任何架构更改)。
这是我现在所做的:
res = sourcedb.fetchall() # from Appointment Table
for myrecord in res:
try:
existingrecord = Person.objects.filter(vendorid = myrecord[12], office = myoffice)[0]
except:
existingrecord = Person(vendorid = myrecord[12], office = myoffice)
existingrecord.firstname = myrecord[0]
existingrecord.midname = myrecord[1]
existingrecord.lastname = myrecord[2]
existingrecord.address1 = myrecord[3]
existingrecord.address2 = myrecord[4]
existingrecord.save()
问题是这太慢了(20K 条记录大约需要 8 分钟)。我该怎么做才能加快速度?
我考虑过以下方法:
1. bulk_create: 不能用这个,因为我有时要更新。
2。全部删除然后bulk_create Person模型对其他东西有依赖性,所以无法删除Person模型中的记录。
3。 INSERT ... ON DUPLICATE KEY UPDATE: 无法执行此操作,因为 Person table 的 PK 不同于 Appointment table PK(主键)。约会 PK 被复制到 Person table。如果有一种方法可以检查两个重复的键,我认为这种方法会起作用。
一些想法:
- 编辑:请参阅 Trewq 对此的评论并首先在您的 table 上创建索引……
- 使用
with transaction.atomic():
将其全部包装在一个事务中,因为默认情况下 Django 会在每次 save()
调用时创建一个新事务,这可能会变得非常昂贵。对于 20K 条记录,一个巨大的交易也可能是个问题,因此您可能必须编写一些代码将您的交易分成多个批次。试用并测量!
- 如果 RAM 不是问题(不应该有 20k 条记录),请先从约会 table 获取所有数据,然后使用单个
SELECT
查询获取所有现有的 Person 对象每条记录一个
- 使用
bulk_create
即使其中一些是更新。这仍然会为您的更新发出 UPDATE
查询,但会将所有 INSERT
查询减少到 one/a 几个,这仍然是一个改进。您可以通过以下事实来区分插入和更新:插入在调用 save()
之前不会设置主键并将插入保存到 Python 列表中以供稍后 bulk_create
而不是直接保存它们
- 作为最后的手段:编写原始 SQL 以利用 MySQLs
INSERT … ON DUPLICATE KEY UPDATE
语法。您不需要为此使用相同的主键,UNIQUE
键就足够了。键可以跨越多列,参见 Django 的 Meta.unique_together
模型选项。
我有一个定义了模型 (Person
) 的 django 应用程序,我还有一些没有任何模型的数据库(其中有一个 table Appointment
)已定义(并不意味着连接到 django 应用程序)。
我需要将一些数据从 Appointment
table 移到 Person
以便人们 table 需要反映约会 table 的所有信息].之所以这样,是因为有多个独立的数据库,例如 Appointment,需要复制到 Person table(所以我不想对其设置方式进行任何架构更改)。
这是我现在所做的:
res = sourcedb.fetchall() # from Appointment Table
for myrecord in res:
try:
existingrecord = Person.objects.filter(vendorid = myrecord[12], office = myoffice)[0]
except:
existingrecord = Person(vendorid = myrecord[12], office = myoffice)
existingrecord.firstname = myrecord[0]
existingrecord.midname = myrecord[1]
existingrecord.lastname = myrecord[2]
existingrecord.address1 = myrecord[3]
existingrecord.address2 = myrecord[4]
existingrecord.save()
问题是这太慢了(20K 条记录大约需要 8 分钟)。我该怎么做才能加快速度?
我考虑过以下方法:
1. bulk_create: 不能用这个,因为我有时要更新。
2。全部删除然后bulk_create Person模型对其他东西有依赖性,所以无法删除Person模型中的记录。
3。 INSERT ... ON DUPLICATE KEY UPDATE: 无法执行此操作,因为 Person table 的 PK 不同于 Appointment table PK(主键)。约会 PK 被复制到 Person table。如果有一种方法可以检查两个重复的键,我认为这种方法会起作用。
一些想法:
- 编辑:请参阅 Trewq 对此的评论并首先在您的 table 上创建索引……
- 使用
with transaction.atomic():
将其全部包装在一个事务中,因为默认情况下 Django 会在每次save()
调用时创建一个新事务,这可能会变得非常昂贵。对于 20K 条记录,一个巨大的交易也可能是个问题,因此您可能必须编写一些代码将您的交易分成多个批次。试用并测量! - 如果 RAM 不是问题(不应该有 20k 条记录),请先从约会 table 获取所有数据,然后使用单个
SELECT
查询获取所有现有的 Person 对象每条记录一个 - 使用
bulk_create
即使其中一些是更新。这仍然会为您的更新发出UPDATE
查询,但会将所有INSERT
查询减少到 one/a 几个,这仍然是一个改进。您可以通过以下事实来区分插入和更新:插入在调用save()
之前不会设置主键并将插入保存到 Python 列表中以供稍后bulk_create
而不是直接保存它们 - 作为最后的手段:编写原始 SQL 以利用 MySQLs
INSERT … ON DUPLICATE KEY UPDATE
语法。您不需要为此使用相同的主键,UNIQUE
键就足够了。键可以跨越多列,参见 Django 的Meta.unique_together
模型选项。