16

我正在使用 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 );

EXPLAIN在 Postgres 上,我可以对上述内容执行查询,并得到以下查询计划:

                                    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] Scan 操作。

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

 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))

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

4

4 回答 4

15

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

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

    python3 manage.py makemigrations appName --empty
    
  2. DjangoUPPER用于不精确的查找。所以创建一个添加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";'
            ),
        ]
    
于 2017-12-14T23:45:51.063 回答
4

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

如果你想创建

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

类似的东西应该工作。

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',
            ),
        ]

于 2021-04-06T09:52:36.970 回答
3

在 Django 1.9(尚未发布)之前,您可以使用 sqlcustom 命令,但如果您查看即将发布的 1.9 的开发文档,您会发现该命令明显缺失。

所以:

  • 在 <= 1.8.* 中,@daniel-rucci 的回答适用。将您的 SQL 放在 SQL 目录中,它将以不确定的顺序运行。
  • 在 >= 1.9 中,您需要开始使用新的RunSQL 函数作为迁移的一部分。如果您愿意,您也可以在 1.7 或 1.8 中执行此操作。
于 2015-08-26T14:10:31.323 回答
2

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

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

从应用它们时的文档中:

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

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

于 2014-01-22T17:28:34.717 回答