今天看了一个视频是关于梅西和C罗的,视频的主题是问他们两个是不是朋友?结果可想而知,两个人私底下很较劲,梅西投票从来没投给过C罗,C罗也从来没投过梅西,2个人在足球场上争斗了10年。今天你方唱罢,明天我方登场。如果你的一生中没有一个劲敌,自身前进的动力就会受影响。所以我们也要在自己的工作领域中找一个尊敬的对手,没事和他斗上一斗。
火钳刘明
。今天我们来介绍date分区算法
1.hash分区算法
2.stringhash分区算法
3.enum分区算法
4.numberrange分区算法
5.patternrange分区算法
6.date分区算法
7.jumpstringhash算法
<tableRule name="rule_date">
<rule>
<columns>create_date</columns>
<algorithm>func_date</algorithm>
</rule>
</tableRule>
<function name="func_date" class="Date">
<property name="dateFormat">yyyy-MM-dd</property>
<property name="sBeginDate">2015-01-01</property>
<property name="sEndDate">2015-01-31 </property> <!--if not set sEndDate,then in fact ,the sEndDate = sBeginDate+ (node size)*sPartionDay-1 -->
<property name="sPartionDay">10</property>
<property name="defaultNode">0</property><!--the default is -1-->
</function>
和之前的算法一样。需要在rule.xml中配置tableRule和function。
这个算法有两种工作模式:
1.模式1为带状模式。不需要定义sEndDate或者将sEndDate可以配置为""。这种模式只定义了开始时间,没有定义结束时间,它会以sPartionDay为间隔,进行区间划分,每个区间对应一个数据节点,然后可以一直循环无限增加下去。
真的是这样吗?
,其实不是,sEndDate在不定义的情况下,和配置schema.xml有关。就是在schema.xml中我们会预先设置分片数。那么实际sEndDate是等于下面的结果的。
2.模式2为环形模式。定义sEndDate且不为""。这种模式定义了开始时间,也定义了结束时间,它以sPartionDay为间隔进行区间划分,划分为N个区间,每个区间对应一个数据节点。当执行一条SQL语句的时候,如果分区字段key的值小于结束时间值,则和模式1一样落在指定分区中。而一旦key的值大于结束时间。则要进行取模运算。通过取摸运算得出的分区号。
计算公式为:
在启动dble之后,就会读取rule.xml文件,加载sBeginDate来确定起始时间,如上面配置就会加载2015-01-01,确定为起始时间,然后读取sPartionDay来确定每个MySQL分片承载多少天内的数据。如上面配置10天的数据存放在一个分片上。读取dateFormat来确定日期格式,这里的日期格式为'yyyy-mm-dd'。
如果有用户通过where查询create_date='2015-01-21'的时候,就会访问date分片算法,将where条件的值取出来尝试转换成Java内部的时间类型。然后求这个值与起始时间的差,在除以指定分区的间隔,确定所属的分片。
<tableRule name="rule_date">
<rule>
<columns>create_date</columns>
<algorithm>func_date</algorithm>
</rule>
</tableRule>
<function name="func_date" class="Date">
<property name="dateFormat">yyyy-MM-dd</property>
<property name="sBeginDate">2015-01-01</property>
<property name="sEndDate">2015-01-31 </property> <!--if not set sEndDate,then in fact ,the sEndDate = sBeginDate+ (node size)*sPartionDay-1 -->
<property name="sPartionDay">10</property>
<property name="defaultNode">0</property><!--the default is -1-->
</function>
<table name="test_date" primaryKey="id" rule="rule_date" dataNode="dn1,dn2,dn3,dn4"/>
[root@mysql5 ~]# mysql -uman1 -p -P9066 -h192.168.56.185 -p654321
mysql> reload @@config;
Query OK, 1 row affected (0.39 sec)
Reload config success
可以发现,我们插入了四条数据,分别是2015-01-07,2015-01-17,2015-01-27,2015-02-25。前面三条数据都小于我们的sEndDate。然后起始时间是2015-01-01,间隔是10,那么对应的分片情况就应该如下所示:
index 0: 2015-01-01,2015-01-10 ===>2015-01-07
index 1: 2015-01-11,2015-01-20 ===>2015-01-17
index 2: 2015-01-20,2015-01-30 ===>2015-01-27
index 3: 2015-01-31,2015-02-09
我们来看看源代码是如何实现的。
public Integer calculate(String columnValue) {
try {
if (columnValue == null || "null".equalsIgnoreCase(columnValue)) {
if (defaultNode >= 0) {
return defaultNode;
}
return null;
}
long targetTime = formatter.get().parse(columnValue).getTime();
if (targetTime < beginDate) {
return (defaultNode >= 0) ? defaultNode : null;
}
int targetPartition = (int) ((targetTime - beginDate) / partitionTime);
if (targetTime > endDate && nCount != 0) {
targetPartition = targetPartition % nCount;
}
return targetPartition;
} catch (ParseException e) {
throw new IllegalArgumentException("columnValue:" + columnValue + " Please check if the format satisfied.", e);
}
}
从代码中可以看出总共两种计算方式,输入时间大于beginDate小于等于endDate。就按照下面方式计算。
int targetPartition = (int) ((targetTime - beginDate) / partitionTime);
输入时间大于endDate就是上面计算出来的值在求模
targetPartition = targetPartition % nCount;
而这里需要注意一点的就是partitionTime被设置成了等于sPartionDay的值*86400000微秒,因为一天正好是86400000微秒。
private static final long ONE_DAY = 86400000;
partitionTime = Integer.parseInt(sPartionDay) * ONE_DAY;
那么当我们插入2015-02-25,就先将字符串转换成时间,时间在转换成long类型。然后相减在除以864000000(这里要乘以sPartionDay,也就是10天)。做下列运算得出来的值是5,然后5在对nCount(分区数)取模,最后得出结果是1,然后该数据就会落到分片2上(索引从0开始计算)。如果分区字段值小于sBeginDate,则会检查是否设置了defaultNode。设置了就会落到defaultNode上,没有设置就会报错。我们来写段java验证这个算法。
[root@mysql5 ~]# more test1.java
import java.text.SimpleDateFormat;
import java.util.Date;
public class test1 {
public static void main(String[] args) throws Exception
{
SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd");
long startDate=sdf.parse("2015-01-01").getTime();
long endDate=sdf.parse("2015-01-31").getTime();
long tarDate=sdf.parse("2015-02-25").getTime();
int nCount = (int) ((endDate - startDate) / 864000000) + 1;
int targetPartition = (int) ((tarDate - startDate) / 864000000);
System.out.println(nCount);
System.out.println(targetPartition);
}
}
[root@mysql5 ~]# java test1
4
5
今天就介绍到这里,在遇到一些小疑惑的时候通过看源码解决了。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。