垂直分表、水平分表详解

这篇具有很好参考价值的文章主要介绍了垂直分表、水平分表详解。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

垂直分表

什么是垂直分表

垂直分表就是把一张表按列分为多张表,多张表通过主键进行关联,从而组成完整的数据。

分表之后,每张表的结构都不相同。

垂直分表不需要额外引用其他组件,需要到Repository层面建立好表映射即可。

根据什么分表呢?

根据数据是否是热点数据划分。

热点数据即经常查询、更新频繁的列。

例如一个订单状态信息会频繁进行更新、订单金额在列表会频繁被查询到作为热点数据,而下单地址、手机号码等信息基本不会改变或者改变次数很少作为非热点数据。

垂直分表有哪些好处呢?

  1. 把热点数据分离,更新的性能更加高;
  2. 减少行数据,数据库IO效率高;
  3. 业务所有数据存在一个或者多个表,管理后台聚合查询(走从库)比较方便。

垂直分表实战

例如我们有一张外卖的表,全表结构如下:

CREATE TABLE `meal_order` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
  `trade_no` varchar(128) NOT NULL DEFAULT '' COMMENT '交易流水号',
  `order_id` bigint(20) NOT NULL COMMENT '订单ID',
  `order_type` tinyint(4) NOT NULL COMMENT '外卖类型:4:外卖;1:买单;3:团购',
  `order_status` tinyint(4) NOT NULL COMMENT '订单状态:1:未付款;2:已付款;4:部分退款;5:已退款;6:已完成;-1:已取消',
  `delivery_status` int(11) DEFAULT NULL COMMENT '配送状态:0:默认;0:已推送给配送方;10:已抢单;20:已取餐;40:已送达;100:已取消',
  `consumption_type` tinyint(4) NOT NULL DEFAULT '1' COMMENT '类型,1=个人,2=商务',
  `user_sn` bigint(20) NOT NULL COMMENT 'userSn',
  `employee_sn` bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT '员工SN',
  `enterprise_sn` varchar(20) NOT NULL DEFAULT '' COMMENT '企业编号',
  `order_amount` decimal(12,2) NOT NULL DEFAULT '0.00' COMMENT '订单总价',
  `order_pay_amount` decimal(12,2) NOT NULL DEFAULT '0.00' COMMENT '订单支付价格',
  `shipping_fee` decimal(12,2) DEFAULT NULL COMMENT '订单配送费(原始配送费)',
  `service_fee` decimal(12,2) DEFAULT NULL COMMENT '服务费',
  `ent_service_fee` decimal(15,2) NOT NULL DEFAULT '0.00' COMMENT '企业服务费',
  `ent_service_fee_ratio` decimal(15,2) DEFAULT NULL COMMENT '企业服务费比例',
  `order_time` datetime DEFAULT NULL COMMENT '下单时间',
  `latest_refund_time` datetime DEFAULT NULL COMMENT '最后退款时间',
  `pay_expire_at` datetime DEFAULT NULL COMMENT '支付之后有效时间',
  `pay_time` datetime DEFAULT NULL COMMENT '支付时间',
  `pay_type` tinyint(4) DEFAULT NULL COMMENT '支付方式 1-微信支付,2-支付宝支付,3-骑士币支付,31-骑士币+微信支付,32-骑士币+支付宝支付',
  `pay_status` tinyint(4) NOT NULL COMMENT '支付状态',
  `shop_name` varchar(128) DEFAULT NULL COMMENT '商家名',
  `shop_phone` varchar(100) DEFAULT NULL COMMENT '商家电话,多个,隔开',
  `shop_address` varchar(300) DEFAULT NULL COMMENT '商家地址',
  `estimate_arrive_time` datetime DEFAULT NULL COMMENT '预计送达时间',
  `actual_arrive_time` datetime DEFAULT NULL COMMENT '实际送达时间',
  `outer_order_id` varchar(100) NOT NULL COMMENT '外部订单ID',
  `outer_order_status` int(11) DEFAULT NULL COMMENT '外部订单状态',
  `recipient_name` varchar(64) DEFAULT NULL COMMENT '收货人姓名',
  `recipient_phone` varchar(64) DEFAULT NULL COMMENT '收货人手机号',
  `recipient_address` varchar(128) DEFAULT NULL COMMENT '收货地址',
  `recipient_address_longitude` varchar(50) DEFAULT NULL COMMENT '收货地址经度  实际值需要除以 10^6 进行换算',
  `recipient_address_latitude` varchar(50) DEFAULT NULL COMMENT '收货地址维度	实际值需要除以 10^6 进行换算',
  `notify_url` varchar(500) DEFAULT NULL COMMENT '渠道服务器主动通知外部服务器里指定的页面路径',
  `return_url` varchar(500) DEFAULT NULL COMMENT '操作成功跳转地址',
  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  `version` bigint(20) DEFAULT '0' COMMENT '版本号',
  PRIMARY KEY (`id`),
  UNIQUE KEY `uniq_order_id` (`order_id`),
  KEY `idx_employee_sn` (`employee_sn`),
  KEY `idx_order_id` (`outer_order_id`),
  KEY `idx_trade_no` (`trade_no`),
  KEY `idx_user_sn` (`user_sn`),
  KEY `idx_create_time_status` (`create_time`,`order_status`)
) ENGINE=InnoDB AUTO_INCREMENT=406 DEFAULT CHARSET=utf8mb4 COMMENT='外卖订单表'

表中的字段很多,如果只是获取其中某些列,数据库也需要把整行加载到内存再截取某些列,这样自然增加了IO成本。

在外卖订单里面,订单ID、订单状态、配送状态、用户Sn、支付状态等经常更新和在订单列表查询到,作为热点数据。

企业信息、服务费、商家信息、收货人信息等更新频率极低,并且只在订单详情查询,作为非热点数据。

外卖订单表垂直拆分如下:

CREATE TABLE `meal_order` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
  `order_id` bigint(20) NOT NULL COMMENT '订单ID',
  `order_type` tinyint(4) NOT NULL COMMENT '外卖类型:4:外卖;1:买单;3:团购',
  `order_status` tinyint(4) NOT NULL COMMENT '订单状态:1:未付款;2:已付款;4:部分退款;5:已退款;6:已完成;-1:已取消',
  `delivery_status` int(11) DEFAULT NULL COMMENT '配送状态:0:默认;0:已推送给配送方;10:已抢单;20:已取餐;40:已送达;100:已取消',
  `user_sn` bigint(20) NOT NULL COMMENT 'userSn',
  `order_amount` decimal(12,2) NOT NULL DEFAULT '0.00' COMMENT '订单总价',
  `order_pay_amount` decimal(12,2) NOT NULL DEFAULT '0.00' COMMENT '订单支付价格',
  `order_time` datetime DEFAULT NULL COMMENT '下单时间',
  `pay_expire_at` datetime DEFAULT NULL COMMENT '支付之后有效时间',
  `pay_time` datetime DEFAULT NULL COMMENT '支付时间',
  `pay_type` tinyint(4) DEFAULT NULL COMMENT '支付方式 1-微信支付,2-支付宝支付,3-骑士币支付,31-骑士币+微信支付,32-骑士币+支付宝支付',
  `pay_status` tinyint(4) NOT NULL COMMENT '支付状态',
  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  `version` bigint(20) DEFAULT '0' COMMENT '版本号',
  PRIMARY KEY (`id`),
  UNIQUE KEY `uniq_order_id` (`order_id`),
  KEY `idx_user_sn` (`user_sn`),
  KEY `idx_create_time_status` (`create_time`,`order_status`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='外卖订单表';

CREATE TABLE `meal_order_attach` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
  `trade_no` varchar(128) NOT NULL DEFAULT '' COMMENT '交易流水号',
  `order_id` bigint(20) NOT NULL COMMENT '订单ID',
  `consumption_type` tinyint(4) NOT NULL DEFAULT '1' COMMENT '类型,1=个人,2=商务',
  `employee_sn` bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT '员工SN',
  `enterprise_sn` varchar(20) NOT NULL DEFAULT '' COMMENT '企业编号',
  `shipping_fee` decimal(12,2) DEFAULT NULL COMMENT '订单配送费(原始配送费)',
  `service_fee` decimal(12,2) DEFAULT NULL COMMENT '服务费',
  `ent_service_fee` decimal(15,2) NOT NULL DEFAULT '0.00' COMMENT '企业服务费',
  `ent_service_fee_ratio` decimal(15,2) DEFAULT NULL COMMENT '企业服务费比例',
  `latest_refund_time` datetime DEFAULT NULL COMMENT '最后退款时间',
  `shop_name` varchar(128) DEFAULT NULL COMMENT '商家名',
  `shop_phone` varchar(100) DEFAULT NULL COMMENT '商家电话,多个,隔开',
  `shop_address` varchar(300) DEFAULT NULL COMMENT '商家地址',
  `estimate_arrive_time` datetime DEFAULT NULL COMMENT '预计送达时间',
  `actual_arrive_time` datetime DEFAULT NULL COMMENT '实际送达时间',
  `outer_order_id` varchar(100) NOT NULL COMMENT '外部订单ID',
  `outer_order_status` int(11) DEFAULT NULL COMMENT '外部订单状态',
  `recipient_name` varchar(64) DEFAULT NULL COMMENT '收货人姓名',
  `recipient_phone` varchar(64) DEFAULT NULL COMMENT '收货人手机号',
  `recipient_address` varchar(128) DEFAULT NULL COMMENT '收货地址',
  `recipient_address_longitude` varchar(50) DEFAULT NULL COMMENT '收货地址经度  实际值需要除以 10^6 进行换算',
  `recipient_address_latitude` varchar(50) DEFAULT NULL COMMENT '收货地址维度	实际值需要除以 10^6 进行换算',
  `notify_url` varchar(500) DEFAULT NULL COMMENT '渠道服务器主动通知外部服务器里指定的页面路径',
  `return_url` varchar(500) DEFAULT NULL COMMENT '操作成功跳转地址',
  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  `version` bigint(20) DEFAULT '0' COMMENT '版本号',
  PRIMARY KEY (`id`),
  UNIQUE KEY `uniq_order_id` (`order_id`),
  KEY `idx_employee_sn` (`employee_sn`),
  KEY `idx_order_id` (`outer_order_id`),
  KEY `idx_trade_no` (`trade_no`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='外卖订单表拓展信息';

meal_order 表保存热点数据,meal_order_attach表保存非热点数据。

meal_order 表可以很好的支持列表查询、订单状态更新等热点数据,并且表列数比原来少了一半多。

水平分表

什么是水平分表

水平分表就是指以行为单位对数据进行拆分,一般意义上的分库分表指的就是水平分表。

分表之后,所有表的结构都是一样的。

水平分表需要额外引入中间主键完成,例如shardingSphere等。

为什么要水平分表

水平分表可以解决表中的数据量大的问题,如果一张表的数据太多,操作起来会很麻烦,所以分表存储数据。

水平分表有哪些好处呢?

  1. 表数据量小,如分表算法合适,每个表大小相似;
  2. 拓展方便,如数据量继续增大,可以在增加表;

但凡事有两面性,水平分表需要选择合适的列进行,管理后台查询是需要union 或者引入ES等组件。

水平分表实战

水平分表算法

一般可以有范围法和hash法来进行水平分表。

加入未来5年数据量增加到1亿,预算每个表1千万数据,那么需要分成10个表。

范围法很好理解,可以让第1-1千万行数据存放在表1,第1千万01-2千万行数据存放在表2,以此类推。
范围法也有缺点,冷热数据不均匀,例如订单查询和操作都是最近的,几个月或者更早一起的订单便很少有操作。

hash法也不难理解,就是选择一个合适的hash函数对指定的列计算哈希码后进行取模,比如说使用取模操作(%),把%3结果为0的数据存放在表1,结果为1的存放在表2,结果为2的存放在表3即可。
hash法也有缺点,后续再就行分表时,需要改造hash函数,或者迁移就数据。文章来源地址https://www.toymoban.com/news/detail-473163.html

到了这里,关于垂直分表、水平分表详解的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 微信小程序23__flex布局 相关的3种居中: 水平居中_垂直居中_水平垂直居中

    类似这样写法 display:  flex; flex-direction:  column;                //垂直布局 align-items:  center;                    // 水平居中     justify-content:  space-around; //垂直方向分散布局 类似这样写法 display:  flex; flex-direction: row;          //水平布局       align-items: center;    

    2024年02月03日
    浏览(43)
  • 水平分库分表排雷帖

    一、背景 提起分库分表,对于大部分服务器开发来说,其实并不是一个新鲜的名词。随着业务的发展,我们表中的数据量会变的越来越大,字段也可能随着业务复杂度的升高而逐渐增多,我们为了解决单表的查询性能问题,一般会进行分表操作。 同时我们业务的用户活跃度

    2024年02月02日
    浏览(66)
  • 水平越权与垂直越权

    越权,顾名思义,就是超出了权限或权力范围。多数WEB应用都具备权限划分和控制,但是如果权限控制功能设计存在缺陷,那么攻击者就可以通过这些缺陷来访问未经授权的功能或数据,这就是我们通常说的越权漏洞。攻击者越权后就可以进行一些操作,例如查看敏感信息、

    2023年04月11日
    浏览(37)
  • 块、行内块水平垂直居中

    1.定位实现水平垂直居中 2.定位+位移 3.相对于整个视口水平垂直居中 4.flex+margin   5. flex 水平垂直居中 6.遮挡层

    2024年02月13日
    浏览(36)
  • 水平越权&垂直越权

    1、水平越权-同级用户权限共享 2、垂直越权-低高用户权限共享 3、访问控制-验证丢失取消验证脆弱验证 4、脆弱验证-CookieTokenJwt等 水平越权 就是同级用户之间的越权,打个比方现在有ABC三个用户,A是管理员,BC都是普通用户,现在B能够使用C这个用户的权限这就是水平越权

    2024年02月04日
    浏览(45)
  • 水平越权、垂直越权、防范措施

    一、越权简介 越权 :权限控制功能设计存在缺陷,攻击者就可以通过这些缺陷来访问未经授权的功能或数据。基于数据的访问控制设计缺陷引起。 越权 : 水平越权 、 垂直越权 二、水平越权 水平越权 : 权限相等者互相越权 。 A账号和B账号都可以访问这个功能,但是A账号

    2024年02月09日
    浏览(38)
  • CSS水平垂直居中

    1.利用定位 + margin:auto 2.flex布局 3.grid布局 一、利用position+margin:auto  二、利用flex 三、gird布局

    2024年02月14日
    浏览(41)
  • 居中一个元素(水平+垂直居中)

    我们的示例代码全在此基础上修改: 具体原理参考下面这篇博客: flex 弹性布局_本郡主是喵的博客-CSDN博客 对于内容是 行内式元素(内容大小撑起标签宽高)或文字, 是有效的。 line-heignt == height ,能使文字垂直对齐,text-align:center,能使内容居中水平对齐 父元素,采用相对布局,

    2024年02月11日
    浏览(53)
  • CSS 水平垂直居中的方式

    目录 在不知道子元素宽高的情况下,水平垂直居中的六种方式: 1、弹性盒子布局方式来实现(flex)。  2、绝对定位 + transform 3、table标签 4、display:table-cell 5、display: grid 6、writing-mode 属性 在实际使用最好测试下最低版本是否支持对应的实现方式,尽量选各个浏览器支持比

    2024年02月08日
    浏览(57)
  • 【CSS 布局】水平垂直方向居中

    单行元素 方式一: relative 和 absolute 方式二: relative 和 absolute (变种,适合于宽高固定) 方式三: flex 和 margin 方式四: flex 方式五: flex 多行元素

    2024年02月13日
    浏览(41)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包