索引类便于创建数据库索引。它们可以使用 Meta.indexes
选项来添加。本文档解释了 Index
的 API 引用,其中包括 index options 。
引用内置索引
索引是在 django.db.models.indexes
中定义的,但为了方便,它们被导入到 django.db.models
中。标准的惯例是使用 from django.db import models
并将索引称为 models. <IndexClass>
。
Index
选项
-
class
Index
(*expressions, fields=(), name=None, db_tablespace=None, opclasses=(), condition=None, include=None) 在数据库中创建一个索引(B 树)。
expressions
位置参数 *expressions
允许在表达式和数据库函数上创建函数索引。
例子:
Index(Lower('title').desc(), 'pub_date', name='lower_title_date_idx')
在 title
字段的小写字母上按降序创建索引,在 pub_date
字段上按默认升序创建索引。
另一个例子:
Index(F('height') * F('weight'), Round('weight'), name='calc_idx')
在字段 height
和 weight
相乘的结果上创建一个索引,weight
四舍五入为最接近的整数。
Index.name
在使用 *expressions
时是必需的。
Oracle 的限制
Oracle 要求索引中引用的函数被标记为 DETERMINISTIC
。Django 并不验证这一点,但 Oracle 会出错。这意味着诸如 Random()
这样的函数不被接受。
PostgreSQL 的限制
PostgreSQL 要求在索引中引用的函数和运算符被标记为 IMMUTABLE
。Django 并不验证这一点,但 PostgreSQL 会出错。这意味着诸如 Concat()
这样的函数不被接受。
MySQL 和 MariaDB
函数索引在 MySQL < 8.0.13 和 MariaDB 中被忽略,因为两者都不支持它们。
fields
需要索引字段的名称列表或元组。
默认情况下,索引是以每列的升序创建的。要为列定义一个降序索引,请在字段名前添加一个连字符。
For example Index(fields=['headline', '-pub_date'])
would create SQL with
(headline, pub_date DESC)
.
MySQL 和 MariaDB
Index ordering isn't supported on MySQL < 8.0.1 and MariaDB < 10.8. In that case, a descending index is created as a normal index.
name
索引的名称。如果没有提供 name
,Django 会自动生成一个名称。为了兼容不同的数据库,索引名不能超过 30 个字符,并且不应该以数字(0-9)或下划线(_)开头。
抽象基类中的部分索引
你必须始终为索引指定一个唯一的名称。因此,通常不能在抽象基类上指定部分索引,因为 Meta.indexes
选项是由子类继承的,每次的属性值(包括 name
)都完全相同。为了解决名称碰撞的问题,名称的一部分可以包含 '%(app_label)s'
和 '%(class)s'
,它们分别被具体模型的小写应用标签和类名所代替。例如 Index(field=['title'], name='%(app_label)s_%(class)s_title_index')
。
db_tablespace
该索引要使用的 数据库表空间 名称。对于单字段索引,如果没有提供 db_tablespace
,则在字段的 db_tablespace
中创建索引。
如果没有指定 Field.db_tablespace
(或者如果索引使用了多个字段),则在模型的 class Meta
里面的 db_tablespace
选项中指定的表空间创建索引。如果这两个表空间都没有设置,则在与表相同的表空间中创建索引。
参见
关于 PostgreSQL 特有的索引列表,请参见 django.contrib.postgres.indexes
。
opclasses
要为这个索引使用的 PostgreSQL 运算符类 名称。如果你需要一个自定义的操作类,你必须为索引中的每个字段提供一个操作类。
例如,GinIndex(name='json_index', fields=['jsonfield'], opclasses=['jsonb_path_ops'])
使用 jsonb_path_ops
在 jsonfield
上创建一个 gin 索引。
opclasses
对于 PostgreSQL 以外的数据库来说是被忽略的。
Index.name
在使用 opclasses
时需要。
condition
如果表非常大,而且你的查询主要针对行的子集,那么将索引限制在该子集上可能会很有用。将条件指定为 Q
。例如,condition=Q(pages__gt=400)
对超过 400 页的记录进行索引。
Index.name
在使用 condition
时需要。
PostgreSQL 的限制
PostgreSQL 要求条件中引用的函数必须标记为 IMMUTABLE。Django 不会验证这一点,但 PostgreSQL 会报错。这意味着诸如 日期函数 和 Concat
这样的函数不被接受。如果你把日期存储在 DateTimeField
中,与 datetime
对象进行比较时,可能需要提供 tzinfo
参数,否则比较的结果可能是一个可变的函数,因为 Django 对 lookups 进行了转换。
SQLite 的限制
SQLite 对如何构建部分索引 施加了限制 。
Oracle
Oracle 不支持部分索引。相反,部分索引可以通过使用函数索引和 Case
表达式来进行模拟。
MySQL 和 MariaDB
在 MySQL 和 MariaDB 中,condition
参数被忽略,因为它们都不支持条件索引。
include
一个包含在覆盖索引中作为非键列的字段名称的列表或元组。这允许仅索引扫描,用于只选择包含的字段( include
)和只通过索引字段过滤的查询( fields
)。
例子:
Index(name='covering_index', fields=['headline'], include=['pub_date'])
将允许对 headline
进行过滤,同时选择 pub_date
,而只从索引中获取数据。
使用 include
将产生一个比使用多列索引更小的索引,但缺点是不能使用非键列进行排序或过滤。
include
对于 PostgreSQL 以外的数据库来说是被忽略的。
Index.name
在使用 include
时是必需的。
关于 covering indexes 的更多细节,请参阅 PostgreSQL 文档。
PostgreSQL 的限制
PostgreSQL < 12 only supports covering B-Tree indexes, PostgreSQL 12+ also
supports covering GiST indexes
, and PostgreSQL 14+ also
supports covering SP-GiST indexes
.
Support for covering SP-GiST indexes with PostgreSQL 14+ was added.
讨论区