zoukankan      html  css  js  c++  java
  • mysql 分表技术浅析

    Mysql系统的分表技术浅析

    *一、案例描述

    智能交通项目中,随着城市车辆日渐繁多,数据量急剧增大,主表的无限制增长势必影响系统性能。为了使数据库保持在较好性能,需要采用分表机制。

    首先要了解为什么要分表及其分表的好处是什么。我们先数据库执行SQL的过程:

    接收到SQL --> 放入SQL执行队列 --> 使用分析器分解SQL --> 按照分析结果进行数据的提取或者修改 --> 返回处理结果.

    这意味着如果前一个SQL没有执行完毕的话,后面的SQL是不会执行的,因为为了保证数据的完整性,必须对数据表文件进行锁定,包括共享锁和独享锁两种锁定。共享锁是在锁定的期间,其它线程也可以访问这个数据文件,但是不允许修改操作,相应的,独享锁就是整个文件就是归一个线程所有,其它线程无法访问这个数据文件。

    一般MySQL中最快的存储引擎MyISAM,它是基于表锁定的,就是说如果一锁定的话,那么整个数据文件外部都无法访问,必须等前一个操作完成后,才能接收下一个操作,那么在这个前一个操作没有执行完成,后一个操作等待在队列里无法执行的情况叫做阻塞,一般我们通俗意义上叫做“锁表”。

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

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

    *二、案例分析和解决

    下面给出几种分表的操作思路和基本步骤:

    第一招、基于基础表的分表处理

    其基本思路在于将业务分为主要表和基础表,其中主要表保存所有的基本信息,如果业 务需要使用到具体数据,则必须从基础表中寻找指定的表名等。

    以智能交通的过车数据为例,过车信息主要包含  车牌号等车牌信息,图片信息(图片路径、图片大小等),其余信息(如时间、违法类型等)。所以我们可以把过车信息表设计为基础信息表,将车牌信息表和图片信息表设计为业务表。

    过车信息、车牌信息表、图片信息表的大小关系如下:过车信息<车牌信息表<图片信息表。

    因此我们可以针对车牌信息表和图片信息表做分表操作。我们加深我们的表信息如下

    Passvehicle_tb表

    基础表ID   INT(10)

    数据类型名称  char(50)

    子表ID   INT(10)   

    车牌表Plate_tb  表

    车牌表ID   INT(10)

    基础表ID   INT(10)

    图片表Picture_tb表

    图片表ID   INT(10)

    车牌表ID   INT(10)

    我们有一条Passvehicle_tb的记录为:

    基础表ID 车牌类型 子表ID

        1          蓝牌       1

    那么我们根据Passvehicle_tb可以组合出指标的名字,比如blueplate_1。然后所有的蓝牌过车数据就保存到blueplate_1中。

    当我们的车牌种类比较少的时候,那么这种做法可能没有什么好处,但当数据类型多的时候,那么对于数据的插入、查找将有非常大的提高。

    比如我们要查找所有的蓝牌车辆的过车信息。我们就可以直接搜索:select *from bluePlate_1 where baseinfoid=1;

    当某一个地方蓝牌车辆非常多的情况下,我们可以根据尾牌来进行分表。这时候我们的子表ID可以更加丰富,比如以尾号为区分,把所有的蓝牌过车分为:blueplate_0、blueplate_1...blueplate_9这样的10个数字。

    这种方式的处理优缺点如下:

    【优势】增加删除节点非常方便,为后期升级维护带来很大便利

    【劣势】需要增加表或者对某一个表进行操作,还是无法离开数据库,会产生瓶颈

    第二招、基于Hash算法的分表

    Hash表就是通过某个特殊的Hash算法计算出的一个唯一值,且可以使用这个计算出来的值查找到需要的值,这个叫做哈希表。

    分表的设计原理跟这个思想类似:通过一个原始目标的ID或者名称通过一定的hash算法计算出数据存储表的表名,进而可以访问相应的表。

    继续以交通信息表为例,每一个基础表的id和车牌信息的id是唯一的,这两项值是固定的,并且是惟一的,那么我们就可以考虑通过对这两项值中的一项进行一些运算得出一个目标表的名称。

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

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

    int get_hash(int id){

    String str = bin2hex(id);

    String hash = substr(str, 0, 4);

         if (strlen(hash)<4){

             hash = str_pad(hash, 4, "0");//不足4位则补齐

         }

         return StringToIni(hash);

    }

    算法大致就是传入一个基础信息表ID值,然后函数返回一个4位的数字。比如:get_hash(1),输出的结果是“3100”,输入:get_hash(23819),得到的结果是:3233,我们继续经过简单的跟表前缀组合,就能够访问这个表了。那么我们需要访问ID为1的内容时候哦,组合的表将是:plate_3100、picture_3100,那么就可以直接对目标表进行访问了。

    这里要说明的是,即使使用hash算法后,有部分数据是可能在同一个表的,这一点跟hash表不同,hash表是尽量解决冲突,但我们不需要,我们只需要做好预测和分析表数据可能保存的表名,且数据的合理分配。

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

    总之,使用hash方式的话必须选择好的hash算法,才能生成更多的表,使数据查询的更迅速。

    【优点hash算法直接得出目标表名称,效率很高】

    【劣势】扩展性比较差,选择了一个hash算法,定义了多少数据量,以后只能在这个数据量上跑,不能超过过这个数据量,可扩展性稍差

    第三招、基于重命名表明的分表技术

    这种分表技术适用于将数据库主表的某一个字段作为分表的依据字段,还是以过车信息表为例,所有的过车数据都集中在1~12这12个月份中。我们完全可以把数据分为vehicle_2011_01、vehicle_2011_02...vehicle_2011_12这样的12张表中。

    这时候我查询某一个时间段的数据、统计某一个月份的数据就不需要多表查询(因为很多查询操作发生在查询本月的过车信息中)。但是如果你的查询操作经常发生在多个月份的联合查询那么这种分表技术就不是很适合了。

    每个月初建立一张以月为单位的新表用来存储过去一个月的数据,此外有一张表明不变的数据表,该表是用于暂时存储新的一个月的数据的。不妨命名为my_table,那这张表是一直存在的,比如现在是十一月二号,那六月份的数据就暂时存储在这张表中,这时候首先需要my_table变名,

    rename table my_table to table_2011_10; 这时候就重新命名了my_table这张表,但是原来的my_table这张表还是存在的,但所有的数据都已经存储在table_2011_11这张表,需要注意的时rename期间表是锁定的。但采用rename进行批处理的好处,大量的数据不需要在进行转移的时候不需要进行导出和导入的操作,那样效率会很低,而且对数据库造成的压力会很大,

    在重新命名了my_table这张表后需要重新要创建my_table这张表,CREAT my_table (.......)

    table_2011_10 原则上存储的都是十月份的数据,但是因为是三号才进行这个操作,所以肯定是十一月一号到三号的数据还是存储到了table_2011_10 这张表上,那就需要从这张表中把一号到三号的数据重新查找出来插入到my_table (暂时存储的是10月份的数据)

    insert into my_table (field1,field2....) SELECT field1,field2....FROM my_table_2011_10 WHERE filed3 >= "2011-11-01"; 这样就把一号到三号的数据存入到了暂时存储六月份数据的my_table ,每到新月份时时还要对该表进行重复的操作进行分表处理,但my_table 这张表保持不变,每次插入的sql语句就不用改了,但是进行查询的时候就需要对时间进行判断,以确定具体查找那一张表,因为我们已经进行了分表操作。

    这样每个月初都重复这样一个操作,分表就顺利实现,且进行插入时还要进行此操作:

    Alter table my_table max_rows=10000000 avg_row_length=15000;这样操作的好处是保证表存储好大量数据(超过2G)的数据(如果是数据量很小的话就不需要进行这个操作了)

    三、总结

    在大负载应用当中,数据库一直是个很重要的瓶颈,必须要突破,现在客户的要求越来越高,在保证数据的稳定性的基础上,本文粗略讲解了两种分表的方式,仅起到抛砖引玉的作用。当然,本文代码和设想没有经过严谨推敲,所以无法保证设计的完全准确实用,见谅!

  • 相关阅读:
    R语言初涉
    Android源码大全
    Centos关闭防火墙
    Java开发常用下载的网址
    linux下解压命令大全
    Android常见布局问题
    配置Nutch模拟浏览器以绕过反爬虫限制
    Nutch的发展历程
    用三层交换机当路由器——最复杂的网络拓扑结构
    Ant 简易教程
  • 原文地址:https://www.cnblogs.com/xianqingzh/p/2267396.html
Copyright © 2011-2022 走看看