Fixed #31376 -- Optimized nulls ordering when possible on SQLite and MySQL.

Both backends order NULLs first on ascending ordering and last on
descending ordering which makes ORDER BY IS (NOT)? NULL wasteful when
asc(nulls_first) and desc(nulls_last) are used since it prevents indice
usage.
This commit is contained in:
Simon Charette 2020-03-17 22:00:28 -04:00 committed by Mariusz Felisiak
parent f622b49010
commit 9f07f27124
4 changed files with 11 additions and 2 deletions

View File

@ -91,6 +91,9 @@ class BaseDatabaseFeatures:
# Does the backend support NULLS FIRST and NULLS LAST in ORDER BY? # Does the backend support NULLS FIRST and NULLS LAST in ORDER BY?
supports_order_by_nulls_modifier = True supports_order_by_nulls_modifier = True
# Does the backend orders NULLS FIRST by default?
order_by_nulls_first = False
# The database's limit on the number of query parameters. # The database's limit on the number of query parameters.
max_query_params = None max_query_params = None

View File

@ -51,6 +51,7 @@ class DatabaseFeatures(BaseDatabaseFeatures):
# Neither MySQL nor MariaDB support partial indexes. # Neither MySQL nor MariaDB support partial indexes.
supports_partial_indexes = False supports_partial_indexes = False
supports_order_by_nulls_modifier = False supports_order_by_nulls_modifier = False
order_by_nulls_first = True
@cached_property @cached_property
def _mysql_storage_engine(self): def _mysql_storage_engine(self):

View File

@ -45,3 +45,4 @@ class DatabaseFeatures(BaseDatabaseFeatures):
supports_frame_range_fixed_distance = Database.sqlite_version_info >= (3, 28, 0) supports_frame_range_fixed_distance = Database.sqlite_version_info >= (3, 28, 0)
supports_aggregate_filter_clause = Database.sqlite_version_info >= (3, 30, 1) supports_aggregate_filter_clause = Database.sqlite_version_info >= (3, 30, 1)
supports_order_by_nulls_modifier = Database.sqlite_version_info >= (3, 30, 0) supports_order_by_nulls_modifier = Database.sqlite_version_info >= (3, 30, 0)
order_by_nulls_first = True

View File

@ -1120,9 +1120,13 @@ class OrderBy(BaseExpression):
elif self.nulls_first: elif self.nulls_first:
template = '%s NULLS FIRST' % template template = '%s NULLS FIRST' % template
else: else:
if self.nulls_last: if self.nulls_last and not (
self.descending and connection.features.order_by_nulls_first
):
template = '%%(expression)s IS NULL, %s' % template template = '%%(expression)s IS NULL, %s' % template
elif self.nulls_first: elif self.nulls_first and not (
not self.descending and connection.features.order_by_nulls_first
):
template = '%%(expression)s IS NOT NULL, %s' % template template = '%%(expression)s IS NOT NULL, %s' % template
connection.ops.check_expression_support(self) connection.ops.check_expression_support(self)
expression_sql, params = compiler.compile(self.expression) expression_sql, params = compiler.compile(self.expression)