Search code examples
djangopostgresqlindexingdjango-querysetfull-text-indexing

Fulltext indexes vs pattern_ops indexes


I am using django, and all of my queries are created by django, so i have no handwritten queries...

I have a table of BillRecords, which has a field subscriberno . In my django filters, i use a filtering query like:

BillRecords.objects.filter(subscriberno__icontains='123456')

Since the subscriberno the customer said might be quite shortened version of the real number...

That filter outputs a query like:

SELECT "subscriberno" FROM "BillRecords" WHERE UPPER("subscriberno"::text) LIKE UPPER(E'%123456%');

subscriberno is a char field because some numbers contains alphas and some special chars.

On my database, i have two indexes for that column, created by my colleagues.

"BillRecords_subscriberno" btree (subscriberno)
"BillRecords_fsubscriberno_like" btree (subscriberno varchar_pattern_ops)

I am wondering using two indexes for a such query is logical. Since all of our django filter uses icontains and that supposed to be create queries like i write above.

Postgres analyse of the query is as follows:

Seq Scan on BillRecords  (cost=0.00..159782.40 rows=370 width=15) (actual time=579.637..3705.079 rows=10 loops=1)
Filter: (upper((subscriberno)::text) ~~ '%123456%'::text)
Total runtime: 3705.106 ms
(3 rows)

So, as far as i see, no index is used. Since index usega have costs in data insertion and update, having two indexes with no usage (as far as i can see from this analyse) seemed me not logical.

Is there any channce for django to output different queries for a similar icontanis filter? Or my indexes are totally useless?


Solution

  • You cannot use an index on an unanchored like statement.

    upper(foo) like 'bar%' -- index on upper(foo)
    upper(foo) like '%bar' -- no index
    reverse(upper(foo)) like 'rab%' -- index on reverse(upper(foo))
    upper(foo) like '%bar%' -- no index
    

    But you might find the trigram contrib of use, if you want to reduce the search window.