在现今数据体量越来越大的时代,分库分表已经成为应对各种瓶颈的常用手段。当然已有不少数据库已经原生支持分库分表,如MongoDB的分片、PostgresSQL的分表等等;虽然提供了很强大的功能,但是也存在着各种限制或者不足。
在数据体量还没达到一定量级,仅仅需要简单的分表即可满足性能要求,但使用如MongoDB集群又存在成本高问题时,有没有简单并且可高度自定义的方案呢?比如使用客户编码(字符串类型)来分64张或128表并实现自动落入分表的方案。
分64张或128张表,64、128这都是数字,字符串又如何跟这些数字关联起来,并且是稳定的关联关系。那就是今天的主题:字符串作为分表取模几种方式 !
NO.1 通过加密类计算哈希值转成Int64的数值,然后根据具体分表数取余。
通过MD5计算:
public int GetModByMD5(string customerNo)
{
using (var md5 = MD5.Create())
{
byte[] hashBytes = md5.ComputeHash(Encoding.UTF8.GetBytes(customerNo));
int number = BitConverter.ToInt64(hashBytes, 0);
/*一般情况下,仅有相同字符串才能计算出相等的number
但number取余后,数值范围是0~123
*/
renturn number%128;
}
}
通过SHA256计算:
public int GetModBySHA256(string customerNo)
{
using (var sHA256 = SHA256.Create())
{
byte[] hashBytes = sHA256.ComputeHash(Encoding.UTF8.GetBytes(customerNo));
int number = BitConverter.ToInt64(hashBytes, 0);
/*一般情况下,仅有相同字符串才能计算出相等的number
但number取余后,数值范围是0~123
*/
renturn number%128;
}
}
还有很多中加密类计算哈希值的方式这里不就一一列出。
NO.2 通过字符串的Unicode编码进行计算。
public int GetModByUnicode(string customerNo)
{
long number=0;
foreach (char c in customerNo)
{
number += (int)c; //可以改为乘等累计
}
/*
使用Unicode编码,字符串中字符一样(与顺序无关)的计算出的结果完成一样
如CT01001和CT00011,计算出的number均是393
*/
renturn number%128;
}
计算出每个客户编码对应的Mod后,可以根据此值找到数据库命名关系对应的表,如订单表命名格式:order_{mod},即:order_0...order_123;
说明:使用这种简单计算取模的方式,存在着数据分布不均的可能,如某些大体量的客户都落在了同一张或几张表,导致一些表的数据特别多,这种情况会降低分表策略旨在提升的性能效果。为了应对这一问题,需要根据实际业务和数据特征,采取更为精细和动态的数据分布策略。
注:为什么不直接使用拓展方法GetHashCode()呢,虽然使用GetHashCode()扩展方法也能计算出简便的散列值;但此方法计算的值与运行环境有密切关联,仅在同一个程序且没有重启的情况下,计算的结果才是一致的,然而一旦程序重启,原有的散列值计算就会发生变化,不存在稳定关联关系。