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

Bil*_*one 12 database django indexing model django-models

我正在使用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)
Run Code Online (Sandbox Code Playgroud)

然后我运行查询查询,以term不区分大小写的方式找到正确匹配的相应行.例如:

MetadataTerms.objects.filter(term__iexact=search_string, size=3)
Run Code Online (Sandbox Code Playgroud)

这个查找子句转换为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 );
Run Code Online (Sandbox Code Playgroud)

在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))
Run Code Online (Sandbox Code Playgroud)

由于该term字段未编制索引,并且未按案例规范化方式编制索引,因此上述查询需要跨所有数据库行执行慢速Seq [uential] Scan操作.

然后我插入一个简单的case-normalized索引,例如:

 CREATE INDEX size_term_insisitive_idx ON app_metadataterms (upper(term), size);
Run Code Online (Sandbox Code Playgroud)

上面的查询现在运行速度提高了大约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))
Run Code Online (Sandbox Code Playgroud)

我的问题是:如何在Django模型管理命令中注入高级DB索引的创建?

Max*_*ysh 12

Django 1.11(2.0也应该没问题)+ PostgreSQL:

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

    python3 manage.py makemigrations appName --empty
    
    Run Code Online (Sandbox Code Playgroud)
  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";'
            ),
        ]
    
    Run Code Online (Sandbox Code Playgroud)


Tom*_*cik 10

从3.2开始,您可以添加*expressionsIndex.

如果你想创建

 CREATE INDEX size_term_insisitive_idx ON app_metadataterms (upper(term), size);
Run Code Online (Sandbox Code Playgroud)

类似的东西应该有效。

from django.db.models import Index
from django.db.models.functions import Upper


class MetadataTerms(models.Model):
    term = models.CharField(max_length=200)
    size = models.IntegerField(default=0)
    validity = models.IntegerField(default=0, choices=TERM_VALIDITY_CHOICES)
    
    class Meta:
        indexes = [
            Index(
                Upper('term'), 'size',
                name='size_term_insisitive_idx',
            ),
        ]

Run Code Online (Sandbox Code Playgroud)


Dan*_*cci 2

要将自定义 sql 注入 django 模型管理命令,请查看django-admin.py sqlcustom

\n\n

您可以将包含创建索引的 sql 文件放入<app_name>/sql/<model_name>.sql

\n\n

从应用它们时的文档来看:

\n\n
\n

执行完所有 models\xe2\x80\x99 表创建语句后,SQL 文件将直接通过管道传输到数据库中。使用此 SQL 挂钩进行任何表修改,或将任何 SQL 函数插入数据库。

\n
\n\n

您可以通过运行查看每个应用程序的自定义 sqlmanage.py sqlcustom <app_name>

\n