为什么MySQL不为这个select查询使用索引?

为什么MySQL不为这个select查询使用索引?,mysql,innodb,database-indexes,Mysql,Innodb,Database Indexes,为什么这个查询不在这里使用索引?该表使用InnoDB引擎 explain SELECT null as id, -> up_time, -> reg_date, -> refer, -> MAX(IFNULL(visits_count,0)) as visits_count, -> MAX(IFNULL(register_count,0)) as register_count, -> MAX(IFNU

为什么这个查询不在这里使用索引?该表使用InnoDB引擎

explain SELECT null as id,
    ->  up_time,
    ->  reg_date,
    ->  refer,
    ->  MAX(IFNULL(visits_count,0)) as visits_count,
    ->  MAX(IFNULL(register_count,0)) as register_count,
    ->  MAX(IFNULL(players_count,0)) as players_count,
    ->  MAX(IFNULL(activity_count,0)) as activity_count,
    ->  MAX(IFNULL(payment_users_count,0)) as payment_users_count,
    ->  MAX(IFNULL(payment_count,0)) as payment_count,
    ->  MAX(IFNULL(payment_sum,0)) as payment_sum FROM stats_refers
    ->
    ->  WHERE
    ->
    ->  stats_refers.reg_date < 1435006800
    ->  AND stats_refers.up_time < 1435006800
    ->
    ->  GROUP BY stats_refers.refer, stats_refers.reg_date;
以及可以使用的钥匙:

+--------------+------------+--------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
|表|非唯一|键|名称|列|名称|排序规则|基数|子|部分|压缩|空|索引|类型|注释|索引|注释|
+--------------+------------+--------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
|统计数据是指| 0 |主要| 1 | id | A | 2983126 |空|空| BTREE ||
|统计数据是指| 0 |注册日期| 1 |注册日期| A | 13317 |空|空| BTREE ||
|统计数据是指| 0 |登记|日期| 2 |更新|时间| A | 1491563 |空|空|树||
|统计数据指的是| 0 |登记|日期| 3 |指的是| A | 2983126 |空|空| BTREE ||
|统计是指| 1 |统计| 1 |登记|日期| A | 15142 |空|空| BTREE ||
|统计数字| 1 |统计数字| 2 |参考数字| A | 28683 |空|空| B树||
|统计数据|参考| 1 |参考|正常运行时间| 1 |参考| A | 2307 |空|空| B树||
|统计数据| 1 |参考正常运行时间| 2 |运行时间| A | 1491563 |空|空| BTREE ||
|统计数据是指| 1 |上升|注册|索引| 1 |注册|日期| A | 2314 |空|空| BTREE ||
|统计数据是指| 1 |上升|指数| 2 |上升|时间| A | 1491563 |零|零|树||
+--------------+------------+--------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
以下是表格说明:

CREATE TABLE `stats_refers` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `reg_date` int(10) unsigned NOT NULL,
  `up_time` int(10) unsigned NOT NULL,
  `refer` varchar(16) NOT NULL DEFAULT '',
  `visits_count` int(10) unsigned NOT NULL DEFAULT '0',
  `register_count` int(10) unsigned NOT NULL DEFAULT '0',
  `players_count` int(10) unsigned NOT NULL DEFAULT '0',
  `activity_count` int(10) unsigned NOT NULL DEFAULT '0',
  `payment_users_count` int(10) unsigned NOT NULL DEFAULT '0',
  `payment_count` int(10) unsigned NOT NULL DEFAULT '0',
  `payment_sum` int(10) unsigned NOT NULL DEFAULT '0',
  PRIMARY KEY (`id`),
  UNIQUE KEY `reg_date` (`reg_date`,`up_time`,`refer`),
  KEY `stat` (`reg_date`,`refer`),
  KEY `refer_uptime` (`refer`,`up_time`),
  KEY `up_reg_index` (`reg_date`,`up_time`)
) ENGINE=InnoDB AUTO_INCREMENT=4136504 DEFAULT CHARSET=utf8 |
+----+-------------+--------------+-------+-----------------------------------+-------------+---------+------+---------+-------------+
|id |选择|类型|类型|可能的|键|键|列|参考|行|额外|
+----+-------------+--------------+-------+-----------------------------------+-------------+---------+------+---------+-------------+
|1 |简单|统计|引用|索引|注册|日期、更新时间、注册、搜索|索引|组|索引| 54 |空| 3011896 |使用where|
+----+-------------+--------------+-------+-----------------------------------+-------------+---------+------+---------+-------------+

复合索引
stat
,我假设它是为这个分组操作创建的,与您尝试执行的分组操作的顺序相反。要使索引可用于此分组操作,您需要执行以下操作之一:

  • 颠倒
    stat
    索引上的列顺序
  • 上添加单独的索引,请参阅
  • 参考
    注册日期

您做出的决定最终需要考虑表上的其他查询操作。

在这里,您可能需要更广泛地考虑索引的使用。与在表上的查询范围内为每个字段使用单独的索引相比,使用复合索引可以提高性能,但在您的情况下,您是在表描述中以不同的组合在相同字段上复制索引。如果不了解所有查询用例,您可能很难看到总体索引建议,但我只想指出,您可能需要考虑一下这一点

例如,
up\u reg\u索引
根本不需要,因为该索引已经包含在
reg\u日期
唯一索引中。您最好使用以下一组索引:

PRIMARY KEY (`id`),
UNIQUE KEY `regdate_uptime_refer` (`reg_date`,`up_time`,`refer`),
KEY `reg_date` (`reg_date`),
KEY `refer` (`refer`),
KEY `up_time` (`up_time`),
这无疑会比您目前拥有的索引占用更少的空间,并允许在如何筛选/加入/分组这些列方面具有更大的灵活性,但不要将此视为一个坚定的建议。针对不同的查询场景测试不同索引场景的性能(如果是用例,则特别是插入性能)

按照该顺序,优化器可能会将其用于
分组依据

INDEX(up_time)
对于
中引用
up\u time
部分可能有用

    reg_date < 1435006800
AND up_time  < 1435006800

(当然,更改可能会打乱其他查询。)

可以或不能使用索引?…不能,抱歉,我会修复它的。不用担心。我只是想澄清一下。
id
列是否唯一?可能是
auto_increment
ing?出于好奇,字段的数据类型是什么?是的,id是主要的唯一键+1,供您解释和建议,但是,我有一个问题。为什么它不能让用户“引用”多列索引“引用正常运行时间”的一部分?我的意思是,在“refere”列中添加单个索引会给已经存在的以“refere”作为第一列的多列索引带来什么好处?@sactiw查看MySQL文档中的GROUP BY optimizatoin-具体查看“松散索引扫描”下的第二个要点。具体讨论了这个条件。A.
    reg_date < 1435006800
AND up_time  < 1435006800
PRIMARY KEY(refer, reg_date, uptime)