当前位置:首页 > 问答 > 正文

聊聊MySQL外键那些查询语句的事儿,DBA经验分享点滴总结

聊聊MySQL外键那些查询语句的事儿,DBA经验分享点滴总结 来源:根据多位DBA的社区分享、技术博客及个人实践经验整理)

今天咱们不聊外键约束该不该用的大道理,那个争论太多了,就假设你的数据库里已经用上了外键,那作为开发或者刚接触管理的DBA,怎么才能快速看清楚这些外键关系呢?总不能靠猜或者翻几个月前的设计文档吧?这篇就专门聊聊怎么用SQL语句把数据库里的外键关系给“挖”出来。

你得知道信息藏在哪儿,MySQL把数据库、表、列、外键这些对象的描述信息都放在一个叫 INFORMATION_SCHEMA 的数据库里,这个数据库是MySQL自带的,像个百宝箱,你想知道数据库内部的结构,多半都得来这儿翻找,来源中多位DBA都强调,这是最权威、最准确的信息来源,比用SHOW命令更利于进行程序化处理。

最常用的一个查询,就是想看看某个表到底被谁当成了外键引用,也就是找出它的所有“孩子”,这个场景太常见了,比如你想删除或清空一张主表,必须先知道有没有子表挂着外键指向它,不然肯定会报错,你可以用下面这个语句:

聊聊MySQL外键那些查询语句的事儿,DBA经验分享点滴总结

SELECT
    TABLE_NAME AS '子表名称',
    COLUMN_NAME AS '外键列名称',
    CONSTRAINT_NAME AS '外键约束名',
    REFERENCED_TABLE_NAME AS '父表名称',
    REFERENCED_COLUMN_NAME AS '父表列名称'
FROM
    INFORMATION_SCHEMA.KEY_COLUMN_USAGE
WHERE
    REFERENCED_TABLE_SCHEMA = '你的数据库名'
    AND REFERENCED_TABLE_NAME = '你想查看的那个主表名';

你把里面的‘你的数据库名’和‘你想查看的那个主表名’替换成实际的名字,一执行,结果就出来了,谁引用了它,用的是哪个字段,约束叫啥名,一清二楚,来源中提到,这是排查删除表失败问题时最先要跑的语句。

反过来,我想看一张表里定义了哪些外键,它引用了哪些别的表(也就是找出它的所有“父亲”),这个在你设计表或者理解业务逻辑的时候很有用,语句也很像,只是查询条件变了变:

SELECT
    CONSTRAINT_NAME AS '外键约束名',
    TABLE_NAME AS '当前表名',
    COLUMN_NAME AS '外键列名称',
    REFERENCED_TABLE_NAME AS '被引用的父表名称',
    REFERENCED_COLUMN_NAME AS '被引用的父表列名称'
FROM
    INFORMATION_SCONHEMA.KEY_COLUMN_USAGE
WHERE
    TABLE_SCHEMA = '你的数据库名'
    AND TABLE_NAME = '你想查看外键的子表名'
    AND REFERENCED_TABLE_NAME IS NOT NULL;

注意这里的条件多了一个REFERENCED_TABLE_NAME IS NOT NULL,就是为了筛选出那些确实是外键的约束。

聊聊MySQL外键那些查询语句的事儿,DBA经验分享点滴总结

光知道谁引用谁还不够,有时候你还得知道这个外键约束的详细规则,比如删除和更新的时候是啥行为?是级联删除(CASCADE)还是拒绝(RESTRICT)或者设成空(SET NULL)?这些规则是在另一个视图里存的,叫REFERENTIAL_CONSTRAINTS,你需要把两个视图关联起来查,才能拿到完整信息,来源里有个DBA分享了一个更全面的查询例子,大概长这样:

SELECT
    kcu.CONSTRAINT_NAME,
    kcu.TABLE_NAME AS '子表',
    kcu.COLUMN_NAME AS '子表列',
    kcu.REFERENCED_TABLE_NAME AS '父表',
    kcu.REFERENCED_COLUMN_NAME AS '父表列',
    rc.UPDATE_RULE,
    rc.DELETE_RULE
FROM
    INFORMATION_SCHEMA.KEY_COLUMN_USAGE kcu
JOIN INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS rc
ON kcu.CONSTRAINT_NAME = rc.CONSTRAINT_NAME
AND kcu.CONSTRAINT_SCHEMA = rc.CONSTRAINT_SCHEMA
WHERE
    kcu.TABLE_SCHEMA = '你的数据库名'
    AND kcu.REFERENCED_TABLE_NAME IS NOT NULL;

这个查询结果就丰富多了,你能看到每个外键的更新和删除规则,比如你看到DELETE_RULECASCADE,那你就得特别小心,删除父表的一条记录,子表关联的记录会跟着一起被删掉,这可是个危险操作。

除了查询INFORMATION_SCHEMA,还有一个挺直观的土办法,就是用SHOW CREATE TABLE语句,你在命令行里输入SHOW CREATE TABLE 你的表名;,它会返回创建这个表的完整SQL语句,你就能在输出结果里直接看到定义外键的那一行,包括约束名、引用关系和行为规则都明明白白地写在里面,来源中有人觉得这个方法对于快速看一眼特别方便,尤其是不想记复杂查询的时候,但缺点是结果是一大段文本,不适合用程序去自动解析。

作为DBA或者开发,把这些查询语句收藏到你的小本本里是很有必要的,当数据库越来越复杂,表越来越多的时候,这些查询就是你理清关系的“导航地图”,尤其是在做数据库变更、数据迁移或者性能分析的时候,先摸清外键的来龙去脉,能帮你避免很多意想不到的坑,毕竟,搞清楚表之间的关系,是理解业务逻辑和保证数据安全的第一步。