mysql不使用索引的所有列

时间:2014-06-10 18:07:44

标签: mysql

我有一个包含6列的索引。但MySQL永远不会使用整个索引。它只会使用前缀。

CREATE TABLE TestChannelData
(
    hostId          MEDIUMINT UNSIGNED NOT NULL,
    sessionId       MEDIUMINT UNSIGNED NOT NULL,
    sessionFragment TINYINT   UNSIGNED NOT NULL,
    id              INT       UNSIGNED NOT NULL,
    vcid            INT       UNSIGNED NULL,
    dssId           SMALLINT  UNSIGNED NOT NULL
) ENGINE=InnoDB CHARSET=latin1;

CREATE TABLE TestChannelValue
(
    hostId          MEDIUMINT UNSIGNED NOT NULL,
    sessionId       MEDIUMINT UNSIGNED NOT NULL,
    sessionFragment TINYINT   UNSIGNED NOT NULL,
    id              INT       UNSIGNED NOT NULL,
    ertCoarse       INT      UNSIGNED NOT NULL,
    ertFine         INT      UNSIGNED NOT NULL
) ENGINE=MyISAM CHARSET=latin1;

ALTER TABLE TestChannelValue
    ADD KEY reverseIndex(hostId, sessionId, sessionFragment, id),
    ADD KEY ertReverseIndex(ertCoarse, ertFine, hostId, sessionId, sessionFragment, id);

ALTER TABLE TestChannelValue
ADD KEY reverseErtIndex(hostId, sessionId, sessionFragment, id, ertCoarse, ertFine);

查询:

SELECT cv.sessionId, cv.hostId, cv.sessionFragment,
     cd.dssId, cd.vcid,
     cv.ertCoarse, cv.ertFine
     FROM TestChannelData AS cd
     STRAIGHT_JOIN TestChannelValue AS cv USE INDEX (ertReverseIndex)
     ON ((cv.sessionId       = cd.sessionId)       AND
         (cv.hostId          = cd.hostId)          AND
         (cv.sessionFragment = cd.sessionFragment) AND
         (cv.id              = cd.id))
     WHERE
        (
            (cv.ertCoarse > 0) AND
            ((cv.ertCoarse < 2000) OR ((cv.ertCoarse = 2000) AND (cv.ertFine = 0)))
        )

解释扩展显示使用了indes,但key_len只是8而不是所需的19.如果我强制索引而不是rev​​erseErtIndex,则key_ln为11。

如果我将ert列的比较替换为相等,则key_len为19。

为什么MySQL不会使用整个索引?

1 个答案:

答案 0 :(得分:0)

11的key_len(对于reverseErtIndex)对应于JOIN谓词中的列(3 + 3 + 1 + 4)。只需要那些列来查找匹配的行。可能,EXPLAIN输出显示MySQL正在使用 ref 加入操作(显示在type列中)。

修改查询时,WHERE子句中的谓词都是相等的条件,那么 ref 连接操作可以扩展到其他列,所以你在EXPLAIN输出中得到一个更长的key_len。

对于索引列的不等式比较,MySQL不使用 ref 操作,但可以使用 range 操作。可能,MySQL更倾向于使用较短的密钥前缀上的 ref 操作而不是较长的密钥前缀上的 range 操作。


如果MySQL使用ertReverseIndex索引,我们希望基于range子句中的谓词,WHERE操作的key_len为8。 (如果要删除ertFine列上的谓词,我们希望在EXPLAIN输出中将key_len报告为4。)

MySQL是否引用(即“使用”)索引中的任何其他列以满足查询,这将通过“ Using index 的存在/不存在”反映出来在EXPLAIN输出的Extra列中。如果存在,那么我们知道它是查询的覆盖索引,并且MySQL没有引用基础表中的块。


最重要的是,你有一个平等和不等式谓词的组合。 MySQL可以使用 ref (或 equal_ref )操作来实现相等条件,但不能使用不等式条件。对于不等式,MySQL可以使用 range 操作。