我试图创建一个简单的架构,见下文。但由于某种原因,我得到了这个奇怪的150错误。我能够将问题缩小到唯一键声明:UNIQUE KEY (fk_im_savegroups_sgcode, sscode)
。如果我重构声明:UNIQUE KEY (sscode)
- 它有效。
有人可以向我解释为什么我不能使用复合索引?
DROP DATABASE IF EXISTS test447;
CREATE DATABASE test447 CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;
USE test447;
CREATE TABLE im_savegroups (
id INT UNSIGNED NOT NULL AUTO_INCREMENT,
sgcode VARCHAR(20) NOT NULL,
PRIMARY KEY (id),
UNIQUE KEY (sgcode)
) ENGINE=InnoDB CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE TABLE im_savespecs (
id INT UNSIGNED NOT NULL AUTO_INCREMENT,
fk_im_savegroups_sgcode VARCHAR(20) NOT NULL,
sscode VARCHAR(20) NOT NULL,
max_w INT UNSIGNED,
max_h INT UNSIGNED,
ratio_x INT UNSIGNED,
ratio_y INT UNSIGNED,
quality INT UNSIGNED,
format VARCHAR(10),
rel_dir VARCHAR(400),
is_retina TINYINT UNSIGNED DEFAULT 0,
is_preferred TINYINT UNSIGNED DEFAULT 0,
PRIMARY KEY (id),
FOREIGN KEY (fk_im_savegroups_sgcode) REFERENCES im_savegroups (sgcode) ON DELETE CASCADE ON UPDATE CASCADE,
UNIQUE KEY (fk_im_savegroups_sgcode, sscode)
) ENGINE=InnoDB CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE TABLE im_originals (
id INT UNSIGNED NOT NULL AUTO_INCREMENT,
fk_im_savespecs_sscode VARCHAR(20) NOT NULL,
name VARCHAR(255),
alt VARCHAR(180),
filename VARCHAR(64),
caption VARCHAR(1024),
credit VARCHAR(1024),
expires_at DATETIME,
created_at DATETIME,
updated_at DATETIME,
PRIMARY KEY (id),
FOREIGN KEY (fk_im_savespecs_sscode) REFERENCES im_savespecs (sscode) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;
答案 0 :(得分:1)
CREATE TABLE im_savegroups (
id INT UNSIGNED NOT NULL AUTO_INCREMENT,
sgcode VARCHAR(20) NOT NULL,
PRIMARY KEY (id),
UNIQUE KEY (sgcode)
) ENGINE=InnoDB; -- CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE TABLE im_savespecs (
id INT UNSIGNED NOT NULL AUTO_INCREMENT,
fk_im_savegroups_sgcode VARCHAR(20) NOT NULL,
sscode VARCHAR(20) NOT NULL,
max_w INT UNSIGNED,
max_h INT UNSIGNED,
ratio_x INT UNSIGNED,
ratio_y INT UNSIGNED,
quality INT UNSIGNED,
format VARCHAR(10),
rel_dir VARCHAR(400),
is_retina TINYINT UNSIGNED DEFAULT 0,
is_preferred TINYINT UNSIGNED DEFAULT 0,
PRIMARY KEY (id),
FOREIGN KEY (fk_im_savegroups_sgcode) REFERENCES im_savegroups (sgcode) ON DELETE CASCADE ON UPDATE CASCADE,
UNIQUE KEY (fk_im_savegroups_sgcode, sscode),
unique key (sscode) -- ******************************
) ENGINE=innodb CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE TABLE im_originals (
id INT UNSIGNED NOT NULL AUTO_INCREMENT,
fk_im_savespecs_sscode VARCHAR(20) NOT NULL,
name VARCHAR(255),
alt VARCHAR(180),
filename VARCHAR(64),
caption VARCHAR(1024),
credit VARCHAR(1024),
expires_at DATETIME,
created_at DATETIME,
updated_at DATETIME,
PRIMARY KEY (id),
CONSTRAINT fk_orig_ss FOREIGN KEY (`fk_im_savespecs_sscode`) REFERENCES im_savespecs(sscode) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=innodb CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;
我遇到的最大问题是:
1)是列的一个是varchar(20),复合在其中两个,OP可能需要第二个复合。在我的书中,这些都是相当广泛的复合材料。
2)FK应该回到代码表中的唯一超薄代码(未显示或甚至存在),或者返回到pk的内部。这说明了索引优化。
我甚至会做出大胆的声明,即FK应该几乎总是回到整体,除非它是如此无法忍受的心理沉思,code
本身就像邮政编码一样苗条。
答案 1 :(得分:1)
http://dev.mysql.com/doc/refman/5.6/en/create-table-foreign-keys.html
InnoDB允许外键引用任何索引列或组 列。但是,在引用的表中,必须有一个索引 其中引用的列被列为的第一列 同样的顺序。
强调“第一栏”。
所以只需切换唯一键中字段的顺序:
UNIQUE KEY (sscode, fk_im_savegroups_sgcode),