MySQL版本5.7.18的问题。早期版本的MySQL的行为应该如此。与JOIN不使用索引的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是不使用索引和读取整个表格。 没有WHERE语句:
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 | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+------------------+------------+--------+---------------+-------------+---------+-----------------------+------+----------+-------------+ | 1 | SIMPLE | test_events | NULL | index | NULL | create_time | 4 | NULL | 1 | 100.00 | NULL | | 1 | SIMPLE | test_event_types | NULL | eq_ref | PRIMARY | PRIMARY | 4 | m16.test_events.event | 1 | 100.00 | Using index | +----+-------------+------------------+------------+--------+---------------+-------------+---------+-----------------------+------+----------+-------------+ 2 rows in set, 1 warning (0.00 sec)
现在它使用索引。
MySQL 5.5.55在这两种情况下都使用索引。为什么是这样以及如何处理它?
这很奇怪,但它的工作原理。如果我将列“base”的类型更改为整数并向此列添加索引,MySQL将开始在“create_time”字段中使用索引。如果我只添加索引或只将类型更改为int - 它的行为与以前一样。前一段时间错误地将Varchar设置为字段“base”,但在更新到最后一个版本的MySQL之前它已经正常。谢谢。 –
我不希望在表格中使用不会超过5-10行的索引(主索引除外)。但我认为这是一个错误的策略。但是,问题仍然存在于其他JOIN到文本字段中。在上面的示例中,我可以轻松地将varchar更改为整数,但是我无法在其他表中使用该字段,其中该字段包含一些文本代码。 –
我不知道这个表有少于10行。那么当然不需要索引。但后来mysql查询计划一直很奇怪 – e4c5