在面试时经常会问一个问题请列举出hash在数据库内部的应用hash的原理虽然简单但是它在数据库中可以说是无处不在其中hash partition是hash在数据库中一个简单的应用虽然它没有range partition那么常用但是我们在做数据库水平拆分时其实就是利用了hash partition的原理利用hash函数对某个key进行运算然后将其分布到不同的主机上原理很简单
我们在设计时遇到了一个问题当分区的数量需要变化时基于hash的原理数据可能会从一个分区移动到另外一个分区因为某个key在个分区时可能被分布在分区而在个分区时可能被分布在分区这样每当分区数量变化时就需要全部重新分布数据代价很高
那么Oracle是怎么做的?首先可以肯定的是Oracle的hash partition在分区增加时不需要做全部数据的重新分布有人告诉我Oracle的hash函数比较牛可以保证分区数量增加时这个hash函数可以让原来的数据还在旧的分区中而新的数据可以分布在新的分区Oracle的函数无非就是get_hash_value或ora_hash(g)从hash的原理上来说这也是不可能做到的
我们对hash partition都有一个常识就是partition的数量最好是的次方也就是……否则分区会出现不分区均衡的现象按照hash的原理不管是几个分区都可以做到完全均衡的为什么会不均衡其实答案已经出来了Oracle为了能够增加分区为你预留了几个看不到的分区
假设我们有个分区一共条数据数据的分布如下图
hash partition不能直接增加分区而是split当前分区当需要增加到个分区时实际上是分区和分区分别split产生新的分区和分区如下图
Oracle如何做到分区数量增加后其他分区的数据不受影响呢其实很简单Oracle在做hash运算时预留了分区比如个分区实际上是用个分区的hash来运算的只不过把缺少的分区的数据合并到其他分区这样就会出现数据不均衡的情况Oracle的公式是这样的用等于或者大于当前分区数量的最小的一个的N次方比如个分区做个hash bucket我们再来考虑一下(的N次方)的情况比如要把个分区加为个分区因为已经是的N次方所以数据会均匀分布而且Oracle还是使用个hash bucket这时新增的分区实际上把分区 split后产生的这时因为有个分区了所以会使用个hash bucket这时Oracle的hash函数就比较牛了它可以保证个分区时同一个键值分布在相同的分区或者是对应可以合并的分区看下面的SQL
select ora_hash(hellodba)+ parora_hash(hellodba)+ parora_hash(hellodba)+ parora_hash(hellodba)+ par from dual;
PAR PAR PAR PAR
上面的SQL我们看到分区的数量在时hellodba这个key分别落在在号分区虽然落在不同的分区上但是分区和分区是对应可合并的这样就保证了数据是不需要移动的一句话总结就是hash bucket总是的N次方如果分区数不足则会合并数据产生不均衡的情况这样增加分区时只需要对应分区的数据做split即可同理减少分区也不是简单的drop而是合并分区
再回到我们的项目中我们为了解决这个问题采用了更简单的处理方案直接就做了个分区我们有个物理数据库每个数据库中有个表以后再分拆时只要移动这些表并修改应用中的对应关系就可以了其实和Oracle合并再拆分的思路是一样的