指数并使用主键作为MySQL中的索引

时间:2012-04-18 08:01:07

标签: mysql indexing primary-key

我在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秒,表中有2百万条记录。现在,如果我修改查询以使用索引,结果差异很大:

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. 在仅USE INDEX(sid)过滤的查询中,USE INDEX(cid)sid之间是否存在差异(不仅仅是绩效明智)?

  4. 原谅长篇文章,但我想让它开放讨论。


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

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

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

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

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

1 个答案:

答案 0 :(得分: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版本相关的东西(一个bug?)..

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

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

此外,您有时可能需要使用表优化来刷新索引统计信息..但由于您使用的是InnoDB,因此情况可能不是这样......

HTH

相关问题