我有四个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;
答案 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
条件。
希望这会对你有所帮助。