是否总是需要加入一对一的表?

时间:2014-08-29 19:43:17

标签: mysql sql

我有四个MySQL表,其中前三个共享第一个表PK,第四个表有一个FK到第三个表(见下面的模式)。

鉴于第四张桌子的PK,我只需要来自第一张和第四张桌子的数据。

是否需要加入第二张和第三张桌子?

例如,是:

SELECT t1.*,t4.*
FROM t1
INNER JOIN t2 ON t2.t1_idt1=t1.idt1
INNER JOIN t3 ON t3.t2_idt2=t2.idt2
INNER JOIN t4 ON t4.t3_idt3=t3.idt3
WHERE t4.idt4=123;

好于或坏于:

SELECT t1.*,t4.*
FROM t1
INNER JOIN t4 ON t4.t3_idt3=t1.idt1
WHERE t4.idt4=123;

请解释为什么一个比另一个好。

SCHEMA

-- MySQL Script generated by MySQL Workbench
-- 08/29/14 12:34:46
-- Model: New Model    Version: 1.0
SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0;
SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0;
SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='TRADITIONAL,ALLOW_INVALID_DATES';

-- -----------------------------------------------------
-- Schema mydb
-- -----------------------------------------------------
CREATE SCHEMA IF NOT EXISTS `mydb` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci ;
USE `mydb` ;

-- -----------------------------------------------------
-- Table `mydb`.`t1`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `mydb`.`t1` (
  `idt1` INT NOT NULL,
  `data` VARCHAR(45) NULL,
  PRIMARY KEY (`idt1`))
ENGINE = InnoDB;


-- -----------------------------------------------------
-- Table `mydb`.`t2`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `mydb`.`t2` (
  `t1_idt1` INT NOT NULL,
  `data` VARCHAR(45) NULL,
  PRIMARY KEY (`t1_idt1`),
  CONSTRAINT `fk_t2_t1`
    FOREIGN KEY (`t1_idt1`)
    REFERENCES `mydb`.`t1` (`idt1`)
    ON DELETE NO ACTION
    ON UPDATE NO ACTION)
ENGINE = InnoDB;


-- -----------------------------------------------------
-- Table `mydb`.`t3`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `mydb`.`t3` (
  `t2_t1_idt1` INT NOT NULL,
  `data` VARCHAR(45) NULL,
  PRIMARY KEY (`t2_t1_idt1`),
  CONSTRAINT `fk_t3_t21`
    FOREIGN KEY (`t2_t1_idt1`)
    REFERENCES `mydb`.`t2` (`t1_idt1`)
    ON DELETE NO ACTION
    ON UPDATE NO ACTION)
ENGINE = InnoDB;


-- -----------------------------------------------------
-- Table `mydb`.`t4`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `mydb`.`t4` (
  `t3_t2_t1_idt1` INT NOT NULL,
  `data` VARCHAR(45) NULL,
  INDEX `fk_t4_t31_idx` (`t3_t2_t1_idt1` ASC),
  CONSTRAINT `fk_t4_t31`
    FOREIGN KEY (`t3_t2_t1_idt1`)
    REFERENCES `mydb`.`t3` (`t2_t1_idt1`)
    ON DELETE NO ACTION
    ON UPDATE NO ACTION)
ENGINE = InnoDB;


SET SQL_MODE=@OLD_SQL_MODE;
SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS;
SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS;

3 个答案:

答案 0 :(得分:3)

如果他们与查询无关,则您不需要加入任何表格。如果需要引用列,或者希望结果集限制为该表中具有匹配项的行,则表是相关的。加入额外的表会减慢查询速度,因为查询计划程序无法确定这些连接是多余的;没有办法告诉DBMS两个表之间存在一对一的关系。您可以做的最好的事情是声明外键关系 - 外键需要是另一个表中值的子集;但是没有办法宣布确切的等价。事实上,即使你打算一对一等价,你实际上也没有 - 当你插入三个表时,你必须按顺序执行它们,所以在短时间内有#39 ;在一个或两个表中增加一行。

如果比较两个查询之间EXPLAIN的结果,您可以看到查询计划程序使用了额外的表。

答案 1 :(得分:1)

如果所有四个表中的所有ID都相同,并且您不想排除不会出现在表2和表3中的记录,则没有理由将它们包含在联接中。即使没有外键关系,它仍然会使用表1中的索引。

我会考虑重命名所有ID列,以表示它们是相同的。

答案 2 :(得分:0)

第二种解决方案要好得多,查询只从两个必需的表中获取数据,而不是在你不需要的两个附加表之间应用联合。

我建议你改变你的病情:

SELECT t1.*,t4.*
FROM t1
INNER JOIN t4 ON t4.t3_idt3=t1.idt1
                AND t4.idt4=123

通过这样做,只从t4加载所需的数据,而不是加载每个数据,然后在结果上应用WHERE条件。

希望这会对你有所帮助。