3

我有一个拒绝使用索引的表,它总是使用文件排序。

表格是:

创建表`文章`(
  `ID` int(11) NOT NULL AUTO_INCREMENT,
  `Category_ID` int(11) 默认 NULL,
  `子类别` int(11) 默认为空,
  `CTimestamp` 时间戳 NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `Publish` tinyint(4) 默认为空,
  `Administrator_ID` int(11) 默认为 NULL,
  `位置` tinyint(4)默认'0',
  主键(`ID`),
  KEY `Subcategory` (`Subcategory`,`Position`,`CTimestamp`,`Publish`),
  KEY `Category_ID` (`Category_ID`,`CTimestamp`,`Publish`),
  KEY `Position` (`Position`,`Category_ID`,`Publish`),
  KEY `CTimestamp` (`CTimestamp`),
  约束`article_ibfk_1`外键(`Category_ID`)参考`category`(`ID`)
) 引擎=InnoDB AUTO_INCREMENT=94290 默认字符集=utf8

查询是:

SELECT * FROM article ORDER BY `CTimestamp`;

解释是:

+----+-------------+---------+------+------------- --+------+----------+------+-------+--------------- -+
| 编号 | 选择类型 | 表| 类型 | 可能的键 | 关键 | key_len | 参考 | 行 | 额外 |
+----+-------------+---------+------+------------- --+------+----------+------+-------+--------------- -+
| 1 | 简单 | 文章 | 全部 | 空 | 空 | 空 | 空 | 63568 | 使用文件排序 |
+----+-------------+---------+------+------------- --+------+----------+------+-------+--------------- -+

当我删除“ORDER BY”时,一切正常。所有其他索引(子类别、位置等)在其他查询中运行良好。不幸的是,即使使用我的简单选择查询,也拒绝使用时间戳。我确定我在这里遗漏了一些重要的东西。

如何让 MySQL 使用时间戳索引?

谢谢你。

4

2 回答 2

5

在这种情况下,MySQL 没有使用您的索引进行排序,这是一件好事。为什么?您的表仅包含 64k 行,平均行宽约为 26 字节(如果我添加了正确的列大小),因此磁盘上的总表大小应约为 2MB。只需将 2MB 的数据从磁盘读取到内存中(可能只需 1-2 次磁盘操作或查找)然后在内存中执行文件排序(可能是快速排序的变体),这非常便宜。

如果 MySQL 按索引顺序进行检索,它必须执行 64000 次磁盘查找操作,一条又一条记录!它会非常非常缓慢。

当您可以使用索引快速跳转到大文件中的已知位置并仅读取少量数据时,索引可能会很好,例如在 WHERE 子句中。但是,在这种情况下,这不是一个好主意——而且 MySQL 并不愚蠢!

如果您的表非常大(超过 RAM 大小),那么 MySQL 肯定会开始使用您的索引 - 这也是一件好事。

于 2012-10-25T08:06:04.343 回答
0

好吧,您总是可以提示索引。将您的查询更改为

SELECT * FROM article use index (CTimestamp);

这会强制 MySQL 使用索引进行查询。解释:

1, 'SIMPLE', 'article', 'ALL', '', '', '', '', 1, 100.00, ''

看不到文件排序,并且由于使用的索引是 CTimestamp,因此应相应地对结果进行排序。

或者,您可以保留您的 order by 子句,但强制使用索引:

SELECT * FROM article force index (CTimestamp) order by CTimestamp;

不过,这个问题仍然很奇怪。您是否考虑将其发布到官方 MySQL 帮助论坛?

编辑:你似乎相处得很好
编辑:强制索引似乎效果很好

于 2012-10-25T07:57:39.307 回答