Xin chào các bạn, mình viết bài này để share kinh nghiệm insert hoặc update nhiều dòng dữ liệu với database MySQL.
Bài toán:
mình cần phải thêm nhiều dòng vào DB, nếu dữ liệu đó đã tồn tại thì update một cột nào đó thôi.
Query insert/update từng dòng
Cách đơn giản nhất là query từng dòng, kiểm tra trùng và update. Ở đây mình dùng Django ORM phiên bản 1.6 chỉ có hàm get_or_create
kiểm tra xem dữ liệu có chưa, nếu chưa có thì tạo.
for record in records:
update_time = random.randint(0, 100)
record, created = VideoTab.objects.get_or_create(
match_id=record.match_id,
round_num=record.round_num,
video_id=record.video_id,
platform=record.platform,
defaults={
'status': record.status,
'create_time': record.create_time,
'update_time': update_time,
},
)
if not created:
# nếu đã tạo rồi thì update cái update_time thôi
record.update_time = update_time
record.save()
Làm như thế cũng được, nhưng rất chậm bởi vì mình cần phải gửi yêu cầu lên DB cho mỗi dòng dữ liệu và chờ kiểm tra xử lý.
query update nhiều dòng
Cách hiệu quả hơn đó là dùng MysqlClient.execute_many
DB = MysqlClient(...) #thông tin config db
records = self.get_all_records()
my_raw_sql = """
INSERT INTO my_table (video_id, platform, match_id, round_num, status, create_time, update_time)
VALUES (%s, %s, %s, %s, %s, %s, %s)
ON DUPLICATE KEY UPDATE update_time=VALUES(update_time)
"""
limit = 1000
data = list()
num_report = len(records)
for i, record in enumerate(records):
update_time = random.randint(0, 100)
row = (
record.video_id, record.platform, record.match_id, record.round_num, record.status, record.create_time, update_time
)
data.append(row)
if i + 1 == num_report or (i + 1) % limit == 0:
DB.execute_many(my_raw_sql, data)
data = list()
Với code này thì mình sẽ dồn nhiều record lại rồi gửi lên DB một lần. Trong ví dụ trên thì Đạt để limit = 1000, tức là dồn 1000 record lại rồi gửi lên DB cho nó chạy một lần, như thế nhanh hơn.
lúc lệnh execute_many
được thực thi thì dữ liệu được đẩy vào DB sẽ trông giống thế này
INSERT INTO my_table (video_id, platform, match_id, round_num, status, create_time, update_time)
VALUES
('abc', 1, 396, 1, 0, 1466495556, 90),
...
('xyz', 2, 831, 2, 0, 1489060345, 48)
ON DUPLICATE KEY UPDATE update_time=VALUES(update_time)
So sánh kết quả
Như kết quả so sánh thì cách dùng execute_many
nhanh hơn tới 66 lần với tầm 3000 dòng dữ liệu