一个电商项目的数据库设计实践(第一部分)(附源码)

一次电商项目后台的数据库设计小结(第一部分)(附源码)

  • 1.准备工作
  • 2.用户实体
    • 2.1 用户登陆表(customer_login)
    • 2.2 用户信息表(customer_inf)
    • 2.3 用户级别表(customer_level_inf)
    • 2.4 用户地址表(customer_addr)
    • 2.5 用户积分日志表(customer_point_log)
    • 2.6 用户余额变动表(customer_balance_log)
    • 2.7 用户登录日志表(customer_login_log)
  • 3.customer_login_log分区
    • 3.1 customer_login_log表分区
    • 3.2 使用分区表的注意事项
  • 4.商品实体
    • 4.1 品牌信息表(brand_info)
    • 4.2 分类信息表(product_category)
    • 4.3 商品供应商信息表(supplier_info)
    • 4.4 商品信息表(product_info)
    • 4.5 商品图片表(product_pic_info)
    • 4.5 商品评论表(product_comment)
  • 5.订单实体
    • 5.1 订单主表(order_master)
    • 5.2 订单详情表(order_detail)
    • 5.3 购物车表(order_cart)
    • 5.4 仓库信息表(warehouse_info)
    • 5.5 商品库存表(warehouse_product)
    • 5.6 物流公司信息表(shipping_info)
  • 6. DB规划
    • 6.1 用户数据库(mc_customerdb)
    • 6.2 商品数据库(mc_productdb)
    • 6.3 订单数据库(mc_orderdb)
  • 7.各类规范小结
    • 7.1 数据库命名规范
    • 7.2 索引设计规范
    • 7.3 数据库字段设计规范
    • 7.4 SQL开发规范
    • 7.5 操作行为规范

1.准备工作

数据库:MySQL5.7(5.5、5.6皆可);
数据库客户端软件:SQLyog;
源码在Github上:https://github.com/Fateasstring/EB-SQL ,文章整理不易,请赏个star吧。

2.用户实体

用户模块用于管理和维护用户信息。把所有的用户信息放在一个表中,会容易导致:

  • 数据插入异常;
  • 数据更新异常,比如要修改某一行的值是,不得不修改多行数据;
  • 数据删除异常,删除某一数据时不得不同时删除另一数据;
  • 数据存在冗余; 数据表过宽,会影响修改表结构的效率。

第三范式(3NF)定义:一个表中的列和其它列之间,即不包含部分函数依赖关系,也不包含传递函数依赖关系,那么这个表的设计就符合第三范式。

设计方式:
用户登陆表:{登录名,密码,用户状态}
用户地址表:{省,市,区编码,地址}
用户信息表:{用户姓名,证件类型,证件号码,手机号,邮箱,性别,积分,注册时间,生日,会员级别,用户余额}

2.1 用户登陆表(customer_login)

CREATE table customer_login(customer_id int UNSIGNED AUTO_INCREMENT NOT NULL COMMENT '用户ID',login_name VARCHAR(20) NOT NULL COMMENT '用户登陆名',
password CHAR(32) not NULL COMMENT 'md5加密的密码',user_stats TINYINT NOT null DEFAULT 1 COMMENT '用户状态',modified_time timestamp NOT null 
default  CURRENT_TIMESTAMPON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',PRIMARY key pk_customerid(customer_id))engine = INNODB COMMENT = '用户登录表';

2.2 用户信息表(customer_inf)

CREATE table customer_inf(customer_inf_id int UNSIGNED AUTO_INCREMENT NOT NULL COMMENT '自增主键ID',customer_id int UNSIGNED NOT NULL COMMENT 'customer_login表的自增ID',customer_name VARCHAR(20) not null COMMENT '用户真实姓名',identity_card_type TINYINT not null 
DEFAULT 1 COMMENT '证件类型:1 身份证,2 军官证, 3 护照',identity_card_no VARCHAR(20) COMMENT '证件号码',mobile_phone int UNSIGNED COMMENT '手机号',customer_email VARCHAR(50) COMMENT '邮箱',gender CHAR(1) COMMENT '性别',user_point int NOT NULL DEFAULT 0 COMMENT '用户积分',register_time timestamp not null COMMENT '注册时间',birthday datetime COMMENT '会员生日',customer_level TINYINT NOT null 
DEFAULT 1 COMMENT '会员级别:1.普通会员,2.青铜会员,3.白银会员,4.黄金会员,5.钻石会员',user_money DECIMAL(8,2) NOT null DEFAULT 0.00 COMMENT '用户余额',modified_time timestamp NOT null 
DEFAULT CURRENT_TIMESTAMPON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',primary key pk_customerinfid (customer_inf_id))ENGINE = INNODB COMMENT '用户信息表';

2.3 用户级别表(customer_level_inf)

CREATE table customer_level_inf(customer_level TINYINT not NULL auto_increment COMMENT '会员级别ID',level_name VARCHAR(10) NOT NULL COMMENT '会员级别名称',min_point int UNSIGNED not null DEFAULT 0 COMMENT '该级别最低积分',max_point int UNSIGNED not null DEFAULT 0 COMMENT '该级别最高积分',modified_time timestamp not null 
DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',primary key pk_levelid(customer_level)  )ENGINE = INNODB COMMENT '用户级别信息表';

2.4 用户地址表(customer_addr)

CREATE TABLE customer_addr(
customer_addr_id int UNSIGNED AUTO_INCREMENTnot null COMMENT'自增主键ID',customer_id int UNSIGNED not NULL COMMENT 'customer_login表的自增ID',zip SMALLINT not null COMMENT '邮编',province SMALLINT not null COMMENT '地区表中省份的id',city SMALLINT not null COMMENT '地区表中城市的id',district SMALLINT not null COMMENT '地区表中的区id',address VARCHAR(200) not null COMMENT '具体的地址门牌号',is_default TINYINT not null COMMENT '是否默认',modified_time timestamp not null 
DEFAULT CURRENT_TIMESTAMPON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',primary key pk_customeraddid (customer_addr_id))ENGINE = INNODB COMMENT '用户地址表';

2.5 用户积分日志表(customer_point_log)

CREATE TABLE customer_point_log(point_id int UNSIGNED not null AUTO_INCREMENT COMMENT '积分日志ID',customer_id int UNSIGNED not null COMMENT '用户id',
source TINYINT UNSIGNED not null COMMENT '积分来源:0.订单,1.登陆,2.活动',refer_number int UNSIGNED not null DEFAULT 0 COMMENT '积分来源相关编号',change_point SMALLINT not null DEFAULT 0 COMMENT '变更积分数',create_time timestamp not null COMMENT '积分日志生成时间',primary key pk_point(point_id))ENGINE = INNODB COMMENT '用户积分日志表';

2.6 用户余额变动表(customer_balance_log)

CREATE table customer_balance_log(balance_id int UNSIGNED not null AUTO_INCREMENT COMMENT '余额日志id',customer_id int UNSIGNED not null COMMENT '用户id',
source TINYINT UNSIGNED not null DEFAULT 1 COMMENT '记录来源:1.订单,2.退货单',source_sn int UNSIGNED not null COMMENT '相关单据id',create_time timestamp not null DEFAULT current_timestamp COMMENT '记录生成时间',amount DECIMAL(8,2) not null DEFAULT 0.00 COMMENT '变动金额',primary key pk_balanceid (balance_id))ENGINE = INNODB COMMENT '用户余额变动表';

2.7 用户登录日志表(customer_login_log)

```sql
CREATE table customer_login_log(login_id int UNSIGNED not null AUTO_INCREMENT COMMENT '登录日志id',customer_id int UNSIGNED NOT null COMMENT '登录用户id',login_time timestamp not null COMMENT '用户登录时间',login_ip int UNSIGNED not null COMMENT '登录ip',login_type TINYINT not null COMMENT '登录类型:0.未成功,1.成功',primary key pk_loginid(login_id))ENGINE = INNODB COMMENT '用户登陆日志表'

3.customer_login_log分区

3.1 customer_login_log表分区

业务使用场景:用户登录日志表主要用于用户每次登录的记录,每次登录时会在表中增加一条日志,所以数据量增长很快。为了尽可能保持生产环境数据库不会因为日志表增长而过快增长,用户登录日志只保存一年。

1)登录日志表的分区类型及分区键

这样的场景使用范围(RANGE)分区比较适合,可以很方便删除分区范围的数据,特别时数据量大的时候会方便很多。
这里以login_time作为分区键。

2)分区后的用户登录日志表

```sql
CREATE table customer_login_log(
customer_id int UNSIGNED NOT null ,
login_time DATETIME not null ,
login_ip int UNSIGNED not null ,
login_type TINYINT not null 
)ENGINE = INNODB 
PARTITION by RANGE(YEAR(login_time))
(PARTITION p0 VALUES less than(2015),
PARTITION p1 VALUES less than(2016),
PARTITION p2 VALUES less than(2017)
);

插入数据:

INSERT into customer_login_log(customer_id, login_time, login_ip, login_type)VALUES
(1001,'2015-01-25',0,1),
(1001,'2015-07-1',0,1),
(1001,'2015-10-1',0,1),
(1001,'2016-3-1',0,1),
(1001,'2016-9-1',0,1)

表中的数据为:
在这里插入图片描述

执行下列SQL语句:

SELECT 
table_name, 
partition_name, 
partition_description, 
table_rowsFROM information_schema.`PARTITIONS`
WHERE TABLE_NAME = 'customer_login_log'

得到结果:
在这里插入图片描述
为了避免数据插入到RANGE分区失败,要做修改并添加分区的计划任务。
增加分区:

ALTER TABLE customer_login_log ADD partition (partition p4 VALUES less than(2018));

再次查询分区信息表得到结果:
在这里插入图片描述
接下来删除p0分区:

ALTER TABLE customer_login_log DROP partition p0;

再次查询分区信息表得到结果:
在这里插入图片描述
所以,可以用这种方式删除过期日志,十分便捷。

3)分区数据归档

分区数据迁移条件:

  • MySQL版本>=5.7;
  • 结构相同;
  • 归档到的数据表一定要是非分区表(非临时表);
  • 非临时表,不能有外键约束;
  • 归档引擎要是archive。

首先建立一个与分区表结构相同的非分区表,作为归档表:

CREATE table arch_customer_login_log(
customer_id int UNSIGNED NOT null ,
login_time DATETIME not null ,
login_ip int UNSIGNED not null ,
login_type TINYINT not null 
)ENGINE = INNODB 

执行命令:

SELECT *FROM customer_login_log;

可以看到数据在customer_login_log中的情况:
在这里插入图片描述
现在将这些数据交换到归档表中:

ALTER TABLE customer_login_log exchange PARTITION p1 WITH TABLE arch_customer_login_log;

现在查看customer_login_log中2016年之前的数据:
在这里插入图片描述
查看arch_customer_login_log:
在这里插入图片描述
可以看到2016前的数据已经迁移到arch_customer_login_log归档表中了。
此时customer_login_log中的p1分区依旧是是存在的,所以需要对分区p1进行删除:

ALTER TABLE customer_login_log DROP partition p1;

再一次查看customer_login_log中的分区:

SELECT 
table_name, partition_name, partition_description, table_rowsFROM 
information_schema.`PARTITIONS`WHERE 
TABLE_NAME = 'customer_login_log'

在这里插入图片描述
可以看到p1分区已经没有了。
最后arch_customer_login_log改为使用归档引擎archive:

ALTER TABLE arch_customer_login_log ENGINE=archive;

这样能就完成了整个归档操作。而使用archive引擎的好处是,它比innodb引擎占用的空间更小。但是归档引擎中的表只能进行查询操作,不能进行写操作。

3.2 使用分区表的注意事项

  • 结合业务场景选择分区,避免跨分区查询;
  • 对分区表进行查询最好在where从句中包含分区键;
  • 具有主键或唯一索引的表,主键或唯一索引必须是分区键的一部分;

4.商品实体

商品实体包含的信息如下:
在这里插入图片描述
将这些信息分类存储在以下几个表中。

4.1 品牌信息表(brand_info)

create table brand_info(brand_id SMALLINT unsigned auto_increment not NULL COMMENT '品牌id',brand_name VARCHAR(50) not null COMMENT '品牌名称',telephone VARCHAR(50) not null COMMENT '联系电话',brand_web VARCHAR(100) COMMENT '品牌网站',brand_logo VARCHAR(100) COMMENT '品牌logo URL',brand_desc VARCHAR(150) COMMENT '品牌描述',brand_status TINYINT not NULL DEFAULT 0 COMMENT '品牌状态,0.禁用,1.启用',brand_order TINYINT not null DEFAULT 0 COMMENT '排序',modified_time timestamp not null 
DEFAULT CURRENT_TIMESTAMP on UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',PRIMARY key pk_brandid (brand_id)
)ENGINE = INNODB COMMENT'品牌信息表'

4.2 分类信息表(product_category)

CREATE TABLE product_category(
category_id SMALLINT UNSIGNED auto_increment not NULL COMMENT '分类id',category_name VARCHAR(10) not NULL COMMENT '分类名称',category_code VARCHAR(10) not NULL COMMENT '分类编码',parent_id SMALLINT UNSIGNED not null DEFAULT 0 COMMENT '父分类id',category_level TINYINT not null DEFAULT 1 COMMENT '分类层级',category_status TINYINT not null DEFAULT 1 COMMENT '分类状态',modified_time timestamp not null 
DEFAULT CURRENT_TIMESTAMP on UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',PRIMARY key pk_categoryid(category_id)
)ENGINE = INNODB COMMENT '商品分类';

4.3 商品供应商信息表(supplier_info)

CREATE table supplier_info(
supplier_id int UNSIGNED auto_increment not null COMMENT '供应商id',supplier_code CHAR(8) not null COMMENT '供应商编码',supplier_name CHAR(50) not NULL COMMENT '供应商名称',supplier_type TINYINT not NULL COMMENT '供应商类型:1.自营,2.平台',link_man VARCHAR(10) not NULL COMMENT '供应商联系人',phone_number VARCHAR(50) not null COMMENT '联系电话',bank_name VARCHAR(50) not NULL COMMENT '供应商开户银行名称',bank_account VARCHAR(50) not null COMMENT '银行账号',address VARCHAR(200) not null COMMENT '供应商地址',supplier_status TINYINT not null DEFAULT '0' COMMENT '状态:0.禁用,1.启用',modified_time timestamp not null 
DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',PRIMARY key pk_supplierid (supplier_id)
)ENGINE = INNODB COMMENT '供应商信息表';

4.4 商品信息表(product_info)

DROP TABLE IF EXISTS `product_info`;/*!40101 SET @saved_cs_client     = @@character_set_client */;/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `product_info` (`product_id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '商品ID',`product_code` char(16) NOT NULL COMMENT '商品编码',`product_name` varchar(50) NOT NULL COMMENT '商品名称',`bar_code` varchar(50) NOT NULL COMMENT '国条码',`brand_id` int(10) unsigned NOT NULL COMMENT '品牌表的ID',`one_category_id` smallint(5) unsigned NOT NULL COMMENT '一级分类ID',`two_category_id` smallint(5) unsigned NOT NULL COMMENT '二级分类ID',`three_category_id` smallint(5) unsigned NOT NULL COMMENT '三级分类ID',`supplier_id` int(10) unsigned NOT NULL COMMENT '商品的供应商id',`price` decimal(8,2) NOT NULL COMMENT '商品销售价格',`average_cost` decimal(18,2) NOT NULL COMMENT '商品加权平均成本',`publish_status` tinyint(4) NOT NULL DEFAULT '0' COMMENT '上下架状态:0下架1上架',`audit_status` tinyint(4) NOT NULL DEFAULT '0' COMMENT '审核状态:0未审核,1已审核',`weight` float DEFAULT NULL COMMENT '商品重量',`length` float DEFAULT NULL COMMENT '商品长度',`heigh` float DEFAULT NULL COMMENT '商品高度',`width` float DEFAULT NULL COMMENT '商品宽度',`color_type` enum('红','黄','蓝','黒') DEFAULT NULL,`production_date` datetime NOT NULL COMMENT '生产日期',`shelf_life` int(11) NOT NULL COMMENT '商品有效期',`descript` text NOT NULL COMMENT '商品描述',`indate` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '商品录入时间',`modified_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',PRIMARY KEY (`product_id`)) ENGINE=InnoDB AUTO_INCREMENT=262141 DEFAULT CHARSET=utf8 COMMENT='商品信息表';

4.5 商品图片表(product_pic_info)

DROP TABLE IF EXISTS `product_pic_info`;
/*!40101 SET @saved_cs_client     
= @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `product_pic_info` (`product_pic_id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '商品图片ID',`product_id` int(10) unsigned NOT NULL COMMENT '商品ID',`pic_desc` varchar(50) DEFAULT NULL COMMENT '图片描述',`pic_url` varchar(200) NOT NULL COMMENT '图片URL',`is_master` tinyint(4) NOT NULL DEFAULT '0' COMMENT '是否主图:0.非主图1.主图',`pic_order` tinyint(4) NOT NULL DEFAULT '0' COMMENT '图片排序',`pic_status` tinyint(4) NOT NULL DEFAULT '1' COMMENT '图片是否有效:0无效 1有效',`modified_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',PRIMARY KEY (`product_pic_id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='商品图片信息表';

图片,小视频等数据,是不能直接存在MySQL数据库里的,而是存在专门的图片服务器,文件服务器或者CDN上,并把相应的地址信息存储在MySQL数据库中。

4.5 商品评论表(product_comment)

DROP TABLE IF EXISTS `product_comment`;
/*!40101 SET @saved_cs_client     
= @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `product_comment` (`comment_id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '评论ID',`product_id` int(10) unsigned NOT NULL COMMENT '商品ID',`order_id` bigint(20) unsigned NOT NULL COMMENT '订单ID',`customer_id` int(10) unsigned NOT NULL COMMENT '用户ID',`title` varchar(50) NOT NULL COMMENT '评论标题',`content` varchar(300) NOT NULL COMMENT '评论内容',`audit_status` tinyint(4) NOT NULL COMMENT '审核状态:0未审核1已审核',`audit_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '评论时间',`modified_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',PRIMARY KEY (`comment_id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='商品评论表';

5.订单实体

订单实体包含如下信息:

在这里插入图片描述

5.1 订单主表(order_master)

DROP TABLE IF EXISTS `order_master`;
/*!40101 SET @saved_cs_client     
= @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `order_master` (`order_id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '订单ID',`order_sn` bigint(20) unsigned NOT NULL COMMENT '订单编号 yyyymmddnnnnnnnn',`customer_id` int(10) unsigned NOT NULL COMMENT '下单人ID',`shipping_user` varchar(10) NOT NULL COMMENT '收货人姓名',`province` smallint(6) NOT NULL COMMENT '收货人所在省',`city` smallint(6) NOT NULL COMMENT '收货人所在市',`district` smallint(6) NOT NULL COMMENT '收货人所在区',`address` varchar(100) NOT NULL COMMENT '收货人详细地址',`payment_method` tinyint(4) NOT NULL COMMENT '支付方式:1现金,2余额,3网银,4支付宝,5微信',`order_money` decimal(8,2) NOT NULL COMMENT '订单金额',`district_money` decimal(8,2) NOT NULL DEFAULT '0.00' COMMENT '优惠金额',`shipping_money` decimal(8,2) NOT NULL DEFAULT '0.00' COMMENT '运费金额',`payment_money` decimal(8,2) NOT NULL DEFAULT '0.00' COMMENT '支付金额',`shipping_comp_name` varchar(10) DEFAULT NULL COMMENT '快递公司名称',`shipping_sn` varchar(50) DEFAULT NULL COMMENT '快递单号',`create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '下单时间',`shipping_time` datetime DEFAULT NULL COMMENT '发货时间',`pay_time` datetime DEFAULT NULL COMMENT '支付时间',`receive_time` datetime DEFAULT NULL COMMENT '收货时间',`order_status` tinyint(4) NOT NULL DEFAULT '0' COMMENT '订单状态',`order_point` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '订单积分',`invoice_title` varchar(100) DEFAULT NULL COMMENT '发票抬头',`modified_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',PRIMARY KEY (`order_id`),UNIQUE KEY `ux_ordersn` (`order_sn`)
) ENGINE=InnoDB AUTO_INCREMENT=10011 
DEFAULT CHARSET=utf8 COMMENT='订单主表';
/*!40101 SET character_set_client = @saved_cs_client */;

订单主表是非常重要的表,关系到所有经营的行为活动。

5.2 订单详情表(order_detail)

DROP TABLE IF EXISTS `order_detail`;
/*!40101 SET @saved_cs_client     
= @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `order_detail` (`order_detail_id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主键ID,订单详情表ID',`order_id` int(10) unsigned NOT NULL COMMENT '订单表ID',`product_id` int(10) unsigned NOT NULL COMMENT '订单商品ID',`product_name` varchar(50) NOT NULL COMMENT '商品名称',`product_cnt` int(11) NOT NULL DEFAULT '1' COMMENT '购买商品数量',`product_price` decimal(8,2) NOT NULL COMMENT '购买商品单价',`average_cost` decimal(8,2) NOT NULL DEFAULT '0.00' COMMENT '平均成本价格',`weight` float DEFAULT NULL COMMENT '商品重量',`fee_money` decimal(8,2) NOT NULL DEFAULT '0.00' COMMENT '优惠分摊金额',`w_id` int(10) unsigned NOT NULL COMMENT '仓库ID',`modified_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',PRIMARY KEY (`order_detail_id`)
) ENGINE=InnoDB AUTO_INCREMENT=29698 
DEFAULT CHARSET=utf8 COMMENT='订单详情表';
/*!40101 SET character_set_client = @saved_cs_client */;

5.3 购物车表(order_cart)

DROP TABLE IF EXISTS `order_cart`;
/*!40101 SET @saved_cs_client    = @@character_set_client */;/*!40101 SET character_set_client = utf8 */;CREATE TABLE `order_cart` (`cart_id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '购物车ID',`customer_id` int(10) unsigned NOT NULL COMMENT '用户ID',`product_id` int(10) unsigned NOT NULL COMMENT '商品ID',`product_amount` int(11) NOT NULL COMMENT '加入购物车商品数量',`price` decimal(8,2) NOT NULL COMMENT '商品价格',`add_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '加入购物车时间',`modified_time` timestamp NOT NULLDEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',PRIMARY KEY (`cart_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='购物车表';
/*!40101 SET character_set_client = @saved_cs_client */;

5.4 仓库信息表(warehouse_info)

DROP TABLE IF EXISTS `warehouse_info`;
/*!40101 SET @saved_cs_client     
= @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `warehouse_info` (`w_id` smallint(5) unsigned NOT NULL AUTO_INCREMENT COMMENT '仓库ID',`warehouse_sn` char(5) NOT NULL COMMENT '仓库编码',`warehouse_name` varchar(10) NOT NULL COMMENT '仓库名称',`warehouse_phone` varchar(20) NOT NULL COMMENT '仓库电话',`contact` varchar(10) NOT NULL COMMENT '仓库联系人',`province` smallint(6) NOT NULL COMMENT '省',`city` smallint(6) NOT NULL COMMENT '市',`district` smallint(6) NOT NULL COMMENT '区',`address` varchar(100) NOT NULL COMMENT '仓库地址',`warehouse_status` tinyint(4) NOT NULL DEFAULT '1' COMMENT '仓库状态:0禁用,1启用',`modified_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',PRIMARY KEY (`w_id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 
DEFAULT CHARSET=utf8 COMMENT='仓库信息表';
/*!40101 SET character_set_client = @saved_cs_client */;

5.5 商品库存表(warehouse_product)

DROP TABLE IF EXISTS `warehouse_product`;
/*!40101 SET @saved_cs_client     
= @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `warehouse_product` (`wp_id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '商品库存ID',`product_id` int(10) unsigned NOT NULL COMMENT '商品id',`w_id` smallint(5) unsigned NOT NULL COMMENT '仓库ID',`currnet_cnt` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '当前商品数量',`lock_cnt` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '当前占用数据',`in_transit_cnt` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '在途数据',`average_cost` decimal(8,2) NOT NULL DEFAULT '0.00' COMMENT '移动加权成本',`modified_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',PRIMARY KEY (`wp_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='商品库存表';
/*!40101 SET character_set_client = @saved_cs_client */;

5.6 物流公司信息表(shipping_info)

DROP TABLE IF EXISTS `shipping_info`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `shipping_info` (`ship_id` tinyint(3) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键id',`ship_name` varchar(20) NOT NULL COMMENT '物流公司名称',`ship_contact` varchar(20) NOT NULL COMMENT '物流公司联系人',`telphone` varchar(20) NOT NULL COMMENT '物流公司联系电话',`price` decimal(8,2) NOT NULL DEFAULT '0.00' COMMENT '配送价格',`modified_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',PRIMARY KEY (`ship_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='物流公司信息表';

6. DB规划

从以下角度考虑:

  • 为以后数据库迁移和拆分提供方便;
  • 避跨库操作,把经常一起关联查询的表放在一个DB中;
  • 为了方便识别表所在的DB,在表名前面增加库名前缀。

6.1 用户数据库(mc_customerdb)

包含:

  • customer_inf
  • customer_login
  • customer_level_inf
  • customer_login_log
  • customer_point_log
  • customer_balance_log

6.2 商品数据库(mc_productdb)

包含:

  • product_info
  • product_pic_info
  • product_category
  • product_supplier_info
  • product_comment
  • product_brand_info

6.3 订单数据库(mc_orderdb)

  • order_master
  • order_detail
  • order_customer_addr
  • warehouse_info
  • shipping_info
  • order_cart
  • warehouse_product

在接下来文章中会在MySQL数据库创建这些数据库。

7.各类规范小结

7.1 数据库命名规范

  • 所有数据库对像名称必须使用小写字母并用下划线分割,MySQL大小写敏感;
  • 所有数据库对像名称禁止使用MySQL保留关键字;
  • 数据库对像的命名要能做到见名识义,尽量不要超过32个字符;
  • 临时库表必须以tmp为前缀,以日期为后缀;
  • 备份库,备份表必须以bak为前缀并,日期为后缀;
  • 所有存储相同数据的列名和列类型必须一致;
  • 所有表尽量使用Innodb存储引擎;
  • 数据库和表的字符集统一使用UTF8(兼容性更好),避免由于字符集转换产生乱码;
  • 所有的表和字段都需要添加注释,使用comment从句添加表和列的备注,从一开始就进行数据字典的维护;
  • 尽量控制单表数据量的大小,建议控制在500万以内,否则修改表结构、备份、恢复都会有很大问题;
  • 谨慎使用MySQL分区表,分区表在物理上表现为多个文件,在逻辑上表现为一个表;
  • 谨慎选择分区键,跨分区查询效率可能更低,建议使用物理分表的方式管理大量数据;
  • 尽量做到冷热数据分离,减小表的宽度,MySQL对行数没有限制,但限制最多存储4096列;
  • 经常一起使用的列放在一个表中;
  • 禁止在表中建立预留字段,预留字段的命名很难做到见名识义,对于预留字段的类型修改会对表进行锁定;
  • 禁止在数据库中存储图片、文件等二进制数据;
  • 禁止在线上做数据库压力测试;
  • 禁止从开发环境、测试环境直连生产环境数据库。

5.6以后的默认引擎支持事务,行级锁,更好的恢复性,高并发下性能更好。可以利用历史数据归档,分库分表来控制数据量大小。

7.2 索引设计规范

  • 限制每张表上的索引列数量,单张表索引尽量不要超过5个;
  • 避免建立冗余索引和重复索引;
  • 禁止给表中的每一列都建立单独的索引;
  • 每个Innodb表必须有一个主键;
  • 不使用更新频繁的列作为主键,不适用多列主键;
  • 不使用UUID、MD5、HASH字符串列作为主键;
  • 主键建议选择使用自增ID值;
  • 对于频繁的查询优先考虑使用覆盖索引,避免Innodb表进行索引的二次查找;
  • 尽量避免使用外键约束(通常是表与表之间的关联键),但一定在表与表之间的关联键上建立索引;
  • 索引可以增加查询效率,但同样也会降低插入和更新的效率。

Innodb是按照主键来组织表的。

面试问题:要在哪些列上建立索引?
答:通常使用SELECT、UPDATE、DELETE语句中的where从句中的列,包含在ORDER BY、GROUP BY、DISTINCT中的字段,多表JOIN的关联列。

面试问题:如何选择索引列的顺序?
答:把区分度最高的列(主键)放在能够在联合索引的最左侧,其实尽量把字段长度小的列放在联合索引的最左侧,使用最频繁的列放到联合索引的左侧。

7.3 数据库字段设计规范

  • 优先选择符合存储需要的最小的数据类型;
  • 避免使用TEXT、BLOB数据类型,若要使用,则把BLOB或TEXT分离到单独的扩展表中;
  • 避免使用ENUM数据类型;
  • 禁止使用数值作为ENUM的枚举值;
  • 尽可能把所有的列定义为NOT NULL;
  • 使用TIMESTAMP或DATETIME类型存储时间;
  • 同财务相关的金额类数据,必须使用decimal类型。

7.4 SQL开发规范

  • 建议使用预编译语句进行数据库操作;
  • 避免数据类型的隐式转换;
  • 程序连接不同的数据库使用不同的账号,禁止跨库查询;
  • 禁止使用不含字段列表的INSERT语句;
  • 避免使用子查询,可以把子查询优化为join操作,子查询的结果集无法使用索引;
  • 避免使用JOIN关联太多的表;
  • 尽量减少与数据库的交互次数;
  • 禁止使用order by rand()进行随机排序;
  • where从句中禁止对列进行函数转换和计算;
  • 在明显不会有重复值是使用union all 而不是union;
  • 拆分复杂的大SQL为多个小SQL。

7.5 操作行为规范

  • 超100万行的批量写操作,要分批多次进行操作;
  • 对于大表使用pt-online-schema-change修改表结构;
  • 禁止为程序使用的账号赋予super权限;
  • 对于程序连接数据库账号,遵循权限最小原则。


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部