2026/4/18 5:57:25
网站建设
项目流程
自建企业网站模板下载,长沙谷歌优化,wordpress只能传2m,网站优化大赛文章目录5.1 实现分表1、 选择要拆分的表2、 分表字段3、 修改配置文件 schema.xml4、 修改配置文件 rule.xml5、 在数据节点 dn2 上建 orders 表6、 重启 Mycat#xff0c;让配置生效7、 访问 Mycat 实现分片5.3 常用分片规则1、 取模2、 分片枚举3、 范围约定5.4 全局序列1、…文章目录5.1 实现分表1、 选择要拆分的表2、 分表字段3、 修改配置文件 schema.xml4、 修改配置文件 rule.xml5、 在数据节点 dn2 上建 orders 表6、 重启 Mycat让配置生效7、 访问 Mycat 实现分片5.3 常用分片规则1、 取模2、 分片枚举3、 范围约定5.4 全局序列1、 本地文件2、 数据库方式3、 时间戳方式4、 自主生成全局序列相对于垂直拆分水平拆分不是将表做分类而是按照某个字段的某种规则来分散到多个库之中每个表中 包含一部分数据。简单来说我们可以将数据的水平切分理解为是按照数据行的切分就是将表中的某些行切分 到一个数据库而另外的某些行又切分到其他的数据库中如图5.1 实现分表1、 选择要拆分的表MySQL 单表存储数据条数是有瓶颈的单表达到 1000 万条数据就达到了瓶颈会影响查询效率需要进行水平拆分分表进行优化。例如例子中的 orders、orders_detail 都已经达到 600 万行数据需要进行分表优化。2、 分表字段以 orders 表为例可以根据不同自字段进行分表编号分表字段效果1id主键、或创建时间查询订单注重时效历史订单被查询的次数少如此分片会造成一个节点访问多一个访问少不平均。2customer_id客户 id 根据客户 id 去分两个节点访问平均一个客户的所有订单都在同一个节点3、 修改配置文件 schema.xml#为 orders 表设置数据节点为 dn1、dn2并指定分片规则为 mod_rule自定义的名字table nameordersdataNodedn1,dn2rulemod_rule/table4、 修改配置文件 rule.xml#在 rule 配置文件里新增分片规则 mod_rule并指定规则适用字段为 customer_id #还有选择分片算法 mod-long对字段求模运算customer_id 对两个节点求模根据结果分片#配置算法 mod-long参数 count 为2两个节点tableRule namemod_rulerulecolumnscustomer_id/columnsalgorithmmod-long/algorithm/rule/tableRule…function namemod-longclassio.mycat.route.function.PartitionByMod!--how many data nodes--property namecount2/property/function5、 在数据节点 dn2 上建 orders 表6、 重启 Mycat让配置生效7、 访问 Mycat 实现分片#在 mycat 里向 orders 表插入数据INSERT 字段不能省略 INSERTINTOorders(id,order_type,customer_id,amount)VALUES(1,101,100,100100);INSERTINTOorders(id,order_type,customer_id,amount)VALUES(2,101,100,100300);INSERTINTOorders(id,order_type,customer_id,amount)VALUES(3,101,101,120000);INSERTINTOorders(id,order_type,customer_id,amount)VALUES(4,101,101,103000);INSERTINTOorders(id,order_type,customer_id,amount)VALUES(5,102,101,100400);INSERTINTOorders(id,order_type,customer_id,amount)VALUES(6,102,100,100020);#在mycat、dn1、dn2中查看orders表数据分表成功5.2 Mycat 的分片 “join”Orders 订单表已经进行分表操作了和它关联的 orders_detail 订单详情表如何进行 join 查询。我们要对 orders_detail 也要进行分片操作。Join 的原理如下图1、 ER 表Mycat 借鉴了 NewSQL 领域的新秀 Foundation DB 的设计思路Foundation DB 创新性的提出了 Table Group 的概念其将子表的存储位置依赖于主表并且物理上紧邻存放因此彻底解决了JION 的效率和性能问 题根据这一思路提出了基于 E-R 关系的数据分片策略子表的记录与所关联的父表记录存放在同一个数据分片上。#修改 schema.xml 配置文件 …table nameordersdataNodedn1,dn2rulemod_rulechildTable nameorders_detailprimaryKeyidjoinKeyorder_idparentKeyid//table…#在 dn2 创建 orders_detail 表#重启 Mycat#访问 Mycat 向 orders_detail 表插入数据INSERTINTOorders_detail(id,detail,order_id)values(1,detail1,1);INSERTINTOorders_detail(id,detail,order_id)VALUES(2,detail1,2);INSERTINTOorders_detail(id,detail,order_id)VALUES(3,detail1,3);INSERTINTOorders_detail(id,detail,order_id)VALUES(4,detail1,4);INSERTINTOorders_detail(id,detail,order_id)VALUES(5,detail1,5);INSERTINTOorders_detail(id,detail,order_id)VALUES(6,detail1,6);#在mycat、dn1、dn2中运行两个表join语句Selecto.*,od.detail from orders o inner join orders_detail od on o.idod.order_id;2、 全局表在分片的情况下当业务表因为规模而进行分片以后业务表与这些附属的字典表之间的关联就成了比较 棘手的问题考虑到字典表具有以下几个特性① 变动不频繁② 数据量总体变化不大③ 数据规模不大很少有超过数十万条记录鉴于此Mycat 定义了一种特殊的表称之为“全局表”全局表具有以下特性① 全局表的插入、更新操作会实时在所有节点上执行保持各个分片的数据一致性② 全局表的查询操作只从一个节点获取③ 全局表可以跟任何一个表进行 JOIN 操作将字典表或者符合字典表特性的一些表定义为全局表则从另外一个方面很好的解决了数据JOIN 的难题。通过全局表基于 E-R 关系的分片策略Mycat 可以满足 80%以上的企业应用开发#修改 schema.xml 配置文件…table nameordersdataNodedn1,dn2rulemod_rulechildTable nameorders_detailprimaryKeyidjoinKeyorder_idparentKeyid//tabletable namedict_order_typedataNodedn1,dn2typeglobal/table…#在 dn2 创建 dict_order_type 表#重启 Mycat#访问 Mycat 向 dict_order_type 表插入数据INSERTINTOdict_order_type(id,order_type)VALUES(101,type1);INSERTINTOdict_order_type(id,order_type)VALUES(102,type2);#在Mycat、dn1、dn2中查询表数据5.3 常用分片规则1、 取模此规则为对分片字段求摸运算。也是水平分表最常用规则。5.1 配置分表中orders 表采用了此规则。2、 分片枚举通过在配置文件中配置可能的枚举 id自己配置分片本规则适用于特定的场景比如有些业务需要按照省份或区县来做保存而全国省份区县固定的这类业务使用本条规则。#1修改schema.xml配置文件table nameorders_ware_infodataNodedn1,dn2rulesharding_by_intfile/table#2修改rule.xml配置文件tableRule namesharding_by_intfilerulecolumnsareacode/columnsalgorithmhash-int/algorithm/rule/tableRule…function namehash-intclassio.mycat.route.function.PartitionByFileMapproperty namemapFilepartition-hash-int.txt/propertyproperty nametype1/propertyproperty namedefaultNode0/property/function# columns分片字段algorithm分片函数 # mapFile标识配置文件名称type0为int型、非0为String #defaultNode默认节点:小于0表示不设置默认节点大于等于0表示设置默认节点 # 设置默认节点如果碰到不识别的枚举值就让它路由到默认节点如不设置不识别就报错 #3修改partition-hash-int.txt配置文件11001201#4重启Mycat#5访问Mycat创建表 #订单归属区域信息表CREATETABLEorders_ware_info(id INT AUTO_INCREMENT comment编号,order_id INT comment订单编号,addressVARCHAR(200)comment地址,areacodeVARCHAR(20)comment区域编号,PRIMARYKEY(id));#6插入数据 INSERTINTOorders_ware_info(id,order_id,address,areacode)VALUES(1,1,北京,110);INSERTINTOorders_ware_info(id,order_id,address,areacode)VALUES(2,2,天津,120);#7查询Mycat、dn1、dn2可以看到数据分片效果3、 范围约定此分片适用于提前规划好分片字段某个范围属于哪个分片#1修改schema.xml配置文件table namepayment_infodataNodedn1,dn2ruleauto_sharding_long/table#2修改rule.xml配置文件tableRule nameauto_sharding_longrulecolumnsorder_id/columnsalgorithmrang-long/algorithm/rule/tableRule…function namerang-longclassio.mycat.route.function.AutoPartitionByLongproperty namemapFileautopartition-long.txt/propertyproperty namedefaultNode0/property/function# columns分片字段algorithm分片函数 # mapFile标识配置文件名称 #defaultNode默认节点:小于0表示不设置默认节点大于等于0表示设置默认节点 # 设置默认节点如果碰到不识别的枚举值就让它路由到默认节点如不设置不识别就 报错 #3修改autopartition-long.txt配置文件0-1020103-2001#4重启Mycat#5访问Mycat创建表 #支付信息表 CREATETABLEpayment_info(id INT AUTO_INCREMENT comment编号,order_id INT comment订单编号,payment_status INT comment支付状态,PRIMARYKEY(id));#6插入数据 INSERTINTOpayment_info(id,order_id,payment_status)VALUES(1,101,0);INSERTINTOpayment_info(id,order_id,payment_status)VALUES(2,102,1);INSERTINTOpayment_info(id,order_id,payment_status)VALUES(3,103,0);INSERTINTOpayment_info(id,order_id,payment_status)VALUES(4,104,1);#7查询Mycat、dn1、dn2可以看到数据分片效果4、 按日期天分片此规则为按天分片。设定时间格式、范围#1修改schema.xml配置文件table namelogin_infodataNodedn1,dn2rulesharding_by_date/table#2修改rule.xml配置文件tableRule namesharding_by_daterulecolumnslogin_date/columnsalgorithmshardingByDate/algorithm/rule/tableRule…function nameshardingByDateclassio.mycat.route.function.PartitionByDateproperty namedateFormatyyyy-MM-dd/propertyproperty namesBeginDate2019-01-01/propertyproperty namesEndDate2019-01-04/propertyproperty namesPartionDay2/property/function# columns分片字段algorithm分片函数 #dateFormat 日期格式 #sBeginDate 开始日期 #sEndDate结束日期,则代表数据达到了这个日期的分片后循环从开始分片插入 #sPartionDay 分区天数即默认从开始日期算起分隔2天一个分区 #3重启Mycat#4访问Mycat创建表 #用户信息表 CREATETABLElogin_info(id INT AUTO_INCREMENT comment编号,user_id INT comment用户编号,login_date date comment登录日期,PRIMARYKEY(id));#6插入数据 INSERTINTOlogin_info(id,user_id,login_date)VALUES(1,101,2019-01-01);INSERTINTOlogin_info(id,user_id,login_date)VALUES(2,102,2019-01-02);INSERTINTOlogin_info(id,user_id,login_date)VALUES(3,103,2019-01-03);INSERTINTOlogin_info(id,user_id,login_date)VALUES(4,104,2019-01-04);INSERTINTOlogin_info(id,user_id,login_date)VALUES(5,103,2019-01-05);INSERTINTOlogin_info(id,user_id,login_date)VALUES(6,104,2019-01-06);#7查询Mycat、dn1、dn2可以看到数据分片效果5.4 全局序列在实现分库分表的情况下数据库自增主键已无法保证自增主键的全局唯一。为此Mycat 提供了全局 sequence并且提供了包含本地配置和数据库配置等多种实现方式1、 本地文件此方式 Mycat 将 sequence 配置到文件中当使用到 sequence 中的配置后Mycat 会更下classpath 中的 sequence_conf.properties 文件中 sequence 当前的值。① 优点本地加载读取速度较快② 缺点抗风险能力差Mycat 所在主机宕机后无法读取本地文件。2、 数据库方式利用数据库一个表 来进行计数累加。但是并不是每次生成序列都读写数据库这样效率太低。Mycat 会预加载一部分号段到 Mycat 的内存中这样大部分读写序列都是在内存中完成的。如果内存中的号段用完了 Mycat 会再向数据库要一次。问那如果 Mycat 崩溃了 那内存中的序列岂不是都没了是的。如果是这样那么 Mycat 启动后会向数据库申请新的号段原有号段会弃用。也就是说如果 Mycat 重启那么损失是当前的号段没用完的号码但是不会因此出现主键重复① 建库序列脚本#在 dn1 上创建全局序列表 CREATETABLEMYCAT_SEQUENCE(NAMEVARCHAR(50)NOTNULL,current_value INTNOTNULL,increment INT NOT NULLDEFAULT100,PRIMARYKEY(NAME))ENGINEINNODB;#创建全局序列所需函数 DELIMITER $$ CREATEFUNCTIONmycat_seq_currval(seq_nameVARCHAR(50))RETURNSVARCHAR(64)DETERMINISTIC BEGIN DECLARE retvalVARCHAR(64);SETretval-999999999,null;SELECTCONCAT(CAST(current_valueASCHAR),,,CAST(incrementASCHAR))INTO retval FROM MYCAT_SEQUENCEWHERENAMEseq_name;RETURNretval;END $$ DELIMITER;DELIMITER $$ CREATEFUNCTIONmycat_seq_setval(seq_nameVARCHAR(50),VALUEINTEGER)RETURNSVARCHAR(64)DETERMINISTIC BEGIN UPDATE MYCAT_SEQUENCESETcurrent_valueVALUEWHERENAMEseq_name;RETURNmycat_seq_currval(seq_name);END $$ DELIMITER;DELIMITER $$ CREATEFUNCTIONmycat_seq_nextval(seq_nameVARCHAR(50))RETURNSVARCHAR(64)DETERMINISTIC BEGIN UPDATE MYCAT_SEQUENCESETcurrent_valuecurrent_valueincrementWHERENAMEseq_name;RETURNmycat_seq_currval(seq_name);END $$ DELIMITER;#初始化序列表记录 INSERTINTOMYCAT_SEQUENCE(NAME,current_value,increment)VALUES(ORDERS,400000,100);② 修改 Mycat 配置#修改sequence_db_conf.propertiesvim sequence_db_conf.properties#意思是 ORDERS这个序列在dn1这个节点上具体dn1节点是哪台机子请参考schema.xml#修改server.xmlvim server.xml#全局序列类型0-本地文件1-数据库方式2-时间戳方式。此处应该修改成1。#重启Mycat③ 验证全局序列#登录Mycat插入数据 insert intoorders(id,amount,customer_id,order_type)values(next valueforMYCATSEQ_ORDERS,1000,101,102);#查询数据#重启Mycat后再次插入数据再查询3、 时间戳方式全局序列ID 64 位二进制 (42(毫秒)5(机器 ID)5(业务编码)12(重复累加) 换算成十进制为 18 位数的long 类型每毫秒可以并发 12 位二进制的累加。① 优点配置简单② 缺点18 位 ID 过长4、 自主生成全局序列可在 java 项目里自己生成全局序列如下① 根据业务逻辑组合② 可以利用 redis 的单线程原子性 incr 来生成序列但自主生成需要单独在工程中用 java 代码实现还是推荐使用 Mycat 自带全局序列如果文章对你有一点点帮助欢迎【点赞、留言、 关注】您的关注是我创作的动力若有疑问/交流/需求欢迎留言/私聊多一个朋友多一条路