我有一个数据库架构,如下所示。
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';
CREATE SCHEMA IF NOT EXISTS `mydb` DEFAULT CHARACTER SET latin1 COLLATE latin1_swedish_ci ;
USE `mydb` ;
-- -----------------------------------------------------
-- Table `mydb`.`parent`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `mydb`.`parent` (
`id` INT NOT NULL ,
`data` VARCHAR(45) NULL ,
PRIMARY KEY (`id`) )
ENGINE = InnoDB;
-- -----------------------------------------------------
-- Table `mydb`.`OtherTable`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `mydb`.`OtherTable` (
`id` INT NOT NULL ,
`data` VARCHAR(45) NULL ,
PRIMARY KEY (`id`) )
ENGINE = InnoDB;
-- -----------------------------------------------------
-- Table `mydb`.`parent_has_OtherTable`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `mydb`.`parent_has_OtherTable` (
`parent_id` INT NOT NULL ,
`OtherTable_id` INT NOT NULL ,
PRIMARY KEY (`parent_id`, `OtherTable_id`) ,
INDEX `fk_parent_has_OtherTable_OtherTable1_idx` (`OtherTable_id` ASC) ,
INDEX `fk_parent_has_OtherTable_parent1_idx` (`parent_id` ASC) ,
CONSTRAINT `fk_parent_has_OtherTable_parent1`
FOREIGN KEY (`parent_id` )
REFERENCES `mydb`.`parent` (`id` )
ON DELETE NO ACTION
ON UPDATE NO ACTION,
CONSTRAINT `fk_parent_has_OtherTable_OtherTable1`
FOREIGN KEY (`OtherTable_id` )
REFERENCES `mydb`.`OtherTable` (`id` )
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB;
-- -----------------------------------------------------
-- Table `mydb`.`child`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `mydb`.`child` (
`parent_id` INT NOT NULL ,
`andAnotherTable_id` INT NOT NULL ,
`data` VARCHAR(45) NULL ,
PRIMARY KEY (`parent_id`) ,
CONSTRAINT `fk_child_parent1`
FOREIGN KEY (`parent_id` )
REFERENCES `mydb`.`parent` (`id` )
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;
我希望执行以下两个查询:
SELECT *
FROM child
INNER JOIN parent ON parent.id=child.parent_id
INNER JOIN parent_has_OtherTable ON parent_has_OtherTable.parent_id=parent.id
INNER JOIN OtherTable ON OtherTable.id=parent_has_OtherTable.OtherTable_id
WHERE child.parent_id=123
SELECT *
FROM child
INNER JOIN parent ON parent.id=child.parent_id
INNER JOIN parent_has_OtherTable ON parent_has_OtherTable.parent_id=parent.id
INNER JOIN OtherTable ON OtherTable.id=parent_has_OtherTable.OtherTable_id
WHERE OtherTable.id=123
我有什么理由需要在我的查询中包含parent
表(假设我不需要任何数据),而是执行如下查询?我担心的是索引可能不再有效,因为索引介于parent
和parent_has_OtherTable
之间,而不是child
和parent_has_OtherTable
。 PS。我有其他类似于child
的表与parent
具有一对一的关系,因此我的架构就是它的原因。
SELECT *
FROM child
INNER JOIN parent_has_OtherTable ON parent_has_OtherTable.parent_id=child.parent_id
INNER JOIN OtherTable ON OtherTable.id=parent_has_OtherTable.OtherTable_id
WHERE child.parent_id=123
SELECT *
FROM child
INNER JOIN parent_has_OtherTable ON parent_has_OtherTable.parent_id=child.parent_id
INNER JOIN OtherTable ON OtherTable.id=parent_has_OtherTable.OtherTable_id
WHERE OtherTable.id=123
mysql> EXPLAIN SELECT * FROM child INNER JOIN parent_has_OtherTable ON parent_has_OtherTable.parent_id=child.parent_id INNER JOIN OtherTable ON OtherTable.id=parent_has_OtherTable.OtherTable_id WHERE child.parent_id=1;
+----+-------------+-----------------------+-------+---------------------------------------------------------------------------------------+--------------------------------------+---------+-------+------+--------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-----------------------+-------+---------------------------------------------------------------------------------------+--------------------------------------+---------+-------+------+--------------------------------+
| 1 | SIMPLE | child | const | PRIMARY | PRIMARY | 4 | const | 1 | |
| 1 | SIMPLE | parent_has_OtherTable | ref | PRIMARY,fk_parent_has_OtherTable_OtherTable1_idx,fk_parent_has_OtherTable_parent1_idx | fk_parent_has_OtherTable_parent1_idx | 4 | const | 2 | Using index |
| 1 | SIMPLE | OtherTable | ALL | PRIMARY | NULL | NULL | NULL | 3 | Using where; Using join buffer |
+----+-------------+-----------------------+-------+---------------------------------------------------------------------------------------+--------------------------------------+---------+-------+------+--------------------------------+
3 rows in set (0.00 sec)
mysql> EXPLAIN SELECT * FROM child INNER JOIN parent_has_OtherTable ON parent_has_OtherTable.parent_id=child.parent_id INNER JOIN OtherTable ON OtherTable.id=parent_has_OtherTable.OtherTable_id WHERE OtherTable.id=1;
+----+-------------+-----------------------+-------+---------------------------------------------------------------------------------------+------------------------------------------+---------+-------+------+--------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-----------------------+-------+---------------------------------------------------------------------------------------+------------------------------------------+---------+-------+------+--------------------------------+
| 1 | SIMPLE | OtherTable | const | PRIMARY | PRIMARY | 4 | const | 1 | |
| 1 | SIMPLE | parent_has_OtherTable | ref | PRIMARY,fk_parent_has_OtherTable_OtherTable1_idx,fk_parent_has_OtherTable_parent1_idx | fk_parent_has_OtherTable_OtherTable1_idx | 4 | const | 2 | Using index |
| 1 | SIMPLE | child | ALL | PRIMARY | NULL | NULL | NULL | 3 | Using where; Using join buffer |
+----+-------------+-----------------------+-------+---------------------------------------------------------------------------------------+------------------------------------------+---------+-------+------+--------------------------------+
3 rows in set (0.00 sec)
mysql>
答案 0 :(得分:1)
索引永远不会跨越表格。外键引用另一个表,但FK利用表中定义的索引和FK,引用引用表中的唯一索引。
通过使用EXPLAIN
分析查询,您应该能够测试是否正在使用索引。例如,您可以看到每个表格引用都显示了键字段中使用的某个索引:
mysql> explain SELECT * FROM child
INNER JOIN parent ON parent.id=child.parent_id
INNER JOIN parent_has_OtherTable ON parent_has_OtherTable.parent_id=parent.id
INNER JOIN OtherTable ON OtherTable.id=parent_has_OtherTable.OtherTable_id
WHERE child.parent_id=123\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: child
type: const
possible_keys: PRIMARY
key: PRIMARY
key_len: 4
ref: const
rows: 1
Extra: NULL
*************************** 2. row ***************************
id: 1
select_type: SIMPLE
table: parent
type: const
possible_keys: PRIMARY
key: PRIMARY
key_len: 4
ref: const
rows: 1
Extra: NULL
*************************** 3. row ***************************
id: 1
select_type: SIMPLE
table: parent_has_OtherTable
type: ref
possible_keys: PRIMARY,fk_parent_has_OtherTable_OtherTable1_idx,fk_parent_has_OtherTable_parent1_idx
key: PRIMARY
key_len: 4
ref: const
rows: 1
Extra: Using index
*************************** 4. row ***************************
id: 1
select_type: SIMPLE
table: OtherTable
type: eq_ref
possible_keys: PRIMARY
key: PRIMARY
key_len: 4
ref: mydb.parent_has_OtherTable.OtherTable_id
rows: 1
Extra: NULL
对于第二个查询,它还使用索引:
mysql> explain SELECT * FROM child
INNER JOIN parent ON parent.id=child.parent_id
INNER JOIN parent_has_OtherTable ON parent_has_OtherTable.parent_id=parent.id
INNER JOIN OtherTable ON OtherTable.id=parent_has_OtherTable.OtherTable_id
WHERE OtherTable.id=123\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: OtherTable
type: const
possible_keys: PRIMARY
key: PRIMARY
key_len: 4
ref: const
rows: 1
Extra: NULL
*************************** 2. row ***************************
id: 1
select_type: SIMPLE
table: parent_has_OtherTable
type: ref
possible_keys: PRIMARY,fk_parent_has_OtherTable_OtherTable1_idx,fk_parent_has_OtherTable_parent1_idx
key: fk_parent_has_OtherTable_OtherTable1_idx
key_len: 4
ref: const
rows: 1
Extra: Using index
*************************** 3. row ***************************
id: 1
select_type: SIMPLE
table: child
type: eq_ref
possible_keys: PRIMARY
key: PRIMARY
key_len: 4
ref: mydb.parent_has_OtherTable.parent_id
rows: 1
Extra: NULL
*************************** 4. row ***************************
id: 1
select_type: SIMPLE
table: parent
type: eq_ref
possible_keys: PRIMARY
key: PRIMARY
key_len: 4
ref: mydb.parent_has_OtherTable.parent_id
rows: 1
Extra: NULL
重新评论和编辑问题:
是的,由于child
与parent
的关系为1:1,因此不需要在联接中包含父级。包含父级的原因是,如果您需要来自父级的一些列,或者行限制 - 也就是说,父级中的parent_id值可能少于子级中的父级(但是根据定义,这是不可能的,因为没有值可以出现在父母不在的孩子身上。)
最后,我猜一般原则是:你可以根据包含相同逻辑值域的任何列进行连接 - 它们不必须是显式外来的一部分关键关系。