为什么递归查询比加入和分组更快?

时间:2012-11-02 08:40:11

标签: mysql sql

我正在使用MySQL服务器5.5并具有下一个数据库结构

    -- -----------------------------------------------------
    -- Table `mydb`.`User`
    -- -----------------------------------------------------
    CREATE  TABLE IF NOT EXISTS `mydb`.`User` (
      `id` INT NOT NULL ,
      `Name` VARCHAR(45) NOT NULL ,
      PRIMARY KEY (`id`) )
    ENGINE = InnoDB;


    -- -----------------------------------------------------
    -- Table `mydb`.`Payments`
    -- -----------------------------------------------------
    CREATE  TABLE IF NOT EXISTS `mydb`.`Payments` (
      `id` INT NOT NULL ,
      `Amount` DOUBLE NOT NULL ,
      `User` INT NOT NULL ,
      PRIMARY KEY (`id`) ,
      INDEX `fk_Payments_User` (`User` ASC) ,
      CONSTRAINT `fk_Payments_User`
        FOREIGN KEY (`User` )
        REFERENCES `mydb`.`User` (`id` )
        ON DELETE NO ACTION
        ON UPDATE NO ACTION)
    ENGINE = InnoDB;


    -- -----------------------------------------------------
    -- Table `mydb`.`Extras`
    -- -----------------------------------------------------
    CREATE  TABLE IF NOT EXISTS `mydb`.`Extras` (
      `id` INT NOT NULL ,
      `ExtraAmount` DOUBLE NOT NULL ,
      PRIMARY KEY (`id`) ,
      INDEX `fk_Extras_Payments1` (`id` ASC) ,
      CONSTRAINT `fk_Extras_Payments1`
        FOREIGN KEY (`id` )
        REFERENCES `mydb`.`Payments` (`id` )
        ON DELETE NO ACTION
        ON UPDATE NO ACTION)
    ENGINE = InnoDB;

问题是:为什么这个查询

    SELECT u.*, sum(`amount`),sum(`ExtraAmount`)
    FROM `user` AS `u`
    LEFT JOIN payments AS p ON u.id = p.`user`
    INNER JOIN extras AS e ON p.id = e.id
    WHERE `Name` = 'abc'
    GROUP BY `Name`

比这个更慢

    SELECT *, IFNULL((SELECT sum(`amount`)
                      FROM payments AS p
                      WHERE u.id = p.`user`),0) AS `TotalAmount`,
              IFNULL((SELECT sum(`ExtraAmount`)
                      FROM payments AS p
                      INNER JOIN extras AS e ON p.id = e.id
                      WHERE p.`User` = u.id),0) AS `sum2`
    FROM `user` AS `u`
    WHERE `Name` = 'abc'

即使在空DB上也存在差异(0.0001-0002s,不多,但仍然)。但如果用50k记录填充每个表,差异将更明显。

从我的观点来看,第二个查询执行更多的子查询,所以它应该工作得更慢。

有人可以帮我解释一下吗?

1 个答案:

答案 0 :(得分:4)

不同之处在于,在第二个内部查询(SELECT sum(`amount`) FROM payments AS p WHERE u.id = p.`user`)上,mysql正在使用索引,与第一个查询相比,其中元素是在没有索引的情况下确定的。使用explain,您将能够看到执行计划,涉及的行数以及子查询是否使用索引。

请参阅sqlFiddle(请注意额外列)以了解您的方案的执行计划。