MySQL多列索引

时间:2016-10-03 19:14:16

标签: mysql database indexing

好的,我有以下MySQL表结构:

CREATE TABLE `creditlog` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `memberId` int(10) unsigned NOT NULL,
  `quantity` decimal(10,2) unsigned DEFAULT NULL,
  `timeAdded` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `reference` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `memberId` (`memberId`),
  KEY `timeAdded` (`timeAdded`));

我这样查询:

SELECT SUM(quantity) FROM creditlog where timeAdded>'2016-09-01' AND timeAdded<'2016-10-01' AND memberId IN (3,6,8,9,11)

现在,我也使用use index (timeAdded),因为条目数量更方便。解释上述查询显示:

type -> range,
key -> timeAdded,
rows -> 921294
extra -> using where

同时,如果我使用memberId INDEX,则会显示:

type -> range,
key -> memberId,
rows -> 1707849
extra -> using where

现在,我的问题是,可以将这两个索引组合在一起使用并减少查询的表面,因为我还需要添加更多条件(在其他列上)。

1 个答案:

答案 0 :(得分:0)

MySQL几乎从不在单个查询中使用两个索引;这不符合成本效益。但是,复合索引通常非常有效。您需要此订单:INDEX(memberId, timeAdded)

以这种方式构建索引......

  1. 首先包括使用WHERE测试的=子句中的列。 (没有,在你的情况下。)
  2. 包含IN
  3. 的任何列
  4. 一个'范围',例如<BETWEEN
  5. 移至GROUP BYORDER BY的所有字段。 (这里不相关。)
  6. 有很多例外和警告。有些是在cookbook中提供的。

    (与流行的观点相反,基数在设计索引时几乎从不相关。)

    这是一种比较两个索引的方法(即使是一个太小而无法获得可靠时序的表):

    FLUSH STATUS;
    SELECT SQL_NO_CACHE ...;
    SHOW SESSION STATUS LIKE 'Handler%';
    (repeat for other query/index)
    

    较小的数字几乎总是表示更好。

    “timeAdded&gt;'2016-09-01'AND timeAdded&lt;'2016-10-01'” - 不包括第一天的午夜。我推荐这种模式:

        timeAdded >= '2016-09-01'
    AND timeAdded  < '2016-09-01' + INTERVAL 1 MONTH
    

    这也避免了计算日期。

    闻起来像是一个常见的查询?您是否考虑过构建和维护Summary tables?等效查询可能会快10倍。