你的查询语句本身没有问题。但是一个带有LEFT JOIN的查询只能使用右表(
staffcost
)上的索引。左表(
workdone
)上没有索引可以支持连接操作。所以你只需要在
staffcost(costyear)
上建立索引即可。
你可以使用以下脚本进行测试:
DROP TABLE IF EXISTS `staffcost`;
CREATE TABLE IF NOT EXISTS `staffcost` (
`id` int(10) unsigned NOT NULL,
`costyear` year(4) NOT NULL,
`data` text COLLATE utf8_unicode_ci,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
INSERT INTO `staffcost` (`id`, `costyear`, `data`) VALUES
(1, '2018', '0.6555866465490187'),
(2, '2019', '0.12234661925802624'),
(3, '2020', '0.64497318737672'),
(4, '2021', '0.8578261098431667'),
(5, '2022', '0.354211017819318'),
(6, '2023', '0.19757679030073508'),
(7, '2024', '0.9252509287793663'),
(8, '2025', '0.03352430372827156'),
(9, '2026', '0.3918687630369037'),
(10, '2027', '0.8587709347333489');
DROP TABLE IF EXISTS `workdone`;
CREATE TABLE IF NOT EXISTS `workdone` (
`id` int(10) unsigned NOT NULL,
`date` date NOT NULL,
`data` text COLLATE utf8_unicode_ci,
PRIMARY KEY (`id`),
KEY `date` (`date`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
INSERT INTO `workdone` (`id`, `date`, `data`) VALUES
(1, '2017-12-31', '0.40540353712197724'),
(2, '2018-01-01', '0.8716141803857071'),
(3, '2018-01-02', '0.1418603212962489'),
(4, '2018-01-03', '0.09445909605776807'),
(5, '2018-01-04', '0.04671454713373868'),
(6, '2018-01-05', '0.9501954782290342'),
(7, '2018-01-06', '0.6108337804776'),
(8, '2018-01-07', '0.2035824984345422'),
(9, '2018-01-08', '0.18541118147355615'),
(10, '2018-01-09', '0.31630844279779907');
EXPLAIN
SELECT * FROM workdone
LEFT JOIN staffcost ON YEAR(workdone.date) = staffcost.costyear;
ALTER TABLE `staffcost` ADD INDEX `costyear` (`costyear`);
EXPLAIN
SELECT * FROM workdone
LEFT JOIN staffcost ON YEAR(workdone.date) = staffcost.costyear;
SELECT VERSION();
结果:
id|select_type|table |type|possible_keys|key|key_len|ref|rows|Extra
1|SIMPLE |workdone |ALL | | | | | 10|
1|SIMPLE |staffcost|ALL | | | | | 10|Using where; Using join buffer (flat, BNL join)
id|select_type|table |type|possible_keys|key |key_len|ref |rows|Extra
1 |SIMPLE |workdone |ALL | | | | | 10|
1 |SIMPLE |staffcost|ref |costyear |costyear|1 |func| 1|Using where
VERSION()
10.1.26-MariaDB
在线演示: http://rextester.com/JIAL51740
yes
,那么可以在应用程序逻辑中强制要求在第二个表中包含一条记录并将JOIN转换为INNER JOIN。 - Adarsh Madrechastaffcost.costyear
上建立一个索引。 - Paul SpiegelEXPLAIN
来获取“正确”的查询计划。如果有更多的行会发生什么?特别是如果数据跨越超过10年。 - Rick James