简体   繁体   English

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

[英]Is joining 1-to-1 tables always necessary?

I have four MySQL tables where the first three share the first tables PK, and the forth has a FK to the third table (see below for schema). 我有四个MySQL表,其中前三个共享第一个表PK,第四个共享第三个表的FK(有关架构,请参见下文)。

Given the PK of the forth table, I need data from the first and forth table only. 给定第四张表的PK,我只需要第一张表和第四张表中的数据。

Is there any need to join the second and third table? 有必要加入第二张和第三张桌子吗?

For instance, is: 例如,是:

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;

better or worse than: 比以下更好或更坏:

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

Please explain why one is better than the other. 请解释为什么一个比另一个更好。

SCHEMA 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;

You don't need to join any tables if they're not relevant to the query. 如果它们与查询无关,则不需要联接任何表。 A table is relevant if you need to refer to it columns, or you want the result set limited to rows that have matches in that table. 如果需要引用表列,或者要将结果集限制为该表中具有匹配项的行,则该表是相关的。 Joining with extra tables will slow down the query, because the query planner cannot determine that these joins are redundant; 用额外的表联接将减慢查询速度,因为查询计划者无法确定这些联接是否是冗余的。 there's no way to tell the DBMS that there's a 1-to-1 relationship between two tables. 无法告诉DBMS两个表之间存在一对一的关系。 The best you can do is declare foreign key relationships -- the foreign key is required to be a subset of the values in the other table; 最好的办法就是声明外键关系-外键必须是另一个表中值的子集; but there's no way to declare exact equivalence. 但是没有办法宣布完全对等。 In fact, even if you intend to have 1-to-1 equivalence, you don't actually have it -- when you insert into the three tables, you have to do them sequentially, so for a brief period there's an extra row in one or two of the tables. 实际上,即使您打算具有1对1的对等关系,也实际上并没有它-当您插入三个表时,您必须按顺序进行操作,因此在短时间内会有一个额外的行一两个表。

You can see that the query planner makes use of the extra tables if you compare the result of EXPLAIN between the two queries. 如果您比较两个查询之间的EXPLAIN结果,则可以看到查询计划程序使用了多余的表。

If all IDs are the same in all four tables, and if you don't want to exclude records that don't appear in tables 2 and 3, then there is no reason to include them in the join. 如果所有四个表中的所有ID都相同,并且您不想排除未出现在表2和3中的记录,则没有理由将它们包括在联接中。 It will still use the index on table 1, even without the foreign key relationship. 即使没有外键关系,它仍将使用表1上的索引。

I would consider renaming all the ID columns to signify the fact that they are the same. 我会考虑重命名所有ID列以表示它们相同的事实。

The second solution is much better, the query only get the data from the two required tables instead of applying the jointure between two additional tables that you don't need. 第二种解决方案更好,查询仅从两个必需的表中获取数据,而不是在不需要的两个其他表之间应用联合。

I suggest you to change just the place of your condition: 我建议您仅更改条件的位置:

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

By doing so, only the required data are loaded from t4 instead of loading every data and then applying the WHERE condition on the result. 这样,仅从t4加载所需的数据,而不是加载每个数据,然后在结果上应用WHERE条件。

Hope this will help you. 希望这会帮助你。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM