Reputation: 1052
I have a django model with the following indexes:
class Meta:
indexes = [
models.Index(fields=['-current']),
models.Index(fields=['current']),
]
The relevant field is defined as:
current = models.IntegerField(null=True)
These were added and I ran the migration and saw the results:
companies/migrations/0294_auto_20220110_1155.py
- Create index companies_c_current_f2c815_idx on field(s) -current of model company
- Create index companies_c_current_c8bcb7_idx on field(s) current of model company
I've found that running a django-rest-framework query with ordering=current is ~5x faster than with ordering=-current. Using PSQL explain I get the following:
# explain analyze select * from company order by current desc nulls last limit 100;
QUERY PLAN
--------------------------------------------------------------------------------------------------------------------------------------------------------
Limit (cost=41028.75..41040.42 rows=100 width=1223) (actual time=866.587..867.650 rows=100 loops=1) -> Gather Merge (cost=41028.75..68747.19 rows=237570 width=1223) (actual time=866.585..867.644 rows=100 loops=1)
Workers Planned: 2
Workers Launched: 2
-> Sort (cost=40028.73..40325.69 rows=118785 width=1223) (actual time=849.292..849.296 rows=48 loops=3)
Sort Key: current DESC NULLS LAST
Sort Method: top-N heapsort Memory: 275kB
Worker 0: Sort Method: top-N heapsort Memory: 314kB
Worker 1: Sort Method: top-N heapsort Memory: 299kB
-> Parallel Seq Scan on companies_company (cost=0.00..35488.85 rows=118785 width=1223) (actual time=0.278..756.498 rows=95028 loops=3)
Planning Time: 0.444 ms
Execution Time: 867.759 ms
(12 rows)
# explain analyze select * from company order by current asc nulls last limit 100;
QUERY PLAN
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Limit (cost=0.42..49.79 rows=100 width=1223) (actual time=1.700..13.268 rows=100 loops=1)
-> Index Scan Backward using companies_c_current_f2c815_idx on companies_company (cost=0.42..140727.06 rows=285084 width=1223) (actual time=1.698..13.244 rows=100 loops=1)
Planning Time: 1.139 ms
Execution Time: 13.426 ms
(4 rows)
It seems clear from the above that the asc is using the index while the desc is not, which explains the time difference. My question is: why not? Is there a different way the index needs to be added to make sure it's used for both asc and desc? I originally tried adding it to the model field definition with db_index=True
but that yielded the same issue.
Upvotes: 2
Views: 584
Reputation: 246123
An index can be scanned in both directions, but it needs to be sorted exactly like the ORDER BY
clause it is intended by default. A plain index is sorted in ASC NULLS LAST
order, so it can support that order or the reverse, namely DESC NULLS FIRST
. To create an index that can support your ORDER BY
clause, use
CREATE INDEX ON companies_company (current ASC NULLS FIRST);
Upvotes: 1