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

Len*_*ena 5 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'),
        )
Run Code Online (Sandbox Code Playgroud)

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

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

现在,在我的情况下,结果必须按顺序排序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 
Run Code Online (Sandbox Code Playgroud)

有完整的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 
Run Code Online (Sandbox Code Playgroud)

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

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`),
Run Code Online (Sandbox Code Playgroud)

因此,似乎正确的索引甚至不是可能的键.

e4c*_*4c5 7

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

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

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

class Meta:
    index_together = (
        ('user', 'time','action'),
    )
Run Code Online (Sandbox Code Playgroud)

这里的区别在于字段的顺序.这很重要:

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


auv*_*ipy 6

对于新版本的 Django,建议使用 Index 类元而不是 index_together 元选项。

from django.db import models

class Customer(models.Model):
    first_name = models.CharField(max_length=100)
    last_name = models.CharField(max_length=100)

    class Meta:
        indexes = [
            models.Index(fields=['last_name', 'first_name']),
            models.Index(fields=['first_name'], name='first_name_idx'),
        ]
Run Code Online (Sandbox Code Playgroud)

https://docs.djangoproject.com/en/3.2/ref/models/options/#unique-together https://docs.djangoproject.com/en/3.2/ref/models/options/#index-together