设为首页 收藏本站
查看: 713|回复: 0

[经验分享] MySQL InnoDB外键

[复制链接]

尚未签到

发表于 2016-9-13 07:19:26 | 显示全部楼层 |阅读模式
从mysql 3.23.44开始,innodb支持外键约束,跟Oracle基本相同,语法形式如下
[CONSTRAINT symbol] FOREIGN KEY [id] (index_col_name, ...)
REFERENCES tbl_name (index_col_name, ...)
[ON DELETE {RESTRICT | CASCADE | SET NULL | NO ACTION}]
[ON UPDATE {RESTRICT | CASCADE | SET NULL | NO ACTION}]

ALTER TABLE yourtablename
ADD [CONSTRAINT symbol] FOREIGN KEY [id] (index_col_name, ...)
REFERENCES tbl_name (index_col_name, ...)
[ON DELETE {RESTRICT | CASCADE | SET NULL | NO ACTION}]
[ON UPDATE {RESTRICT | CASCADE | SET NULL | NO ACTION}]


外键约束须满足以下条件:
. 父子表都为innodb,不是临时表

. 在子表上,必须存在一个索引,外键列是索引列的全部或部分,但必须是开头部分,并且顺序一致; 从mysql4.1.2开始,如果不存在索引,会自动创建外键上的索引; 加速约束检查/避免全表扫描

. 在父表上,必须存在一个索引,被参照键是索引列的全部或部分,但必须是开头部分,并且顺序一致; 加速约束检查/避免全表扫描

. 不允许在外键前缀或后缀上索引; 外键不能包括text/blob列

. 如果指定约束标识符 symbol, 那么必须数据库范围唯一; 不指定时,系统会自动产生

. 父子表的相应列必须有相似的内部数据类型, 以便进行比较时不必进和类型转换

   对于数字类型,类型长度与符号必须相同;
   对于字符类型, 长度不必相同

. 如果创建一个on delete set null或on update set null约束,子表的列必须不能为not null

. 从mysql3.23.50开始,如果外键或候选键(被引用键)列上有null值,mysql 将不进行check


外键约束对子表的含义:
  如果在父表中找不到候选键,则不允许在子表上进行insert/update

外键约束对父表的含义:
  在父表上进行update/delete以更新或删除在子表中有一条或多条对应匹配行的候选键时,父表的行为取决于:在定义子表的外键时指定的on update/on delete子句, InnoDB支持5种方式, 分列如下

  . cascade方式
   在父表上update/delete记录时,同步update/delete掉子表的匹配记录
   On delete cascade从mysql3.23.50开始可用; on update cascade从mysql4.0.8开始可用

  . set null方式
   在父表上update/delete记录时,将子表上匹配记录的列设为null
   要注意子表的外键列不能为not null
   On delete set null从mysql3.23.50开始可用; on update set null从mysql4.0.8开始可用

  . No action方式
   如果子表中有匹配的记录,则不允许对父表对应候选键进行update/delete操作
   这个是ANSI SQL-92标准,从mysql4.0.8开始支持

  . Restrict方式
   同no action, 都是立即检查外键约束

  . Set default方式
   解析器认识这个action,但Innodb不能识别,不知道是什么意思...

  注意:trigger不会受外键cascade行为的影响,即不会解发trigger

在mysql中,与SQL标准相违背的三点
1.       如果在父表中有多个key值相同,那么在进行外键check时,会当成有相同key值的其他行不存在; 比如当定义了一个restrict行为外键时,一个子表行对应到多个父表行(具有相同key值), Innodb不允许删除父表上的所有这些行

下面这句未理解,depth-first?
InnoDB performs cascading operations through a depth-first algorithm, based on records in the indexes corresponding to the foreign key constraints.

2.       父子表是同一个表,自我参照时不允许指定on update cascade, on update set null
从mysql4.0.13开始,允许同一个表上的on delete set null
从mysql4.0.21开始,允许同一个表上的on delete cascade
但级联层次不能超出15

3, Innodb在检查unique,constraint约束时,是row by row而不是语句或事务结束;
  SQL标准中对constraint的检查是在语句执行完成时


创建/操作外键的例子
--简单外键
CREATE TABLE parent
(
id INT NOT NULL,
PRIMARY KEY (id)
)
engine=INNODB;

CREATE TABLE child
(
   id INT,
   parent_id INT,
   INDEX par_ind (parent_id,id),  è外键列是索引列的开头部分
   FOREIGN KEY (parent_id) REFERENCES parent(id) ON DELETE CASCADE
)
engine=INNODB;

--较复杂的外键
CREATE TABLE product
(
   category INT NOT NULL,
   id INT NOT NULL,
   price DECIMAL,
   PRIMARY KEY(category, id)
)
engine=INNODB;

CREATE TABLE customer
(
  id INT NOT NULL,
  PRIMARY KEY (id)
)
engine=INNODB;

CREATE TABLE product_order
(
   no INT NOT NULL AUTO_INCREMENT,
   product_category INT NOT NULL,
   product_id INT NOT NULL,
   customer_id INT NOT NULL,
   PRIMARY KEY(no),
   INDEX (product_category, product_id),
   FOREIGN KEY (product_category, product_id) REFERENCES product(category, id) ON UPDATE CASCADE ON DELETE RESTRICT,
   INDEX (customer_id),
   FOREIGN KEY (customer_id)REFERENCES customer(id)
)
engine=INNODB;

--查看外建/drop外键/alter 添加外键
mysql> show create table child\G
*************************** 1. row ***************************
       Table: child
Create Table: CREATE TABLE `child` (
  `id` int(11) default NULL,
  `parent_id` int(11) default NULL,
  KEY `par_ind` (`parent_id`,`id`),
  CONSTRAINT `child_ibfk_1` FOREIGN KEY (`parent_id`) REFERENCES `parent` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=latin1
1 row in set (0.00 sec)

mysql> alter table child drop FOREIGN KEY child_ibfk_1;
Query OK, 0 rows affected (0.01 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> alter table child add constraint child_ibfk_1
    -> FOREIGN KEY (parent_id) REFERENCES parent(id) ON DELETE CASCADE;
Query OK, 0 rows affected (0.01 sec)
Records: 0  Duplicates: 0  Warnings: 0


Mysql中与外键相关的错误

If MySQL reports an error number 1005 from a CREATE TABLE statement, and the error message
string refers to errno 150, this means that the table creation failed because a foreign key constraint
was not correctly formed. Similarly, if an ALTER TABLE fails and it refers to errno 150, that
means a foreign key definition would be incorrectly formed for the altered table. Starting from
MySQL 4.0.13, you can use SHOW INNODB STATUS to display a detailed explanation of the
latest InnoDB foreign key error in the server.

测试如下:
set FOREIGN_KEY_CHECKS = 0; --禁用约束检查
drop table product;  --删除product_order的父表
set FOREIGN_KEY_CHECKS = 1; --启用约束检查
重新创建product,这次没有建pk
CREATE TABLE product
(
   category INT NOT NULL,
   id INT NOT NULL,
   price DECIMAL,
   index(category, id)
)
engine=INNODB;

查看show innodb status中的错误信息
------------------------
LATEST FOREIGN KEY ERROR
------------------------
080424 19:38:50  Cannot drop table `test/product`
because it is referenced by `test/product_order`

其它
1, mysqldump在dump数据时,会加入外键信息

2, 也可以用SHOW TABLE STATUS FROM db_name LIKE 'tbl_name';查看外键信息, 在comment列中

3, 注意innodb中如果设置了lower_case_table_names,对外键的影响

4, 在创建外键时,可以加入backtricks(反引号),将外键名,列名包括起来

5, 如果是在mysql3.23.50之前版本,注意如果表上有外键或者作为父表被refer,不要使用alter table , create index命令

6, Innodb要进行外键check时,需要在父或子表上加共享行级锁(shared row lock),不是事务级

7, 从mysql4.1.1开始,为了使reload dumpfile更容易进行,mysqldump生成的文件自动添加了FOREIGN_KEY_CHECKS=0选项以禁止外键约束检查
  对于早期版本,可以用下面方法达到同样目的
   mysql> SET FOREIGN_KEY_CHECKS = 0;
mysql> SOURCE dump_file_name
mysql> SET FOREIGN_KEY_CHECKS = 1;

8, 在alter table或load data时,可能也需要进行上述设置以临时禁止外键约束检查

9, 除非设置了FOREIGN_KEY_CHECKS = 0, Innodb禁止drop父表(被子表外键引用的表)

10, 当设置FOREIGN_KEY_CHECKS = 0后drop一个父子.
  下次重新创建这个父表时,必须跟drop之前一样(正确的列/数据类型/被参照的列上必须有索引), 否则系统会报1005 refer to errno 150  (这一点前述测试中没有发现报错)

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.iyunv.com/thread-271380-1-1.html 上篇帖子: Mysql语言小结 下篇帖子: mysql实现sequence
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表