使用带IN子句的索引和按主键排序

时间:2016-09-07 10:33:46

标签: mysql indexing

我使用MySQL遇到以下任务的问题。我有一个表记录(id,企业,部门,状态)。其中id是主键,enterprise和department是外键,status是整数值(0-CREATED,1-APPROVED,2-REJECTED)。

现在,通常应用程序需要为具体的企业,部门和状态过滤一些东西:

SELECT * FROM Records WHERE status = 0 AND enterprise = 11 AND department = 21
    ORDER BY id desc LIMIT 0,10;

订单依据是必需的,因为我必须向用户提供最新记录。对于这个查询,我创建了一个索引(企业,部门,状态),一切正常。但是,对于某些特权用户,应省略状态:

SELECT * FROM Records WHERE enterprise = 11 AND department = 21
    ORDER BY id desc LIMIT 0,10;

这显然打破了索引 - 它仍然适合过滤,但不适合排序。所以我该怎么做?我不想创建一个单独的索引(企业,部门),所以如果我修改这样的查询怎么办:

SELECT * FROM Records WHERE enterprise = 11 AND department = 21
      AND status IN (0,1,2)
    ORDER BY id desc LIMIT 0,10;

MySQL肯定会立即使用索引,因为它提供了状态值,但主键排序的速度有多快?是否会将每个状态的最近10个值合并,然后合并它们,或者它是否会首先将每个状态的ID合并在一起,并且只有在此之后才会占用前10个(这样我的猜测会慢得多)。 / p>

1 个答案:

答案 0 :(得分:0)

所有查询都将受益于一个复合查询:

INDEX(enterprise, department, status, id)

enterprisedepartment可以互换,但请按顺序保留其余列。

第一个查询将对WHEREORDER BY使用该索引,从而能够在不扫描表格或进行排序的情况下找到10行。

第二个查询缺少status,所以我的索引不够完美。这会更好:

INDEX(enterprise, department, id)

此时,它的工作方式如上。 (注意:如果表是InnoDB,那么这个3列索引与你的2列INDEX(enterprise, department)相同 - 默认包含PK。)

由于IN,第三个查询变得更加严格。不过,我的4列指数几乎是最好的。它将使用前3列,但无法执行ORDER BY id,因此不会使用id。而且它无法满足LIMIT。因此,EXPLAIN会说Using temporary and/or Using filesort。别担心,性能应该还不错。

我的第二个索引不如第三个查询好。

查看我的Index Cookbook

"按ID排序的速度有多快"?这取决于两件事。

  • 是否可以避免排序(见上文);
  • 查询中没有 LIMIT;
  • 的行数
  • 您是否选择了TEXT列。

我小心翼翼地说INDEX是否一直用于ORDER BY,在这种情况下没有排序,LIMIT被折入。否则,< em> all 将行(在过滤后)写入临时表,排序,然后剥离10行。

&#34;临时表&#34;我刚才提到的是各种复杂查询所必需的,例如那些带有子查询的查询GROUP BYORDER BY。 (正如我已经暗示的那样,有时可以避免临时表。)无论如何,临时表有两种形式:MEMORYMyISAMMEMORY是有利的,因为它更快。但是,TEXT(以及其他一些事情)会阻止其使用。

如果使用MEMORY,则Using filesort是用词不当 - 排序实际上是内存排序,因此非常快。对于10行(甚至100行),所花费的时间是微不足道的。