database - 如何在 Django 中创建不区分大小写的数据库索引?

标签 database django django-models model indexing

我正在使用 Django 创建一些数据库表,如下所示:

class MetadataTerms(models.Model):
    term = models.CharField(max_length=200)
    size = models.IntegerField(default=0)
    validity = models.IntegerField(default=0, choices=TERM_VALIDITY_CHOICES)

然后我运行查找查询以找到具有正确 term 的适当行,以不区分大小写的方式匹配。例如:

MetadataTerms.objects.filter(term__iexact=search_string, size=3)

此查找子句在 SQL 中转换为类似这样的内容:

 SELECT "app_metadataterms"."id", "app_metadataterms"."term", "app_metadataterms"."size" FROM "app_metadataterms" WHERE (UPPER("app_metadataterms"."term"::text) = UPPER('Jack Nicklaus survives')  AND "app_metadataterms"."size" = 3 );

在 Postgres 上,我可以对上面的内容执行一个 EXPLAIN 查询,我得到这个查询计划:

                                    QUERY PLAN
-----------------------------------------------------------------------------------
 Seq Scan on app_metadataterms  (cost=0.00..1233.01 rows=118 width=21)
   Filter: ((size = 3) AND (upper((term)::text) = 'JACK NICKLAUS SURVIVES'::text))

因为 term 字段没有索引,也没有以大小写规范化的方式索引,所以上面的查询需要对所有数据库行执行缓慢的 Seq[uential] 扫描操作。

然后我插入一个简单的大小写标准化索引,例如:

 CREATE INDEX size_term_insisitive_idx ON app_metadataterms (upper(term), size);

上面的查询现在运行速度快了大约 6 倍:

                                         QUERY PLAN
---------------------------------------------------------------------------------------------
 Bitmap Heap Scan on app_metadataterms  (cost=5.54..265.15 rows=125 width=21)
   Recheck Cond: ((upper((term)::text) = 'JACK NICKLAUS SURVIVES'::text) AND (size = 3))
   ->  Bitmap Index Scan on size_term_insisitive_idx  (cost=0.00..5.51 rows=125 width=0)
         Index Cond: ((upper((term)::text) = 'JACK NICKLAUS SURVIVES'::text) AND (size = 3))

我的问题是:如何将高级数据库索引的创建注入(inject)到 Django 模型管理命令中?

最佳答案

Django 1.11(2.0 应该也可以)+ PostgreSQL:

  1. 首先,创建一个空迁移:

    python3 manage.py makemigrations appName --empty
    
  2. Django 使用 UPPER 进行不精确查找。因此,创建一个迁移以添加一个 UPPER(yourField) 索引:

    # -*- coding: utf-8 -*-
    # Generated by Django 1.11.7 on 2017-12-14 23:11
    from __future__ import unicode_literals
    
    
    from django.db import migrations
    
    class Migration(migrations.Migration):
    
        dependencies = [
            ('stats', '0027_remove_siteuser_is_admin'),
        ]
    
        operations = [
            migrations.RunSQL(
                sql=r'CREATE INDEX "stats_siteuser_upper_idx" ON "stats_siteuser" (UPPER("email"));',
                reverse_sql=r'DROP INDEX "stats_siteuser_upper_idx";'
            ),
        ]
    

关于database - 如何在 Django 中创建不区分大小写的数据库索引?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18597986/

相关文章:

Django 模型管理器.py 和模型.py

mysql - 在数据库中存储动态字段的最佳实践

database - 数据如何物理存储在 Bigtable 中

android - 如何在 Android 中立即从服务器获取新数据?

python - 不在 ListView 中时,django rest framework 添加字段

python - 从 Django 缓存中删除所有匹配的键

django - 重写模型中的 get() 方法

SQL 查询从列中提取文本并将其存储到同一记录中的不同列

python - Django 模型字段 : reference to self on default keyword

python - Rake:Django 中的任务等价物