Merge pull request #15985 from adityahase/perf-patch

perf(patch): Use INSERT with ON DUPLICATE KEY UPDATE
This commit is contained in:
Nabin Hait 2018-11-15 14:50:58 +05:30 committed by GitHub
commit a0a2f58a21
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -14,7 +14,7 @@ def execute():
"Purchase Order", "Purchase Invoice", "Purchase Receipt", "Quotation", "Supplier Quotation"] "Purchase Order", "Purchase Invoice", "Purchase Receipt", "Quotation", "Supplier Quotation"]
for doctype in doctypes: for doctype in doctypes:
total_qty = frappe.db.sql(''' total_qty = frappe.db.sql('''
SELECT SELECT
parent, SUM(qty) as qty parent, SUM(qty) as qty
FROM FROM
@ -22,14 +22,25 @@ def execute():
GROUP BY parent GROUP BY parent
''' % (doctype), as_dict = True) ''' % (doctype), as_dict = True)
when_then = [] # Query to update total_qty might become too big, Update in batches
for d in total_qty: # batch_size is chosen arbitrarily, Don't try too hard to reason about it
when_then.append(""" batch_size = 100000
when dt.name = '{0}' then {1} for i in range(0, len(total_qty), batch_size):
""".format(frappe.db.escape(d.get("parent")), d.get("qty"))) batch_transactions = total_qty[i:i + batch_size]
if when_then: # UPDATE with CASE for some reason cannot use PRIMARY INDEX,
frappe.db.sql(''' # causing all rows to be examined, leading to a very slow update
UPDATE
`tab%s` dt SET dt.total_qty = CASE %s ELSE 0.0 END # UPDATE with WHERE clause uses PRIMARY INDEX, but will lead to too many queries
''' % (doctype, " ".join(when_then)))
# INSERT with ON DUPLICATE KEY UPDATE uses PRIMARY INDEX
# and can perform multiple updates per query
# This is probably never used anywhere else as of now, but should be
values = []
for d in batch_transactions:
values.append("('{}', {})".format(d.parent, d.qty))
conditions = ",".join(values)
frappe.db.sql("""
INSERT INTO `tab{}` (name, total_qty) VALUES {}
ON DUPLICATE KEY UPDATE name = VALUES(name), total_qty = VALUES(total_qty)
""".format(doctype, conditions))