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?
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.
max_query_params = None

View File

@ -51,6 +51,7 @@ class DatabaseFeatures(BaseDatabaseFeatures):
# Neither MySQL nor MariaDB support partial indexes.
supports_partial_indexes = False
supports_order_by_nulls_modifier = False
order_by_nulls_first = True
@cached_property
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_aggregate_filter_clause = Database.sqlite_version_info >= (3, 30, 1)
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:
template = '%s NULLS FIRST' % template
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
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
connection.ops.check_expression_support(self)
expression_sql, params = compiler.compile(self.expression)