公元前五百年,孙子就已参透了数据库分区的真谛

发布时间:2019-07-01作者:spider阅读(170)

如果说,一个编程者(并非一个职业DBA)除了关注表结构本身以外,分区,可能就是所需要关注的最靠近底层的一个数据库的设计。

    数据库分区,我觉得是一个称得上“伟大”的数据库存储结构概念。

    如果说,一个编程者(并非一个职业DBA)除了关注表结构本身以外,分区,可能就是所需要关注的最靠近底层的一个数据库的设计。

    例如像数据库的表空间这样的概念,通常一个普通开发人员,就未必会去关注。但是分区概念却不一样,因为它与应用场景结合更加紧密。比如,按时间、按地区、按类别分区,等等。

    我猜测很多人是不赞同「数据库分区是个“伟大”的概念」这个观点的。原因是,我翻阅了各种市面上主流数据库的书籍,入门级的如《XX数据库从入门到删库跑路》,看起来高端的如《XX数据库的技术内幕》,大部分书籍在介绍分区的内容的时候,都没有给很大的篇幅。

    甚至有好几本书上,就这么简单的来了一句:对于一个很大的表,如果每次搜索都对全表进行扫描,会很耗时间,如果分区了之后,只要访问某个分区就会很快。

    这难道不是一种误导么?分区真的能这么简单就讲清楚吗?我觉得当然不是,所以本文的内容就是想说说我认为的,分区的重要和伟大之处。

    一、数据库为什么要有分区?

    在《孙子兵法》的第五篇 —《兵势篇》中,孙子曰:凡治众如治寡,分数是也。斗众如斗寡,形名是也。

    说人话:凡是在管理很大的数据库表时就和管理小的数据库表时一样,把它分区就好了;发挥好所有分区的功能就和发挥好其中一个分区的功能一样,他们能有一个统一的表名,可以使用统一的SQL语句来调度就好了。

    上面这段话,从分号隔开,可以分成上下两句。那么“伟大”是在于前半句还是后半句呢?显然是后半句。为啥?你把人分了容易,但是你要把茫茫多的已经分开的人,指挥得像一个人一样,这件事情就伟大了。

    1、考虑隔离与瓶颈

    好,先讨论上半句,分治的思想。我常常遇到这样的对话场景。

    场景一:

    对话者:“我们的数据太大了,我们分表吧!”

    我:“为什么不用分区呢?”

    对话者:“分区可以解决吗?”(请自己脑补不信任的眼神和质疑的语气)

    场景二:

    演讲者:“我们考虑用最先进的分库技术理念来解决这个瓶颈”。

    众人投去了羡慕嫉妒而又膜拜的眼神,等待着大神讲出华丽又牛叉的方案。

    我:“这里有个瓶颈,我们需要给这个表分区。”

    众人轻视又不懈说,好的,那分一下吧。

    其实无论是分区、分表还是分库,我们都需要围绕两个重要概念,一是隔离,一是瓶颈。

    在场景一种,为什么使用者要求分表呢?常见的情况中,例如,我这两个表,虽然结构一样,但是我一个是北京的数据,一个是上海的数据。如果北京的数据坏了,或者,我在对北京的数据进行奇奇怪怪的操作的时候,我需要对上海的数据完全没有影响,这就是所谓隔离。

    又比如,可能全国的数据放在一起量太大,交易量太多,出现了,磁盘、IO、网络、CPU等撑不住的情况,这就是所谓瓶颈。

    分区、分表、分库满足的是不同的隔离级别,以及解决不同的瓶颈。但是,他们的思想是非常接近的。

    2、Partition与Sharding

    Sharding这个词(通常译为分片),可以说是自带高贵的属性。每当与人讨论数据库技术,一聊到Sharding,就有一种自然而然上档次的感觉。

    而且,它有很多好朋友,说出来各个华丽无比,比如分布式、集群、大数据等等。

    而Partition这个词,虽然从很多角度上来看,都很类似于Sharding,或者说它们都是从“分数是也”的理念而来。但就是感觉LOW。

    为啥?按我的理解,因为Partition的实现是由DBMS来完成的,使用者没感觉。而Sharding往往需要程序,设计模式,乃至整个架构的设计围绕着它服务,十分有存在感。

    那它们在实际运用的时候有区别吗?当然有!那么什么时候应该Sharding,什么时候应该Partition呢?

    我个人觉得Sharding的使用有两种情况,第一种叫没钱的时候,第二种是Partition用到极致,也搞不定的时候。

    那么Partition什么时候搞不定呢?又有两种,一种叫没钱的时候,第二种叫超过了当今世上的硬件极限(买最贵的设备都抗不住)的时候。

    1)没钱的时候

    我们细细思量可以发现,分库分表这个套路在什么数据库上用的范围最广?或者你在什么地方见得会比较多?我觉得通常会指到同一个地方,叫MySQL。

    虽然它有各种各样华丽的马甲,比如腾讯的TDSQL。为什么要用MySQL?因为开源免费。什么?InnoDB也很强大?如果明天Oracle开源免费,你选型的时候还会选MySQL?

    不扯远了,MySQL为啥有那么多分库分表呢?我认为真相只有这一个。因为5.1版之前,MySQL不支持分区。这就是我说的第一种情况,叫没钱的时候,Oracle、SQL Server、DB2我通通买不起。好了,下一个免费的MySQL,做分库分表。

    抛开玩笑的内容,Partition确实有解决不掉瓶颈需要使用分库分表的时候。但是,一个成熟的数据库使用者不应该滥用分库分表。这就是所谓DBA界分库铁律第一条,我非常赞同,叫做:能不分,就不分。然后,说说,第二种,Partition用到了极致的场景。

    2)超过当前硬件极限

    简单的说,我买了个Oracle,但是我的系统TPS要1万。在X86上跑Oracle,撑不住怎么办?

    那么出路两条,第一条,Exadata了解一下?IBM主机买一台?买不起,好,我们在MySQL,或者X86上用Oracle做分库分表,这就是第二类里面的没钱的时候。

    还有一种就是Exadata、IBM主机撑不住,所谓超越了地球上科技产品的极限,反正我没见过。

    3、分库、分表、分区的使用场景

    看到这里,是不是觉得扯淡内容太多了。到底什么情况分区?什么情况分表?什么时候分库呢?还是那句话,第一看隔离级别,第二看瓶颈。前一段主要说的是瓶颈场景,那么从隔离级别上来看呢?

    1)分库选择

    两份结构一样的数据。但他属于两个客户,客户说,我有监管要求,我不能把数据和别人的数据放在一起,必须绝对的隔离,有严格的访问控制,别人根本不能有我的DB服务器的登陆权限。

    这就要求,数据在数据库层面就完全的隔开,就可以用分库。

    2)分表选择

    如果说我是一个云提供商,两个客户都用我的客户,他们分别有自己的用户(Schema),他们允许和他人共用数据库服务器,但是,严禁其他人使用归属于他的数据库表。

    那么这时候,可以分表。

    3)分区选择

    如果,两份数据要求简单的隔离,相互处理不影响就可以了,有时候,我还希望一个用户一条SQL,就能对比分析他们的差异。

    那这时候,分区就是一个极佳的选择。

    二、数字库分区的优势

    接下来讲后半部分,斗众如斗寡,形名是也。

    1、分区的同时处理掉技术关口

    斗众如斗寡,这句话讲起来简单,实现起来可不是那么简单。在主流的DBMS里面,不同的分区意味着不同的对象(如Oracle中,不同的Segment,DB2分区表不同分区对应数据文件)。

    不夸张的说,很多数据库中间件产品,在反复纠缠、实现的内容,其本身就是主流DBMS在分区时要处理掉的技术关口。

    比如有:跨库的SQL重写,一个运行在分布式场景的SQL,需要被中间件重写成多个SQL,丢到多个库去执行。尤其是,跨库的连结、聚合(包括Max、Min、Sum、Count)。其实在多分区的时候,一样存在这样的问题。

    如果说这个问题,不太容易被开发者所关注到。再举一个例子:全局/本地索引。

    在DBMS中,全局索引通常是要在设计上有所回避的。一般数据表一旦分区,意味着数据量比较大。例如最常见的B树索引,全局索引意味索引层次多,查询速度慢。

    但是当无论如何,我在查询时,无法送入分区KEY时,全局索引总归还是最后的选择。而在分布式场景里,没有分库KEY就会非常尴尬,要么查不了,要么就要遍历所有的库,这个代价几乎就是不可接受的。

    2、分区与优化密不可分

    分区和分库面临的很多问题都存在着巨大的相似之处,开发者总是会重视分库所面临问题和困难,然而普遍会轻视分区可能带来的副作用。

    我常常被质问,数据多了,为什么不加分区!?并发有冲突,为什么不加分区!?程序速度慢了,为什么不加分区!?PS:这一系列的质问,同样适用于为什么不加索引系列。

    这种轻视源自于,主流DBMS系统对分区功能的很好的支撑。作为DBA,比较害怕的是有人懂一点数据库,且特别自信的站在他自己立场来和我讨论。

    有一些开发者传递给我一个理念,分区多比分区少要好。只要用了分区,就能更快,至少不可能更差!开发者在说起这些的时候,非常的自信。

    其实,在我看来分区设计和查询优化是密切相关的。分区设计一定是与特定的查询场景匹配,才能达到好的结果。

    比如之前提到的没有分区列送入的查询需要逐个遍历每个分区,再比如说Hash分区后的范围查找。

    Oracle中索引的Hash分区,在大规模的高并发插入的数据库表上应用十分常见,因为这种场景非常容易产生冲突事件 ,使用Hash分区之后,可以极大的缓解。然而这也挖下了一个坑,那就是这个索引上的范围查找就变得不那么理想。

    由此推论,分区上可以能遇到的大坑,其实在分库的场景同样使用。

    比如说,做了分库,却发现交易的业务场景拿不到Sharding Key。采用了Hash的算法,算Sharding Key,又突然发现有个交易要范围查Sharding Key,以至于可能要去各个库兜一圈。

    分区面对的坑,可以说在分库场景下,是急剧放大了。所以,不可以随意滥用分区,更加不可以随便乱分库。

    3、容错率提高

    反过来讲,我为何在开篇说分区十分伟大,尤其是Oracle。在你违背了种种优化原则之后,做了NPI,做了跨分区的JOIN等等。尽管有性能上的损失,无论如何,数据库都帮你把那些复杂的工作给完成了。

    当你的需求不是实时响应时,这些奇奇怪怪的跨分区要解决的问题,Rdbms都还是透明的把这些工作给你做完了,这怎么能不说它是伟大的呢?这一点我想那些开发分布式数据库中间件的人,最能认同。

    三、写在最后

    最后写到这里,作为一个DBA,我特别希望给程序开发者传递一个理念,那就是这世界上一定没有一个完美的优化方案。

    你要一个表,又能高并发插入,又能做各种各样高效的查询,一会范围,一会模糊。我只想说,这是不可能的。所有优化方案都是以牺牲某一种性能来换另一种性能。

    而DBA的职责,就是搞清楚业务需要什么,不需要什么。牺牲掉不需要的功能,换取需要的功能,甚至于牺牲不常用的功能,换取优异的常用功能。这其实就是完美的方案,分区也不例外。

    在本文的最后,我想留一个我一直困惑的问题。在我看了无数篇分库分表放在一起的文章和帖子之后,我开始怀疑人生了。

0 +1

版权声明

本文章为系统自动抓取,如涉及您的版权,请联系博主进行下架处理

 数据库  mysql  说说

 请文明留言

0 条评论