diff --git a/frappe/core/report/database_storage_usage_by_tables/database_storage_usage_by_tables.js b/frappe/core/report/database_storage_usage_by_tables/database_storage_usage_by_tables.js index 8a4dbefc45..5a1ae6f87a 100644 --- a/frappe/core/report/database_storage_usage_by_tables/database_storage_usage_by_tables.js +++ b/frappe/core/report/database_storage_usage_by_tables/database_storage_usage_by_tables.js @@ -3,4 +3,49 @@ frappe.query_reports["Database Storage Usage By Tables"] = { filters: [], + onload: function (report) { + report.page.add_inner_button( + __("Optimize"), + function () { + let d = new frappe.ui.Dialog({ + title: "Optimize Doctype", + fields: [ + { + label: "Select a DocType", + fieldname: "doctype_name", + fieldtype: "Link", + options: "DocType", + get_query: function () { + return { + filters: { issingle: ["=", false], is_virtual: ["=", false] }, + }; + }, + }, + ], + size: "small", + primary_action_label: "Optimize", + primary_action(values) { + frappe.call({ + method: "frappe.core.report.database_storage_usage_by_tables.database_storage_usage_by_tables.optimize_doctype", + args: { + doctype_name: values.doctype_name, + }, + callback: function (r) { + if (!r.exec) { + frappe.show_alert( + __( + `${values.doctype_name} has been added to queue for optimization` + ) + ); + } + }, + }); + d.hide(); + }, + }); + d.show(); + }, + __("Actions") + ); + }, }; diff --git a/frappe/core/report/database_storage_usage_by_tables/database_storage_usage_by_tables.py b/frappe/core/report/database_storage_usage_by_tables/database_storage_usage_by_tables.py index c88262552e..73052ad170 100644 --- a/frappe/core/report/database_storage_usage_by_tables/database_storage_usage_by_tables.py +++ b/frappe/core/report/database_storage_usage_by_tables/database_storage_usage_by_tables.py @@ -38,3 +38,27 @@ def execute(filters=None): as_dict=1, ) return COLUMNS, data + + +@frappe.whitelist() +def optimize_doctype(doctype_name: str): + frappe.only_for("System Manager") + frappe.enqueue( + optimize_doctype_job, + queue="long", + job_id=f"optimize-{doctype_name}", + doctype_name=doctype_name, + deduplicate=True, + ) + + +def optimize_doctype_job(doctype_name: str): + from frappe.utils import get_table_name + + doctype_table = get_table_name(doctype_name, wrap_in_backticks=True) + if frappe.db.db_type == "mariadb": + query = f"OPTIMIZE TABLE {doctype_table};" + else: + query = f"VACUUM (ANALYZE) {doctype_table};" + + frappe.db.sql(query)