2014-08-29 37 views
0

我有四个MySQL表,其中前三个共享第一个表PK,第四个有一个FK到第三个表(见下面的模式)。是否需要加入1对1表格?

鉴于第四表的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 @[email protected]@UNIQUE_CHECKS, UNIQUE_CHECKS=0; 
SET @[email protected]@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0; 
SET @[email protected]@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 [email protected]_SQL_MODE; 
SET [email protected]_FOREIGN_KEY_CHECKS; 
SET [email protected]_UNIQUE_CHECKS; 
+3

如果您不使用任何内容,则无需加入表格。 – Barmar 2014-08-29 19:45:52

+0

@Barmar我问的原因是我不确定性能是否会受到索引的影响。 – user1032531 2014-08-29 19:46:33

+0

@Barmer。请回答这个问题,然后如果你被拒绝了,我知道你可能是不对的:) – user1032531 2014-08-29 19:47:32

回答

3

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

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

+0

@ user2864740查询计划程序不能自动排除连接,因为行可能会丢失,因此会从内部连接中删除。 – 2014-08-29 19:52:17

+0

@JeffreyLWhitledge啊,谢谢 - 我现在看到这个案子。这个信息应该在答案中。 – user2864740 2014-08-29 19:53:31

+0

我已经添加了一些解释。 – Barmar 2014-08-29 19:57:33

1

如果所有的ID在所有四个表一样的,如果你不想排除没有出现在表2和表3的记录,那么就没有任何理由将它们包含在连接中。它仍将使用表1中的索引,即使没有外键关系。

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

+0

在你稍后的时间点上,如果我的表是“实体”,“人”,“朋友”和“cars_that_friends_drive”,都应该引用“实体”?我可能会有一张名为“动物”的表,而不是“人”,显然动物不会开车。 – user1032531 2014-08-29 19:51:26

+0

@ user1032531 - 够公平的。我将删除该建议。 – 2014-08-29 19:55:24

0

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

我建议你改变你的病情的好地方:

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

通过这样做,只有需要的数据是从T4加载,而不是每一个数据加载,然后对结果应用WHERE条件。

希望这会帮助你。

+0

谢谢乔尔。其他人,如果您同意或不同意,请发表评论。谢谢 – user1032531 2014-08-29 19:54:00

+0

如果您有可能比较查询与WHERE条款和我提供的查询之间的表现,请分享您的反馈。 – 2014-08-29 20:57:43

+0

不过,我需要学习如何去做,所以可能需要几天时间。谢谢 – user1032531 2014-08-29 22:50:45