14

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

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. 我认为一个查询会自动使用主键作为它的索引,基于这个USE INDEX (cid)然而和之间有一个主要区别NO INDEX。有什么不同?另外,我如何明确地将主键作为索引?

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

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

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


好的,这是我到目前为止发现的:

首先,我被告知密钥设置应该是: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)和使用主键作为索引不同的原因,两者都具有相同的字段。

4

1 回答 1

1

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

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

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

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

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

在这里你可以找到一些关于索引提示的提示:http: //dev.mysql.com/doc/refman/5.1/en/index-hints.html

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

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

高温高压

于 2012-05-08T00:19:48.947 回答