{ 'version': 1, 'handlers': { 'debug_console': { 'level': 'DEBUG', 'class': 'logging.StreamHandler', } }, 'loggers': { 'django.db.backends': { 'level': 'DEBUG', 'handlers': ['debug_console'], } } } Using breakpoint in pymysql source Set breakpoint at pymysql/connections.py:_execute_command You can watch all command including row level command. eg) SET AUTOCOMMIT, COMMIT You cannot watch "SET AUTOCOMMIT", "COMMIT" using django.db.backends logger Using Newrelic APM Databases Using Monyog Query analyzer QUERY ANALYSIS MODE with Sniffer Using performance schema settings.py
performance_schema.events_statements_summary_by_digest, ( SELECT sum(count_star) update_total FROM performance_schema.events_statements_summary_by_digest WHERE digest_text LIKE 'UPDATE%' ) update_totals WHERE digest_text LIKE 'UPDATE%' ORDER BY percentage_of_all DESC LIMIT 10 SELECT * FROM performance_schema.events_statements_history_long WHERE THREAD_ID IN (SELECT THREAD_ID FROM events_statements_history_long WHERE SQL_TEXT = 'COMMIT') ORDER BY THREAD_ID, EVENT_ID ; Optimization examples Removing unnecessary autocommit Before DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'ATOMIC_REQUESTS': True, ... }, } Top 10 time consuming queries Finding where "COMMIT" comes from settings.py
AUTOCOMMIT = 1 SET AUTOCOMMIT = 0 COMMIT SET AUTOCOMMIT = 1 Investigating problem First "SET AUTOCOMMIT = 0" autocommit function is called with value and compared with get_autocommit result which is retrieved from mysql View function Query output
"SET AUTOCOMMIT = 0" is removed because we added autocommit OPTIONS First "SET AUTOCOMMIT = 1" is removed even django calls self.set_autocommit(self.settings_dict["AUTOCOMMIT"]) because pymysql automatically detects current autocommit mode and if it is same, it doesn't send a query Removing transaction with view function def ping_general(request): return HttpResponse('OK', content_type='application/json') SET AUTOCOMMIT = 0 COMMIT SET AUTOCOMMIT = 1 @transaction.non_atomic_requests def ping_general(request): return HttpResponse('OK', content_type='application/json') No queries Removing transaction with view class Query output Before Query output After Query output
check queries @transaction.non_atomic_requests def ping_general(request): user = User.objects.cache().get(pk=44) logger.info(user.id) return HttpResponse('OK', content_type='application/json') SELECT @@SQL_AUTO_IS_NULL SELECT VERSION() SELECT xxx FROM `users` WHERE xxx... I expect no queries are executed at all after model is cached but it still executes two unnecessary query SELECT @@SQL_AUTO_IS_NULL SELECT VERSION() Investigating "SELECT @@SQL_AUTO_IS_NULL" Before After View function Query output with first call Query output with second call
you look at what happens inside the block save parent model handling pre_save signal update or insert and so on... It's impossible to optimize at the moment outside of django FAQ Why use transaction by default? Data integrity issues are usually found long after the problem actually happens Performance issues can be detected in early stage if it is critical Broken data is hard to fix Performance issues can be easily fixed