Django 索引未考虑现有表

Posted

技术标签:

【中文标题】Django 索引未考虑现有表【英文标题】:Django Index not took in account for existing table 【发布时间】:2020-08-18 06:07:08 【问题描述】:

我将现有的 mysql 表与 Django Rest Framework 一起使用。 在一个大的 mysql 表上,phpmysql 中的一个简单的选择请求在没有索引的情况下需要 10 秒。使用字段上的索引,需要 3 毫秒。所以我用 phpMysql 手动添加了索引,但是 Django 仍然需要 10 秒来执行请求并且看不到新索引。 我在 models.py 的字段中添加了db_index=True。但是make migration在我已有的模型上没有看到任何更新,速度还是10s。 (由 django 创建的表的任何更新都非常有效) 我决定用 phpmysql 手动删除我的索引,然后我自己创建了一个 0002_initial.py 文件,代码如下:

从 django.db 导入迁移、模型

类迁移(migrations.Migration):

dependencies = [
    ('tutorials', '0001_initial'), # or last mig
]

operations = [
    migrations.RunSQL("CREATE INDEX idx_last_name ON crm_users (us_last_name(64))")
]

我运行了迁移,django 在表中创建了索引。但是 Django 仍然需要 10s 对索引字段执行一次选择,并且不使用 mysql 索引。

我的问题:我在哪里以及如何告诉 django 使用不是由 Django 创建的现有表的索引?非常感谢!

【问题讨论】:

您不必这样做,通常这是由数据库本身完成的。您确定列上有索引吗?如果你执行DESC crm_users怎么办?你看到索引了吗? 当我执行 DESC crm_users 时,我看到了由 RunSQL 创建的索引。该索引在 phpmysql 中运行良好 您运行的是什么查询。如果你获取 all user 对象,那么它确实需要大约 10 秒,所以我怀疑查询有问题。 profils = profils.filter(us_last_name__icontains=name).using('crm') 然后我使用 url localhost:8080/api/profils?name=XXXX 访问,而 XXXX 只得到 8 个结果 @PatriceG: 但__icontains 可以使用索引,即使它是前缀树或后缀树。对于完整匹配,您可以使用profils.filter(us_last_name=name),但对于子字符串,必须逐行检查。 【参考方案1】:

您的查询:

profils = profils.filter(us_last_name__icontains=name).using('crm')

可以使用索引

确实,您在这里的目标是执行 substring 查找。例如,如果列包含 'foobarqux''bar' 将匹配。没有支持这一点的索引。例如,前缀树或后缀树可以分别匹配以给定字符串开头或结尾的字符串。

对于子字符串,这不是一个选项。可以定义某些复杂的索引,但这些索引在插入、更新和删除元素时需要大量开销,并且与存储的实际数据相比需要相对较大的内存。因此,数据库不太可能实现这些。理想的索引通常在搜索 更新方面都很快,并且与实际表相比通常会消耗少量内存,因为否则加载索引将花费大量时间。

可以使用索引的查询是这样的:

profils = profils.filter(<b>us_last_name=name</b>).using('crm')

但是当然你会执行完全匹配。

这与 Django 无关。如果您尝试在数据库 shell 中执行如下查询:

SELECT * FROM crm_users WHERE <b>us_last_name LIKE '%bar%'</b>

这将花费大约相同的时间。

在搜索引擎中,人们经常通过收集n-grams [wiki] 来“准备”数据库中的数据,这样就可以快速过滤输入。像 django-haystack [readthedocs] 这样的包可能会对此有所帮助。

【讨论】:

你完全正确!由于 __icontains,没有考虑索引。所以我改变了 __istartswith :profils = profils.filter(us_last_name__istartswith=name) 现在索引工作了,我所有的剩余执行时间都是 200 毫秒,它可以适应自动完成,我正在创建,在姓氏字段。非常感谢威廉的帮助!

以上是关于Django 索引未考虑现有表的主要内容,如果未能解决你的问题,请参考以下文章

mysql+springboot+jpa查询几十万条数据很慢 如何解决?

Symfony 属性路由未考虑在内

MySQL ---- 索引类型 & 使用规则 & 回表覆盖索引 & 设计索引考虑因素

MySQL ---- 索引类型 & 使用规则 & 回表覆盖索引 & 设计索引考虑因素

sqlserver分区表索引

如何让mysql速度更快的响应?如何提高读取和查询速度