Steps to reproduce and explanation:
- Create a charfield or a textfield
- Query it using icontains, istartswith or iendswith
- Resulting query looks something like (pun unintended) …
UPPER(field_name) LIKE UPPER(value)
← this can’t make use of any Gin indexes on that field - On the other hand, if it compiled to
field_name ILIKE value
it could and would be a great performance boost!
For more details (and as a starting point towards a fix) check operators
and pattern_ops
fields of the class DatabaseWrapper
in django/db/backends/postgresql/base.py
.
My initial impression is that they should be changed to:
{
"exact": "= %s",
"iexact": "= UPPER(%s)",
"contains": "LIKE %s",
"icontains": "ILIKE %s",
"regex": "~ %s",
"iregex": "~* %s",
"gt": "> %s",
"gte": ">= %s",
"lt": "< %s",
"lte": "<= %s",
"startswith": "LIKE %s",
"endswith": "LIKE %s",
"istartswith": "ILIKE %s",
"iendswith": "ILIKE %s",
}
and
{
"contains": "LIKE '%%' || {} || '%%'",
"icontains": "ILIKE '%%' || {} || '%%'",
"startswith": "LIKE {} || '%%'",
"istartswith": "ILIKE {} || '%%'",
"endswith": "LIKE '%%' || {}",
"iendswith": "ILIKE '%%' || {}",
}
respectively.
I’d assume this was either overlooked or intentionally left less-performant for backward-compatibility with previous versions of postgres or something like that. I’m posting this in hopes that it’s the former and not the latter