Refs #30897 -- Added support for ANALYZE option to Queryset.explain() on MariaDB and MySQL 8.0.18+.
This commit is contained in:
parent
742961332e
commit
55df1750be
|
@ -117,6 +117,10 @@ class DatabaseFeatures(BaseDatabaseFeatures):
|
||||||
# EXTENDED is deprecated (and not required) in MySQL 5.7.
|
# EXTENDED is deprecated (and not required) in MySQL 5.7.
|
||||||
return not self.connection.mysql_is_mariadb and self.connection.mysql_version < (5, 7)
|
return not self.connection.mysql_is_mariadb and self.connection.mysql_version < (5, 7)
|
||||||
|
|
||||||
|
@cached_property
|
||||||
|
def supports_explain_analyze(self):
|
||||||
|
return self.connection.mysql_is_mariadb or self.connection.mysql_version >= (8, 0, 18)
|
||||||
|
|
||||||
@cached_property
|
@cached_property
|
||||||
def supported_explain_formats(self):
|
def supported_explain_formats(self):
|
||||||
# Alias MySQL's TRADITIONAL to TEXT for consistency with other
|
# Alias MySQL's TRADITIONAL to TEXT for consistency with other
|
||||||
|
|
|
@ -299,11 +299,16 @@ class DatabaseOperations(BaseDatabaseOperations):
|
||||||
elif not format and 'TREE' in self.connection.features.supported_explain_formats:
|
elif not format and 'TREE' in self.connection.features.supported_explain_formats:
|
||||||
# Use TREE by default (if supported) as it's more informative.
|
# Use TREE by default (if supported) as it's more informative.
|
||||||
format = 'TREE'
|
format = 'TREE'
|
||||||
|
analyze = options.pop('analyze', False)
|
||||||
prefix = super().explain_query_prefix(format, **options)
|
prefix = super().explain_query_prefix(format, **options)
|
||||||
if format:
|
if analyze and self.connection.features.supports_explain_analyze:
|
||||||
|
# MariaDB uses ANALYZE instead of EXPLAIN ANALYZE.
|
||||||
|
prefix = 'ANALYZE' if self.connection.mysql_is_mariadb else prefix + ' ANALYZE'
|
||||||
|
if format and not (analyze and not self.connection.mysql_is_mariadb):
|
||||||
|
# Only MariaDB supports the analyze option with formats.
|
||||||
prefix += ' FORMAT=%s' % format
|
prefix += ' FORMAT=%s' % format
|
||||||
if self.connection.features.needs_explain_extended and format is None:
|
if self.connection.features.needs_explain_extended and not analyze and format is None:
|
||||||
# EXTENDED and FORMAT are mutually exclusive options.
|
# ANALYZE, EXTENDED, and FORMAT are mutually exclusive options.
|
||||||
prefix += ' EXTENDED'
|
prefix += ' EXTENDED'
|
||||||
return prefix
|
return prefix
|
||||||
|
|
||||||
|
|
|
@ -2587,13 +2587,14 @@ Pass these flags as keyword arguments. For example, when using PostgreSQL::
|
||||||
Execution time: 0.058 ms
|
Execution time: 0.058 ms
|
||||||
|
|
||||||
On some databases, flags may cause the query to be executed which could have
|
On some databases, flags may cause the query to be executed which could have
|
||||||
adverse effects on your database. For example, PostgreSQL's ``ANALYZE`` flag
|
adverse effects on your database. For example, the ``ANALYZE`` flag supported
|
||||||
could result in changes to data if there are triggers or if a function is
|
by MariaDB, MySQL 8.0.18+, and PostgreSQL could result in changes to data if
|
||||||
called, even for a ``SELECT`` query.
|
there are triggers or if a function is called, even for a ``SELECT`` query.
|
||||||
|
|
||||||
.. versionchanged:: 3.1
|
.. versionchanged:: 3.1
|
||||||
|
|
||||||
Support for the ``'TREE'`` format on MySQL 8.0.16+ was added.
|
Support for the ``'TREE'`` format on MySQL 8.0.16+ and ``analyze`` option
|
||||||
|
on MariaDB and MySQL 8.0.18+ were added.
|
||||||
|
|
||||||
.. _field-lookups:
|
.. _field-lookups:
|
||||||
|
|
||||||
|
|
|
@ -169,7 +169,10 @@ Models
|
||||||
:class:`~django.db.models.DateTimeField`, and the new :lookup:`iso_week_day`
|
:class:`~django.db.models.DateTimeField`, and the new :lookup:`iso_week_day`
|
||||||
lookup allows querying by an ISO-8601 day of week.
|
lookup allows querying by an ISO-8601 day of week.
|
||||||
|
|
||||||
* :meth:`.QuerySet.explain` now supports ``TREE`` format on MySQL 8.0.16+.
|
* :meth:`.QuerySet.explain` now supports:
|
||||||
|
|
||||||
|
* ``TREE`` format on MySQL 8.0.16+,
|
||||||
|
* ``analyze`` option on MySQL 8.0.18+ and MariaDB.
|
||||||
|
|
||||||
Pagination
|
Pagination
|
||||||
~~~~~~~~~~
|
~~~~~~~~~~
|
||||||
|
|
|
@ -80,6 +80,25 @@ class ExplainTests(TestCase):
|
||||||
self.assertEqual(len(captured_queries), 1)
|
self.assertEqual(len(captured_queries), 1)
|
||||||
self.assertIn('FORMAT=TRADITIONAL', captured_queries[0]['sql'])
|
self.assertIn('FORMAT=TRADITIONAL', captured_queries[0]['sql'])
|
||||||
|
|
||||||
|
@unittest.skipUnless(connection.vendor == 'mysql', 'MariaDB and MySQL >= 8.0.18 specific.')
|
||||||
|
def test_mysql_analyze(self):
|
||||||
|
# Inner skip to avoid module level query for MySQL version.
|
||||||
|
if not connection.features.supports_explain_analyze:
|
||||||
|
raise unittest.SkipTest('MariaDB and MySQL >= 8.0.18 specific.')
|
||||||
|
qs = Tag.objects.filter(name='test')
|
||||||
|
with CaptureQueriesContext(connection) as captured_queries:
|
||||||
|
qs.explain(analyze=True)
|
||||||
|
self.assertEqual(len(captured_queries), 1)
|
||||||
|
prefix = 'ANALYZE ' if connection.mysql_is_mariadb else 'EXPLAIN ANALYZE '
|
||||||
|
self.assertTrue(captured_queries[0]['sql'].startswith(prefix))
|
||||||
|
with CaptureQueriesContext(connection) as captured_queries:
|
||||||
|
qs.explain(analyze=True, format='JSON')
|
||||||
|
self.assertEqual(len(captured_queries), 1)
|
||||||
|
if connection.mysql_is_mariadb:
|
||||||
|
self.assertIn('FORMAT=JSON', captured_queries[0]['sql'])
|
||||||
|
else:
|
||||||
|
self.assertNotIn('FORMAT=JSON', captured_queries[0]['sql'])
|
||||||
|
|
||||||
@unittest.skipUnless(connection.vendor == 'mysql', 'MySQL < 5.7 specific')
|
@unittest.skipUnless(connection.vendor == 'mysql', 'MySQL < 5.7 specific')
|
||||||
def test_mysql_extended(self):
|
def test_mysql_extended(self):
|
||||||
# Inner skip to avoid module level query for MySQL version.
|
# Inner skip to avoid module level query for MySQL version.
|
||||||
|
|
Loading…
Reference in New Issue