为什么此查询会搜索所有行,尽管被引导'

时间:2018-02-10 19:11:11

标签: mysql

我有不同比赛中马匹赔率的历史数据,所以我有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"这可能对我将来有所帮助。

2 个答案:

答案 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必须以其某种方式重新排列该查询,然后索引才是重要的。