我有不同比赛中马匹赔率的历史数据,所以我有3张桌子
CREATE TABLE `horses` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `name` (`name`)
)
CREATE TABLE `odds` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`raceId` int(11) DEFAULT NULL,
`horseId` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `raceId` (`raceId`),
KEY `horseId` (`horseId`),
)
CREATE TABLE `races` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`venueId` int(10) unsigned NOT NULL,
`raceDate` date DEFAULT NULL,
`raceTime` time DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `locationId` (`venueId`,`raceDate`,`raceTime`)
)
马匹和种族表是几千行,但赔率表是20米+行,在raceId和horseId上索引(每个raceId,horseId多行)
我想在给定的日期提取马匹。我首先尝试了naeive 查询1
SELECT `h`.* FROM `races` `r`
LEFT JOIN `odds` `o` ON `o`.`raceId` = `r`.`id`
LEFT JOIN `horses` `h` ON `h`.`id` = `o`.`horseId`
WHERE `r`.`raceDate` = '2018-02-10'
AND `o`.`horseId` IS NOT NULL
GROUP BY `h`.`id`;
但花了2分钟+
知道我只想考虑给定日期的赔率,我做了这个(查询2 ):
SELECT DISTINCT horseId FROM odds
WHERE raceId IN (SELECT id FROM races WHERE raceDate = '2018-02-10');
这只需要几分之一秒,就能得到我需要的69匹马。因此,使用查询3 ...
来获取马匹应该是一件简单的事情SELECT * FROM horses WHERE horses.id IN (SELECT DISTINCT horseId FROM odds
WHERE raceId IN (SELECT id FROM races WHERE raceDate = '2018-02-10'));
它有效但与第一个查询的时间相同,事实上"解释"非常相似。
但如果我用括号中的实际69匹马替换括号中的整个部分(查询4 ):
SELECT * FROM horses WHERE horses.id IN (4885,3653,3356,4886,451,941...)
它再次在几分之一秒内运行。
我有一个现在快速运行的查询,但我想了解为什么查询3很慢?如果我从内到外以块的形式执行它,就像我直觉上认为mySql会做的那样,它的速度很快。
我确实理解优化器不会总是创建一个好的执行计划。 但是为什么mySql运行得如此低效呢?对我来说这似乎是一个非常有效的查询,与非常快的查询5
没有太大区别SELECT h.* FROM horses h
LEFT JOIN (SELECT DISTINCT horseId
FROM odds WHERE raceId IN (
SELECT id FROM races WHERE raceDate = '2018-02-10')) st
ON st.horseId = h.id
WHERE horseId IS NOT NULL;
我意识到连接可能比IN更好 - 我可以接受,如果查询4也很慢,但它不是,它只是一小部分。希望有一个" a-ha"这可能对我将来有所帮助。
答案 0 :(得分:0)
select distinct h.*
from races r
join odds o on o.raceId = r.id
join horses h on h.id = o.horceId
where r.date = '2018-02-10'
它应该与给定的索引一起使用。
答案 1 :(得分:0)
我的一大问题是覆盖索引中的raceDate必须是第一个。
仍然无法解释为什么查询3很慢,因为如果我自己执行内部部分,它很快,如果我将其输出手动输入外部查询,它就会很快。
MySql必须以其某种方式重新排列该查询,然后索引才是重要的。