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查询几十万条数据很慢 如何解决?
MySQL ---- 索引类型 & 使用规则 & 回表覆盖索引 & 设计索引考虑因素