mysql - 使用带 IN 子句的索引并按主键排序

标签 mysql indexing

我在使用 MySQL 执行以下任务时遇到问题。我有一个表记录(id,企业,部门,状态)。其中 id 是主键,企业和部门是外键,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;

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

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 个值(我猜这样会慢得多)。

最佳答案

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

INDEX(enterprise, department, status, id)

企业部门 可以交换,但保持其余列的顺序。

第一个查询将在 WHEREORDER BY 中使用该索引,从而无需扫描表或进行排序即可找到 10 行。

第二个查询缺少status,因此我的索引不太完美。这样会更好:

INDEX(enterprise, department, id)

此时,它的工作原理就像上面一样。 (注意:如果表是 InnoDB,那么这个 3 列索引与您的 2 列 INDEX(enterprise, Department) 相同 - PK 是默默包含在内的。)

由于 IN,第三个查询变得更加危险。尽管如此,我的 4 列索引几乎是最好的。它将使用前 3 列,但无法执行 ORDER BY id,因此它不会使用 id。并且它无法达到LIMIT。因此,EXPLAIN 将显示使用临时和/或使用文件排序。别担心,性能应该还是不错的。

我的第二个索引对于第三个查询来说不太好。

查看我的Index Cookbook .

“按 id 排序的速度有多快”?这取决于两件事。

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

我很小心地说了INDEX是否一直使用到ORDER BY,在这种情况下没有排序,以及LIMIT 被折叠起来。否则,所有 行(过滤后)都将写入临时表并排序,然后 10 行被剥离。

我刚才提到的“临时表”对于各种复杂的查询是必需的,例如带有子查询、GROUP BYORDER BY的查询。 (正如我已经暗示的,有时可以避免使用临时表。)无论如何,临时表有两种类型:MEMORYMyISAMMEMORY 是有利的,因为它更快。然而,TEXT(以及其他一些东西)阻止了它的使用。

如果使用MEMORY,那么使用文件排序是一个用词不当——排序实际上是内存中排序,因此速度相当快。对于 10 行(甚至 100 行),所花费的时间可以忽略不计。

关于mysql - 使用带 IN 子句的索引并按主键排序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39367529/

相关文章:

mysql - 重新安装 Wamp 时恢复 MySQL 数据库

indexing - 新内容怎么可能在创建几分钟后就出现在谷歌搜索结果中?

sql - 如何有效地按子查询的结果进行排序?

javascript - JavaScript 如何用数组解释索引数组?

android - 删除索引无法正常工作的SQlite Android

python - 在 numpy 中使用重复索引时如何指定列 [与 np.add.at() 一起使用]

javascript - 如何使用 Sequelize.js 解析复杂的查询操作?

php - 当我导出我的表时,仍未完成停止

mysql - 在 debian 上执行 mysql 查询时出错

php - mySQL按一定的ID排列。缺少一行数据