我在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秒 所以这些是我的问题:
我认为查询会根据this自动使用主键作为索引。但USE INDEX (cid)
和NO INDEX
之间存在重大差异。有什么不同?另外,我如何明确地将主键作为索引?
如果NO INDEX
实际上没有使用主键作为索引,那么USE INDEX(PRIMARY)
会导致它与NO INDEX
具有相同的运行时间吗?
在仅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)
并使用主键作为索引的差异的原因,两者都具有相同的字段。
答案 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