Refs #30897 -- Added support for TREE format to Queryset.explain() on MySQL 8.0.16+.

This commit is contained in:
Nick Pope 2019-10-21 17:32:56 +01:00 committed by Mariusz Felisiak
parent 37f02c47f8
commit 742961332e
5 changed files with 25 additions and 6 deletions

View File

@ -48,8 +48,6 @@ class DatabaseFeatures(BaseDatabaseFeatures):
END;
"""
db_functions_convert_bytes_to_str = True
# Alias MySQL's TRADITIONAL to TEXT for consistency with other backends.
supported_explain_formats = {'JSON', 'TEXT', 'TRADITIONAL'}
# Neither MySQL nor MariaDB support partial indexes.
supports_partial_indexes = False
@ -119,6 +117,15 @@ class DatabaseFeatures(BaseDatabaseFeatures):
# EXTENDED is deprecated (and not required) in MySQL 5.7.
return not self.connection.mysql_is_mariadb and self.connection.mysql_version < (5, 7)
@cached_property
def supported_explain_formats(self):
# Alias MySQL's TRADITIONAL to TEXT for consistency with other
# backends.
formats = {'JSON', 'TEXT', 'TRADITIONAL'}
if not self.connection.mysql_is_mariadb and self.connection.mysql_version >= (8, 0, 16):
formats.add('TREE')
return formats
@cached_property
def supports_transactions(self):
"""

View File

@ -296,6 +296,9 @@ class DatabaseOperations(BaseDatabaseOperations):
# Alias MySQL's TRADITIONAL to TEXT for consistency with other backends.
if format and format.upper() == 'TEXT':
format = 'TRADITIONAL'
elif not format and 'TREE' in self.connection.features.supported_explain_formats:
# Use TREE by default (if supported) as it's more informative.
format = 'TREE'
prefix = super().explain_query_prefix(format, **options)
if format:
prefix += ' FORMAT=%s' % format

View File

@ -2571,8 +2571,10 @@ because an implementation there isn't straightforward.
The ``format`` parameter changes the output format from the databases's default,
usually text-based. PostgreSQL supports ``'TEXT'``, ``'JSON'``, ``'YAML'``, and
``'XML'``. MySQL supports ``'TEXT'`` (also called ``'TRADITIONAL'``) and
``'JSON'``.
``'XML'`` formats. MariaDB and MySQL support ``'TEXT'`` (also called
``'TRADITIONAL'``) and ``'JSON'`` formats. MySQL 8.0.16+ also supports an
improved ``'TREE'`` format, which is similar to PostgreSQL's ``'TEXT'`` output
and is used by default, if supported.
Some databases accept flags that can return more information about the query.
Pass these flags as keyword arguments. For example, when using PostgreSQL::
@ -2589,6 +2591,10 @@ adverse effects on your database. For example, PostgreSQL's ``ANALYZE`` flag
could result in changes to data if there are triggers or if a function is
called, even for a ``SELECT`` query.
.. versionchanged:: 3.1
Support for the ``'TREE'`` format on MySQL 8.0.16+ was added.
.. _field-lookups:
``Field`` lookups

View File

@ -169,6 +169,8 @@ Models
:class:`~django.db.models.DateTimeField`, and the new :lookup:`iso_week_day`
lookup allows querying by an ISO-8601 day of week.
* :meth:`.QuerySet.explain` now supports ``TREE`` format on MySQL 8.0.16+.
Pagination
~~~~~~~~~~

View File

@ -71,9 +71,10 @@ class ExplainTests(TestCase):
@unittest.skipUnless(connection.vendor == 'mysql', 'MySQL specific')
def test_mysql_text_to_traditional(self):
# Initialize the cached property, if needed, to prevent a query for
# the MySQL version during the QuerySet evaluation.
# Ensure these cached properties are initialized to prevent queries for
# the MariaDB or MySQL version during the QuerySet evaluation.
connection.features.needs_explain_extended
connection.features.supported_explain_formats
with CaptureQueriesContext(connection) as captured_queries:
Tag.objects.filter(name='test').explain(format='text')
self.assertEqual(len(captured_queries), 1)