【问题标题】:Indices and using primary keys as indices in MySQLMySQL 中的索引和使用主键作为索引
【发布时间】:2012-04-29 14:57:23
【问题描述】:

我在 InnoDB 引擎上有一个表 Assets,定义为:

CREATE TABLE Assets (
qid SMALLINT(5) NOT NULL,
sid BIGINT(20) NOT NULL AUTO_INCREMENT,
...
PRIMARY KEY (sid,qid),
KEY sid (sid)
);

我正在运行以下查询:

SELECT COUNT(*) FROM Assets WHERE sid>10000;

在我的机器上,这个查询大约需要 30 秒,表中有 200 万个条目。现在,如果我修改查询以使用索引,结果会有很大差异:

SELECT COUNT(*) FROM Assets USE INDEX(<index>) WHERE sid>10000;
  • NO INDEX:没有明确的USE INDEX,即第一个SELECT查询:30秒
  • KEY sid (sid):1.5 秒
  • KEY cid (sid,qid):1.5 秒
  • PRIMARY :我在查询中使用了USE INDEX(PRIMARY)。 : 30 秒

所以这些是我的问题:

  1. 我认为查询会自动使用主键作为索引,基于this。然而USE INDEX (cid) 和NO INDEX 之间还是有很大区别的。有什么不同?另外,我如何明确地将主键作为索引?

  2. 如果NO INDEX实际上并没有使用主键作为索引,那么USE INDEX(PRIMARY)做了什么导致它与NO INDEX具有相同的运行时间?

  3. 在仅按 sid 过滤的查询中,USE INDEX(sid) 和 USE INDEX(cid) 之间是否存在差异(不仅仅是性能方面的差异)?

请原谅这篇长文,但我想让它公开讨论。


好的,这是我目前发现的:

首先,有人告诉我密钥设置应该是:PRIMARY KEY(qid,sid), KEY(sid) 或 PRIMARY KEY(sid,qid), KEY(qid)。我真的不明白其中的区别。如果有人这样做,请告诉我。

其次,KEY sid(sid) 引用的索引页比较大的键少得多,因此它往往更快。至于使用 PRIMARY KEY 作为索引和正确的 KEY(即使它们使用相同的字段)之间的区别,我被告知它是这样的:

主键用主键的字段索引整个表数据。这意味着 PRIMARY KEY 和数据存储在一起。因此使用 PRIMARY KEY 的查询将不得不遍历整个表数据,即使是索引也会在大型不可缓存表上陷入困境。

使用离散键,行数可能相同,但扫描的索引(由指示的字段组成)要小得多,它会命中较少数量的磁盘块,因此运行速度要快得多。我假设这也是使用USE INDEX(cid) 和使用主键作为索引不同的原因,两者具有相同的字段。

【问题讨论】:

  • 附注:如果你有PRIMARY KEY (sid,qid),那么KEY sid (sid) 没有意义
  • PS:请给SELECT COUNT(*) FROM Assets WHERE sid&gt;10000写EXPLAIN
  • 总共 2M 行中有多少行带有 sid&gt;10000?如果它超过〜30%,那么mysql认为fullscan更便宜。这就是强制索引有帮助的原因
  • 是的,超过 30%。如果我将其设置在中间标记(100 万)左右,则查询大约需要 20 秒。
  • 如果您将结果集(通过在sid&gt;10000 中指定更大的值)减少到大约 25-30% - 它是否会在没有提示的情况下更快地工作?

标签: mysql indexing primary-key


【解决方案1】:

根据我的经验,拥有一个索引是另一个索引的子集往往会减慢速度。但您的里程可能会有所不同,因为在处理索引时您必须考虑很多事情..

例如,如果您经常阅读并且很少更改数据,那么拥有许多索引可能会帮助您更多;如果您的操作涉及大量插入/更新/删除,那么索引过多可能会减慢您的速度。

如果您的主键是 (sid, qid),那么我认为不适合拥有另一个键 (sid),引擎可能会将其检索为 PK 的前缀。 如果我要利用它,我宁愿在 qid 上添加一个索引 - 也就是说,如果我对该字段有一些查询过滤或排序,或者如果我在该字段上有一些 JOIN..

根据主键上字段的顺序,我通常会尝试确定它们在查询中的使用方式:如果我的所有查询都使用 sid,而有些查询同时使用 sid 和 qid,则选择 (sid,启德);如果他们都使用qid并且只有一些也使用sid,则选择(qid, sid);如果他们碰巧使用 sid 或 qid,则有一个 PK (sid, qid) 和另一个密钥 (qid),以便使用这两个字段的查询将使用您的 PK,仅使用 sid 的查询也会发生同样的情况,最后仅使用 qid 的用户将使用 (qid) 键。

我只是对 use(primary) 强制 mysql 不使用索引有点困惑,但这可能是与您的 mysql 版本相关的东西(错误?)..

您可以在此处找到有关索引提示的一些提示: http://dev.mysql.com/doc/refman/5.1/en/index-hints.html

一般来说尽量不要过多地使用索引提示,优化器通常会做得很好!如果没有,可能是某个地方存在缺陷,或者它只是认为表扫描更快,因为索引的选择性不够。

此外,您有时可能需要优化表来刷新索引统计信息。但由于您使用的是 InnoDB,因此可能并非如此...

HTH

【讨论】:

  • 另见link关于mysql查询优化;在我看来,这很清楚,写得很好
猜你喜欢
  • 2013-08-22
  • 1970-01-01
  • 2018-10-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多