Fixed #31376 -- Optimized nulls ordering when possible on SQLite and MySQL.
diff --git a/django/db/backends/base/features.py b/django/db/backends/base/features.py
index 5760b590987df..c2b92ecdee0e0 100644
--- a/django/db/backends/base/features.py
+++ b/django/db/backends/base/features.py
@@ -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
 
diff --git a/django/db/backends/mysql/features.py b/django/db/backends/mysql/features.py
index 1d0cd365dbc8a..e1d4ce726b7d4 100644
--- a/django/db/backends/mysql/features.py
+++ b/django/db/backends/mysql/features.py
@@ -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):
diff --git a/django/db/backends/sqlite3/features.py b/django/db/backends/sqlite3/features.py
index 6aebbc32627a3..84eca9864409c 100644
--- a/django/db/backends/sqlite3/features.py
+++ b/django/db/backends/sqlite3/features.py
@@ -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
diff --git a/django/db/models/expressions.py b/django/db/models/expressions.py
index f773e99a0fdf1..84960d77e1653 100644
--- a/django/db/models/expressions.py
+++ b/django/db/models/expressions.py
@@ -1120,9 +1120,13 @@ def as_sql(self, compiler, connection, template=None, **extra_context):
             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)

https://code.djangoproject.com/ticket/31376

---

Both backends order `NULL`s 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.