mysql版本5.7.18有问题。早期版本的mysql的行为应该是这样的。
这是两张桌子。表1:

CREATE TABLE `test_events` (
  `id` int(11) NOT NULL,
  `event` int(11) DEFAULT '0',
  `manager` int(11) DEFAULT '0',
  `base_id` int(11) DEFAULT '0',
  `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `client` int(11) DEFAULT '0',
  `event_time` datetime DEFAULT '0000-00-00 00:00:00'
) ENGINE=InnoDB DEFAULT CHARSET=utf8;


ALTER TABLE `test_events`
  ADD PRIMARY KEY (`id`),
  ADD KEY `client` (`client`),
  ADD KEY `event_time` (`event_time`),
  ADD KEY `manager` (`manager`),
  ADD KEY `base_id` (`base_id`),
  ADD KEY `create_time` (`create_time`);

第二张桌子:
CREATE TABLE `test_event_types` (
  `id` int(11) NOT NULL,
  `name` varchar(255) DEFAULT NULL,
  `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `base` varchar(255) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

ALTER TABLE `test_event_types`
  ADD PRIMARY KEY (`id`);

让我们尝试从基础“314”中选择最后一个事件:
EXPLAIN  SELECT  `test_events`.`create_time`
    FROM  `test_events`
    LEFT JOIN  `test_event_types`
           ON ( `test_events`.`event` = `test_event_types`.`id` )
    WHERE  base = 314
    ORDER BY  `test_events`.`create_time` DESC
    LIMIT  1;

+----+-------------+------------------+------------+------+---------------+------+---------+------+--------+----------+----------------------------------------------------+
| id | select_type | table            | partitions | type | possible_keys | key  | key_len | ref  | rows   | filtered | Extra                                              |
+----+-------------+------------------+------------+------+---------------+------+---------+------+--------+----------+----------------------------------------------------+
|  1 | SIMPLE      | test_events      | NULL       | ALL  | NULL          | NULL | NULL    | NULL | 434928 |   100.00 | Using temporary; Using filesort                    |
|  1 | SIMPLE      | test_event_types | NULL       | ALL  | PRIMARY       | NULL | NULL    | NULL |     44 |     2.27 | Using where; Using join buffer (Block Nested Loop) |
+----+-------------+------------------+------------+------+---------------+------+---------+------+--------+----------+----------------------------------------------------+
2 rows in set, 1 warning (0.00 sec)

MySQL is not using index and reads the whole table.Without WHERE statement:

EXPLAIN  SELECT  `test_events`.`create_time`
    FROM  `test_events`
    LEFT JOIN  `test_event_types`
          ON ( `test_events`.`event` = `test_event_types`.`id` )
    ORDER BY  `test_events`.`create_time` DESC
    LIMIT  1;

+——————————————————————————————————————————————————————————————————————————————————————-+
| id选择类型表分区类型可能的键键长度参考行过滤额外|
+——————————————————————————————————————————————————————————————————————————————————————-+
| 1简单测试事件空索引空创建时间4空1 100.00空|
| 1简单测试事件类型空eq参考主要主要4 m16.测试事件1 100.00使用索引|
+——————————————————————————————————————————————————————————————————————————————————————-+
一组2行,1个警告(0.00秒)
现在它使用索引。
mysql 5.5.55在这两种情况下都使用索引。为什么是这样,怎么办?

最佳答案

我不知道您在以前和当前安装中看到的区别,但是服务器的行为是有意义的。

SELECT  test_events.create_time  FROM  test_events  LEFT JOIN  test_event_types ON (  test_events.event =  test_event_types.id )  ORDER BY  test_events.create_time DESC LIMIT 1;

在这个查询中,您没有where子句,但只获取一行。这是在按create_time排序之后,它碰巧有一个索引。这个索引可以用来排序。但让我们看看第二个问题。
SELECT  test_events.create_time  FROM  test_events  LEFT JOIN  test_event_types ON (  test_events.event =  test_event_types.id ) WHERE base = 314 ORDER BY  test_events.create_time DESC LIMIT 1

在基列上没有索引。所以没有索引可用于此。要找到相关的记录,mysql必须进行表扫描。在识别了相关行之后,需要对它们进行排序。但是在这种情况下,查询计划器已经决定在create_time上使用索引是不值得的。
我看到您的设置有几个问题,第一个问题是没有和索引base,如前所述。但为什么base varchar是?你好像在里面存储整数。
ALTER TABLE test_events
  ADD PRIMARY KEY (id),
  ADD KEY client (client),
  ADD KEY event_time (event_time),
  ADD KEY manager (manager),
  ADD KEY base_id (base_id),
  ADD KEY create_time (create_time);

在mysql中,像这样创建多个索引没有多大意义。这是因为mysql只能对每个表使用一个索引进行查询。你最好用一两个索引。可能是多列索引。
我认为理想的索引将包含创建时间和事件字段

10-07 19:17
查看更多