2014-08-29 34 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