数据库分表处理设计思想和实现

一、概述

分表是个目前算是比较炒的比较流行的概念,特别是在大负载的情况下,分表是一个良好分散数据库压力的好方法。

首先要了解为什么要分表,分表的好处是什么。我们先来大概了解以下一个数据库执行SQL的过程:
接收到SQL --> 放入SQL执行队列 --> 使用分析器分解SQL --> 按照分析结果进行数据的提取或者修改 --> 返回处理结果

当然,这个流程图不一定正确,这只是我自己主观意识上这么我认为。那么这个处理过程当中,最容易出现问题的是什么?就是说,如果前一个SQL没有执行完毕的话,后面的SQL是不会执行的,因为为了保证数据的完整性,必须对数据表文件进行锁定,包括共享锁和独享锁两种锁定。共享锁是在锁定的期间,其它线程也可以访问这个数据文件,但是不允许修改操作,相应的,独享锁就是整个文件就是归一个线程所有,其它线程无法访问这个数据文件。一般MySQL中最快的存储引擎MyISAM,它是基于表锁定的,就是说如果一锁定的话,那么整个数据文件外部都无法访问,必须等前一个操作完成后,才能接收下一个操作,那么在这个前一个操作没有执行完成,后一个操作等待在队列里无法执行的情况叫做阻塞,一般我们通俗意义上叫做“锁表”。

锁表直接导致的后果是什么?就是大量的SQL无法立即执行,必须等队列前面的SQL全部执行完毕才能继续执行。这个无法执行的SQL就会导致没有结果,或者延迟严重,影响用户体验。

**特别是对于一些使用比较频繁的表,**比如SNS系统中的用户信息表、论坛系统中的帖子表等等,都是访问量大很大的表,为了保证数据的快速提取返回给用户,必须使用一些处理方式来解决这个问题,这个就是我今天要聊到的分表技术

分表技术顾名思义,就是把若干个存储相同类型数据的表分成几个表分表存储,在提取数据的时候,不同的用户访问不同的表,互不冲突,减少锁表的几率。比如,目前保存用户分表有两个表,一个是user_1表,还有一个是 user_2 表,两个表保存了不同的用户信息,user_1 保存了前10万的用户信息,user_2保存了后10万名用户的信息,现在如果同时查询用户 heiyeluren1 和 heiyeluren2 这个两个用户,那么就是分表从不同的表提取出来,减少锁表的可能。

二、基于基础表的分表处理

这个基于基础表的分表处理方式大致的思想就是:一个主要表,保存了所有的基本信息,如果某个项目需要找到它所存储的表,那么必须从这个基础表中查找出对应的表名等项目,好直接访问这个表。如果觉得这个基础表速度不够快,可以完全把整个基础表保存在缓存或者内存中,方便有效的查询。

我们基于贴吧的情况,构建假设如下的3张表:

  1. 贴吧版块表: 保存贴吧中版块的信息
  2. 贴吧主题表:保存贴吧中版块中的主题信息,用于浏览
  3. 贴吧回复表:保存主题的原始内容和回复内容

“贴吧版块表”包含如下字段:
版块ID board_id int(10)
版块名称 board_name char(50)
子表ID table_id smallint(5)
产生时间 created datetime

“贴吧主题表”包含如下字段:
主题ID topic_id int(10)
主题名称 topic_name char(255)
版块ID board_id int(10)
创建时间 created datetime

“贴吧回复表”的字段如下:
回复ID reply_id int(10)
回复内容 reply_text text
主题ID topic_id int(10)
版块ID board_id int(10)
创建时间 created datetime

那么上面保存了我们整个贴吧中的表结构信息,三个表对应的关系是:

版块 --> 多个主题
主题 --> 多个回复

那么就是说,表文件大小的关系是:
版块表文件 < 主题表文件 < 回复表文件

所以基本可以确定需要对主题表和回复表进行分表,已增加我们数据检索查询更改时候的速度和性能。

看了上面的表结构,会明显发现,在“版块表”中保存了一个"table_id"字段,这个字段就是用于保存一个版块对应的主题和回复都是分表保存在什么表里的。

比如我们有一个叫做“PHP”的贴吧,board_id是1,子表ID也是1,那么这条记录就是:

board_id | board_name | table_id | created
1 | PHP | 1 | 2007-01-19 00:30:12

相应的,如果我需要提取“PHP”吧里的所有主题,那么就必须按照表里保存的table_id来组合一个存储了主题的表名称,比如我们主题表的前缀是“topic_”,那么组合出来“PHP”吧对应的主题表应该是:“topic_1”,那么我们执行:

SELECT * FROM topic_1 WHERE board_id = 1 ORDER BY topic_id DESC LIMIT 10

这样就能够获取这个主题下面回复列表,方便我们进行查看,如果需要查看某个主题下面的回复,我们可以继续使用版块表中保存的“table_id”来进行查询。比如我们回复表的前缀是“reply_”,那么就可以组合出“PHP”吧的ID为1的主题的回复:

SELECT * FROM reply_1 WHERE topic_id = 1 ORDER BY reply_id DESC LIMIT 10

这里,我们能够清晰的看到,其实我们这里使用了基础表,基础表就是我们的版块表。那么相应的,肯定会说**:基础表的数据量大了以后如何保证它的速度和效率?**

当然,我们就必须使得这个基础表保持最好的速度和性能,比如,可以采用MySQL的内存表来存储,或者保存在内存当中,比如Memcache之类的内存缓存等等,可以按照实际情况来进行调整。

一般基于基础表的分表机制在SNS、交友、论坛等Web2.0网站中是个比较不错的解决方案,在这些网站中,完全可以单独使用一个表来来保存基本标识和目标表之间的关系。使用表保存对应关系的好处是以后扩展非常方便,只需要增加一个表记录。

【优势】增加删除节点非常方便,为后期升级维护带来很大便利
【劣势】需要增加表或者对某一个表进行操作,还是无法离开数据库,会产生瓶颈

三、基于Hash算法的分表处理

我们知道Hash表就是通过某个特殊的Hash算法计算出的一个值,这个值必须是惟一的,并且能够使用这个计算出来的值查找到需要的值,这个叫做哈希表。

我们在分表里的hash算法跟这个思想类似:通过一个原始目标的ID或者名称通过一定的hash算法计算出数据存储表的表名,然后访问相应的表。

继续拿上面的贴吧来说,每个贴吧有版块名称和版块ID,那么这两项值是固定的,并且是惟一的,那么我们就可以考虑通过对这两项值中的一项进行一些运算得出一个目标表的名称。

现在假如我们针对我们这个贴吧系统,假设系统最大允许1亿条数据,考虑每个表保存100万条记录,那么整个系统就不超过100个表就能够容纳。按照这个标准,我们假设在贴吧的版块ID上进行hash,获得一个key值,这个值就是我们的表名,然后访问相应的表。

我们构造一个简单的hash算法:

function get_hash($id){
str=bin2hex(str = bin2hex(str=bin2hex(id);
hash=substr(hash = substr(hash=substr(str, 0, 4);
if (strlen($hash)<4){
hash=strpad(hash = str_pad(hash=strp​ad(hash, 4, “0”);
}
return $hash;
}

算法大致就是传入一个版块ID值,然后函数返回一个4位的字符串,如果字符串长度不够,使用0进行补全。

比如:get_hash(1),输出的结果是“3100”,输入:get_hash(23819),得到的结果是:3233,那么我们经过简单的跟表前缀组合,就能够访问这个表了。那么我们需要访问ID为1的内容时候哦,组合的表将是:topic_3100、reply_3100,那么就可以直接对目标表进行访问了。

当然,使用hash算法后,有部分数据是可能在同一个表的,这一点跟hash表不同,hash表是尽量解决冲突,我们这里不需要,当然同样需要预测和分析表数据可能保存的表名。

如果需要存储的数据更多,同样的,可以对版块的名字进行hash操作,比如也是上面的二进制转换成十六进制,因为汉字比数字和字母要多很多,那么重复几率更小,但是可能组合成的表就更多了,相应就必须考虑一些其它的问题。

归根结底,使用hash方式的话必须选择一个好的hash算法,才能生成更多的表,然数据查询的更迅速。

【优点hash算法直接得出目标表名称,效率很高】通过
【劣势】扩展性比较差,选择了一个hash算法,定义了多少数据量,以后只能在这个数据量上跑,不能超过过这个数据量,可扩展性稍差

四、其它问题

1**. 搜索问题**
现在我们已经进行分表了,那么就无法直接对表进行搜索,因为你无法对可能系统中已经存在的几十或者几百个表进行检索,所以搜索必须借助第三方的组件来进行,比如Lucene作为站内搜索引擎是个不错的选择。

  1. 表文件问题
    我们知道MySQL的MyISAM引擎每个表都会生成三个文件,.frm、.MYD、*.MYI 三个文件,分表用来保存表结构、表数据和表索引。Linux下面每个目录下的文件数量最好不要超过1000个,不然检索数据将更慢,那么每个表都会生成三个文件,相应的如果分表超过300个表,那么将检索非常慢,所以这时候就必须再进行分,比如在进行数据库的分离。

使用基础表,我们可以新增加一个字段,用来保存这个表保存在什么数据。使用Hash的方式,我们必须截取hash值中第几位来作为数据库的名字。这样,完好的解决这个问题。

五、总结

在大负载应用当中,数据库一直是个很重要的瓶颈,必须要突破,本文讲解了两种分表的方式,希望对很多人能够有启发的作用。当然,本文代码和设想没有经过任何代码测试,所以无法保证设计的完全准确实用,具体还是需要读者在使用过程当中认真分析实施。

数据库分表处理设计思想和实现相关推荐

  1. 数据库分表设计-任我行

    本文只阐述一个完整的实例,直接可以复制过去用,不作过多的解释. 简单说一下分表与分区: 分区的原理:我在深圳市,但我也在中国,如果中国没有划分区域的话,搜索范围将是整个中国,查询起来很费力.现在既然中 ...

  2. 数据库设计思想深究----Mysql(图文)

    在探索开始前,我们先试想一个问题:存储为什么要分缓存与磁盘? 一.为什么要区分缓存与磁盘? 我们利用高级语言,编写逻辑,最终被解释为指令集合,委托CPU去处理. 根据计算机组成原理,我们知道CPU在执 ...

  3. 如何设计新零售行业数据库?不懂SKU、SPU?带你走进数据库设计,用最容易理解的方式讲述数据库设计思想

    数据库设计思想-使用新零售行业数据库带你走进数据库设计 本篇文章会详细描述数据库设计中问题的解决思路,为什么不用其他方案都会说明. 可能有的小伙伴只是想找数据库做参考,帮忙帮到底,点击下载 概述 像酒 ...

  4. [转载]学习数据库分表和分库思想

    目录: 基本思想之什么是分库分表 基本思想之为什么要分库分表 分库分表的实施策略 何谓垂直切分 何谓水平切分 应该使用哪一种方式来实施数据库分库分表这要看数据库中数据量的瓶颈所在并综合项目的业务类型进 ...

  5. 数据库面试 - 如何设计才可以让系统从未分库分表动态切换到分库分表上?

    数据库面试 - 如何设计才可以让系统从未分库分表动态切换到分库分表上? 面试题 现在有一个未分库分表的系统,未来要分库分表,如何设计才可以让系统从未分库分表动态切换到分库分表上? 面试官心理分析 你看 ...

  6. 数据库面试 - 如何设计可以动态扩容缩容的分库分表方案?

    数据库面试 - 如何设计可以动态扩容缩容的分库分表方案? 面试题 如何设计可以动态扩容缩容的分库分表方案? 面试官心理分析 对于分库分表来说,主要是面对以下问题: 选择一个数据库中间件,调研.学习.测 ...

  7. MapReduce原理与设计思想

    转自:http://www.cnblogs.com/archimedes/p/mapreduce-principle.html 简单解释 MapReduce 算法 一个有趣的例子 你想数出一摞牌中有多 ...

  8. 数据库Sharding的基本思想和切分策略

    为什么80%的码农都做不了架构师?>>>    本文着重介绍sharding的基本思想和理论上的切分策略,关于更加细致的实施策略和参考事例请参考我的另一篇博文:数据库分库分表(sha ...

  9. MyBatis源码-深入理解MyBatis Executor的设计思想

    文章目录 Pre JDBC的执行过程 JDBC Demo JDBC Statement 接口 MyBatis执行过程 四大组件 组件之间的关系 Executor 执行器组件 架构总览 接口继承关系 P ...

最新文章

  1. 辗转相除法是求两个数的最大公约数的方法。
  2. 在C#中调用windows API函数
  3. jbuilder2006注册机
  4. linux 7 zip软件下载,linux安装使用7zip教程
  5. js中直接对字符串转义-用于solr ulr 关键词转义
  6. Android 原生通知Notification 写法
  7. 一名全栈工程师的必备“百宝箱”
  8. android根据中心裁剪图片,拍照,选择照片并进行裁剪,适配Android 7.0
  9. Windows Server 2008 Server Core模式
  10. Java从零开始(4)——入门项目
  11. 隐藏在SWT、Swing、AWT背后的故事
  12. c语言扣血题目,食品分析复习题(改)
  13. 一步一步asp.net_删除模块设计
  14. 【Urule源码解析1】开源可视化规则引擎
  15. WORD 或者 Outlook 提示“无法创建工作文件,请检查临时环境变量” 的解决方法
  16. Windows中 JDK下载与安装教程 JAVA环境变量配置、JDK基本介绍
  17. 如何防止iOS工程师简历石沉大海的几大秘技(请注意查收)
  18. 树莓派3B+使用GPIO实现串口通信
  19. 2021安防视频监控运维市场回顾和展望
  20. 计算机模拟量与数字量的转换,PLC开关量与模拟量编程数值转换原理

热门文章

  1. QLoo graphql engine 学习二 基本试用(kubernetes)
  2. Deepin 系统下安装VMware并激活
  3. parceljs 中文文档24小时诞生记
  4. idea-解决安装及各种问题
  5. android安全攻防实践_Android安全攻防实战 PDF 下载
  6. 【李宏毅2020 ML/DL】P45-50 Network Compression
  7. C#笔记06 面向对象和类
  8. wps一直显示正在备份怎么办_笔记本电脑显示器一直闪动怎么办
  9. Html5学习进阶一 视频和音频
  10. Centos 启用网卡出现 no link present. Check cable