如何使用Django的index_together与filter和order_by进行查询?

时间:2015-10-17 13:03:37

标签: python mysql django indexing

我在为查询构建正确索引时遇到问题 我有这样的模型:

from django.db import models  

class Record(models.Model):
    user = models.ForeignKey(User, db_index=True, related_name='records')
    action = models.ForeignKey(Action, db_index=True)
    time = models.DateTimeField(db_index=True, default=timezone.now)

    class Meta:
        index_together = (
            ('user', 'time'),
            ('action', 'user', 'time'),
        )

如您所见,此模型有两个自定义索引。

如果我想获取与time过滤的特定用户相关的所有记录,我会使用此查询:user.records.filter(time__gt=some_moment)。它工作正常并使用第一个自定义索引(根据Django Debug Toolbar)。

现在,在我的情况下,结果必须按action排序。我使用此查询:user.records.filter(time__gt=some_moment).order_by('action')
但是,尽管存在适当的索引,但不使用它。

我做错了什么?如何为此查询构建正确的索引?
Django版本= 1.8.4,应用了所有迁移,数据库后端= mysql。

UPD:有我的疑问:

SELECT *** FROM `appname_record`
  WHERE (`appname_record`.`user_id` = 1896158 AND 
  `appname_record`.`time` > '2015-10-19 06:39:30.992790') 
  ORDER BY `appname_record`.`action_id` ASC 

有完整的django工具栏说明:

ID: 1  
SELECT_TYPE: SIMPLE  
TABLE: appname_record  
TYPE: ALL  
POSSIBLE_KEYS: 
   appname_record_user_id_3214bab8a46891cc_idx, appname_record_07cc694b  
KEY: None  
KEY_LEN: None  
REF: None  
ROWS: 240  
EXTRA: Using where; Using filesort 

有关键的mysql show create table appname_record;部分:

PRIMARY KEY (`id`),
KEY `appname_record_action_id_3e42ba1d5288899c_idx` (`action_id`, `user_id`,`time`),
KEY `appname_record_user_id_3214bab8a46891cc_idx` (`user_id`,`time`),
KEY `appname_record_07cc694b` (`time`),

所以看起来正确的指数即使在可能的键中也是如此。

3 个答案:

答案 0 :(得分:5)

如果查询根本不使用任何索引,那通常是因为表中没有足够的数据使索引真正有用。然而,有500条记录,指数很有可能发挥作用。

在您使用的查询中,appname_record_user_id_3214bab8a46891cc_idx确实可能是候选人,但仍未使用。为什么?因为你的查询显然会导致数据库看到大约一半的表,因为这样的索引无法加快速度。

你似乎在放弃一个索引的正确轨道上。两个很多类似的索引也不是很有用。我会尝试这个索引:

class Meta:
    index_together = (
        ('user', 'time','action'),
    )

这里的区别在于字段的顺序。这是important

  

MySQL可以对测试所有内容的查询使用多列索引   索引中的列,或仅测试第一列的查询,   前两列,前三列,依此类推。如果你指定   索引定义中的列顺序正确,单个   复合索引可以加快几种查询的速度   表

答案 1 :(得分:4)

我找到了解决方案,它并不优雅,但它对我有用。由于我无法构建任何将使用3列索引的查询,因此我jush删除了2列,因此现在我的两个查询都使用3列。不知道为什么之前被忽略了。也许,一些复杂的mysql优化。

答案 2 :(得分:0)