2015-10-17 53 views
4

我有一个建立我的查询权索引的问题。
我有这样一个模型:如何使用Django的index_together同时用filter和order_by进行查询?

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

如此看来像权利指数甚至没有在可能的关键。

+1

虽然这看起来像一个django问题乍一看这真的是一个MySQL问题。你应该发布的是解释输出(可以从调试工具栏访问)。请更新帖子给出确切的模型(说这是这个,但一个外键,而不是混淆) – e4c5

+0

尝试更改列顺序为'('行动','用户','时间') – pista329

+0

@ e4c5对不起,使模型就像真正的一样。还添加了关于django解释和mysql'create table'查询的详细信息。 – Lena

回答

4

如果一个查询根本没有使用任何索引,那通常是因为表中没有足够的数据以使索引真正有用。但是,如果有500条记录,指数应该起作用的可能性很大。

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

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

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

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

MySQL能使用多列索引来测试索引的所有 列的查询或查询该测试只是第一列中, 前两列,前三列,等等。如果您在索引定义中以正确的顺序指定 列,则单个 组合索引可以在同一个 表上加速多种查询。

+0

感谢您的详细解释,现在我的“只是跌幅较小的指数”解决方案的影响似乎不再那么神奇 – Lena

+0

所以你自己的答案值得赞赏:-) – e4c5

3

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

相关问题