MYSQL使用外键进行优化

假如你是京东的数据库管理员,你现在管理着这样一个数据库。

mysql> select * from goods;
+----+---------------------------------------+---------------------+------------+-----------+---------+------------+
| id | name                                  | cate_name           | brand_name | price     | is_show | is_saleoff |
+----+---------------------------------------+---------------------+------------+-----------+---------+------------+
|  1 | r510vc 15.6英寸笔记本                 | 笔记本              | 华硕       |  3399.000 |        |            |
|  2 | y400n 14.0英寸笔记本电脑              | 笔记本              | 联想       |  4999.000 |        |            |
|  3 | g150th 15.6英寸游戏本                 | 游戏本              | 雷神       |  8499.000 |        |            |
|  4 | x550cc 15.6英寸笔记本                 | 笔记本              | 华硕       |  2799.000 |        |            |
|  5 | x240 超极本                           | 超级本              | 联想       |  4880.000 |        |            |
|  6 | u330p 13.3英寸超极本                  | 超级本              | 联想       |  4299.000 |        |            |
|  7 | svp13226scb 触控超极本                | 超级本              | 索尼       |  7999.000 |        |            |
|  8 | ipad mini 7.9英寸平板电脑             | 平板电脑            | 苹果       |  1998.000 |        |            |
|  9 | ipad air 9.7英寸平板电脑              | 平板电脑            | 苹果       |  3388.000 |        |            |
| 10 | ipad mini 配备 retina 显示屏          | 平板电脑            | 苹果       |  2788.000 |        |            |
| 11 | ideacentre c340 20英寸一体电脑        | 台式机              | 联想       |  3499.000 |        |            |
| 12 | vostro 3800-r1206 台式电脑            | 台式机              | 戴尔       |  2899.000 |        |            |
| 13 | imac me086ch/a 21.5英寸一体电脑       | 台式机              | 苹果       |  9188.000 |        |            |
| 14 | at7-7414lp 台式电脑 linux )          | 台式机              | 宏碁       |  3699.000 |        |            |
| 15 | z220sff f4f06pa工作站                 | 服务器/工作站       | 惠普       |  4288.000 |        |            |
| 16 | poweredge ii服务器                    | 服务器/工作站       | 戴尔       |  5388.000 |        |            |
| 17 | mac pro专业级台式电脑                 | 服务器/工作站       | 苹果       | 28888.000 |        |            |
| 18 | hmz-t3w 头戴显示设备                  | 笔记本配件          | 索尼       |  6999.000 |        |            |
| 19 | 商务双肩背包                          | 笔记本配件          | 索尼       |    99.000 |        |            |
| 20 | x3250 m4机架式服务器                  | 服务器/工作站       | ibm        |  6888.000 |        |            |
| 21 | 商务双肩背包                          | 笔记本配件          | 索尼       |    99.000 |        |            |
+----+---------------------------------------+---------------------+------------+-----------+

某一天,你boss叫你把商品类型改一下。台式机改为台式电脑。

这时候,你要怎么改呢?

update goods set cate_name="台式电脑" where cate_name='台式机';
???

这样的话,数据表的内部要向查找商品类型为台式机的行,然后再改。改完再找,再改......

这里只是一个示例,只有21条数据。京东上十万百万条数据,这样子操作数据库不忙吗?要知道现在web开发瓶颈都在数据库啊,还要数据库做这么多的工作,你良心不会痛吗?

那么?我要怎么修改呢?

大体思路:我们创建一个商品类型表。然后在goods表设置外键,商品类型用数字来表示。1对应商品类型表的平板电脑,2对应商品类型表的台式机......当我们要修改商品类型是,直接修改商品类型表即可。

1.创建商品类型表

create table if not exists goods_cates(id int unsigned primary key auto_increment,name varchar(40) not null);

2.将商品信息表的商品类型同步到商品类型表

# 注意! 把查询出来的结果写入表的单个字段,不需要加values
insert into goods_cates(name) select distinct cate_name from goods;
select * from goods_cates;
+----+---------------------+
| id | name                |
+----+---------------------+
|  1 | 笔记本              |
|  2 | 游戏本              |
|  3 | 超级本              |
|  4 | 平板电脑            |
|  5 | 台式机              |
|  6 | 服务器/工作站       |
|  7 | 笔记本配件          |
+----+---------------------+

 3.将商品信息表的商品类型替换为商品类型表的id

mysql> update goods as g inner join goods_cates as c on g.cate_name=c.name set g.cate_name=c.id;
mysql> select * from goods;
+----+---------------------------------------+-----------+------------+-----------+---------+------------+
| id | name                                  | cate_name | brand_name | price     | is_show | is_saleoff |
+----+---------------------------------------+-----------+------------+-----------+---------+------------+
|  1 | r510vc 15.6英寸笔记本                 | 1         | 华硕       |  3399.000 |        |            |
|  2 | y400n 14.0英寸笔记本电脑              | 1         | 联想       |  4999.000 |        |            |
|  3 | g150th 15.6英寸游戏本                 | 2         | 雷神       |  8499.000 |        |            |
|  4 | x550cc 15.6英寸笔记本                 | 1         | 华硕       |  2799.000 |        |            |
|  5 | x240 超极本                           | 3         | 联想       |  4880.000 |        |            |
|  6 | u330p 13.3英寸超极本                  | 3         | 联想       |  4299.000 |        |            |
|  7 | svp13226scb 触控超极本                | 3         | 索尼       |  7999.000 |        |            |
|  8 | ipad mini 7.9英寸平板电脑             | 4         | 苹果       |  1998.000 |        |            |
|  9 | ipad air 9.7英寸平板电脑              | 4         | 苹果       |  3388.000 |        |            |
| 10 | ipad mini 配备 retina 显示屏          | 4         | 苹果       |  2788.000 |        |            |
| 11 | ideacentre c340 20英寸一体电脑        | 5         | 联想       |  3499.000 |        |            |
| 12 | vostro 3800-r1206 台式电脑            | 5         | 戴尔       |  2899.000 |        |            |
| 13 | imac me086ch/a 21.5英寸一体电脑       | 5         | 苹果       |  9188.000 |        |            |
| 14 | at7-7414lp 台式电脑 linux )          | 5         | 宏碁       |  3699.000 |        |            |
| 15 | z220sff f4f06pa工作站                 | 6         | 惠普       |  4288.000 |        |            |
| 16 | poweredge ii服务器                    | 6         | 戴尔       |  5388.000 |        |            |
| 17 | mac pro专业级台式电脑                 | 6         | 苹果       | 28888.000 |        |            |
| 18 | hmz-t3w 头戴显示设备                  | 7         | 索尼       |  6999.000 |        |            |
| 19 | 商务双肩背包                          | 7         | 索尼       |    99.000 |        |            |
| 20 | x3250 m4机架式服务器                  | 6         | ibm        |  6888.000 |        |            |
| 21 | 商务双肩背包                          | 7         | 索尼       |    99.000 |        |            |
+----+---------------------------------------+-----------+------------+-----------+---------+------------+

4.这时要注意,商品信息表的数据类型还是原数据类型,但是商品信息表的商品类型已经变为整形,所以我们需要更改一下商品信息表的表结构。

mysql> alter table goods change cate_name cate_id int unsigned not null;

5.添加外键,让cate_id是有含义的。

# 添加外键,指向goods_cates表的id字段
mysql> alter table goods add foreign key(cate_id) references goods_cates(id);
mysql> show create table goods;
+-------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table | Create Table                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               |
+-------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| goods | CREATE TABLE `goods` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(150) NOT NULL,
  `cate_id` int(10) unsigned NOT NULL,
  `brand_name` varchar(40) NOT NULL,
  `price` decimal(10,3) NOT NULL DEFAULT '0.000',
  `is_show` bit(1) NOT NULL DEFAULT b'1',
  `is_saleoff` bit(1) NOT NULL DEFAULT b'0',
  PRIMARY KEY (`id`),
  KEY `cate_id` (`cate_id`),
  CONSTRAINT `goods_ibfk_1` FOREIGN KEY (`cate_id`) REFERENCES `goods_cates` (`id`)  # 这句就是外键的设置
) ENGINE=InnoDB AUTO_INCREMENT=22 DEFAULT CHARSET=utf8 |
+-------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+

注意:当数据没有满足外键约束时,无法添加外键!要把没有满足外键约束的行删除才能添加外键。

这样,就完成boss的任务啦。如果要改商品类型的名字,直接在商品类型表改就可以啦~数据库也少了很多负担。

*拓展一下,外键的删除。

mysql> alter table goods drop foreign key goods_ibfk_1;
mysql> show create table goods;
+-------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table | Create Table                                                                                                                                                                                                                                                                                                                                                                                                                          |
+-------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| goods | CREATE TABLE `goods` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(150) NOT NULL,
  `cate_id` int(10) unsigned NOT NULL,
  `brand_name` varchar(40) NOT NULL,
  `price` decimal(10,3) NOT NULL DEFAULT '0.000',
  `is_show` bit(1) NOT NULL DEFAULT b'1',
  `is_saleoff` bit(1) NOT NULL DEFAULT b'0',
  PRIMARY KEY (`id`),
  KEY `cate_id` (`cate_id`)
) ENGINE=InnoDB AUTO_INCREMENT=22 DEFAULT CHARSET=utf8 |
+-------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+

但是!商品信息表还有一个小问题!

如果这个表格主要是查询不怎么会影响效率。
但是如果需要频繁的插入,修改,删除,则会有很大的影响。因为有外键约束,mysql会自己去检测是否符合规则。

如果你要插入十万条数据,mysql会一条一条去检测插入的数据是否满足外键约束。会极大的降低表更新的效率。

这样一来,数据库的工作又沉重了。

那么又应该怎么解决呢?

1.可在数据录入时验证(表示层,ui层),例如网页的选项。

2.在业务层面(python代码)去验证,代码判断输入数据的正确性。

3.不要数据库层面去验证!数据库直接插入,不要外键!前面两个方法任意一个都可以保证插入的数据满足要求。


个人的经验是在一些不常常改变数据的小表上,又是比较基础的数据上使用外键。

猜你喜欢

转载自www.cnblogs.com/chichung/p/9589257.html