1.单表数据量太大
某日上午小C发现业务表所占空间达到了10G,惊恐的叫到:"哦,My God。我们的业务表要撑爆了,已经达到了1千多万条记录了。我要优化数据库提升查询操作性能!"。于是小C找到了公司的DBA,告诉DBA:"我所管理的业务数据量已经达到了千万级别,需要分库分表来提升性能了。你赶紧给我弄一下分库分表吧!"。公司DBA看看小C一脸期待的样子,马上动起手来开启业务表分库分表的操作。经过漫长的操作,DBA告诉小C已经搞定了分库分表。小C看看每个小表中才几百万的数据量,心里美滋滋的说这岂不是查询速度能够快上很多倍~~~
小C觉得分库分表提升了业务表的查询性能,开始向组内其他成员来推广分库分表的实操经验。小C在跟老鸟介绍新技能--分库分表之术时,老鸟突然觉得事情并不是这么简单。于是便有了以下的对话:
老鸟: 你用的数据库存储引擎是哪个?
小C: 当然是InnoDB呀,这还用问。
老鸟: 那这种数据库存储引擎使用那种索引呢?
小C: B+树别,还能有啥子哦。
老鸟: 那感觉你这个分库分表提升不了数据库查询性能。
小C: What?不应该呀。
老鸟: 来先复习一下B+树。
2. B+树
老鸟: B+树是常用的外部文件存储的管理方案,通常用于数据库和操作系统的文件系统中。B+树是多路平衡查找树,能够保持数据稳定有序,其插入与修改拥有较稳定的对数时间复度。
B+树中只有叶节点才真正的拥有需要管理的数据,而中间节点仅仅包含排序好的Key值与其相关的指针,其图形如下.图中d1,d2....d3,d4等等指向真正的数据存储位置,而图中节点均为
中间节点,仅包含key值+指针的集合。
图(1) B+树图示
老鸟:至此,我们已经基本复习完了B+树的概念。如有疑惑,请自行谷歌。
小C:OK,这些基本信息我都掌握了。我们继续吧。
老鸟:那我们说说InnoDB的内存管理吧。
3. InnoDB的内存管理
老鸟: InnoDB是我们常用的存储引擎,其管理内存主要由以下部分组成:
a. 缓冲池(重点)
b. LRU list、Free list、Flush list
c. 重做日志缓冲
缓冲池有以下几部分组成,如下图所示
图(2) InnoDB存储引擎中缓冲池图示
老鸟:InnoDB采用页的方式来管理内存,至于页内存储的是数据还是索引或者其他数据,都能根据其自身相关的标识来识别。至于缓冲池的其他组成部分不是我们探讨的重点,我就不再进行解释了。
小C:哦,原来InnoDB是采用页的方式来管理缓冲池呀!这岂不是跟Linux的页式内存管理很像。
老鸟:对头,它们都是一脉相承的。在高科技的技术都是搭建在基础知识之上的,并且这些基础的知识可能几十年都不会改变。
小C:,我已经了解了InnoDB的缓冲池管理方式,以页为单位进行管理。
老鸟:那我们看看分库分表真的是提高数据库查询效率的银弹吗?
4. 分库分表真的是提高查询效率的银弹吗
老鸟:InnoDB存储引擎使用B+树来管理数据库表数据,按照页来分配管理缓冲区。B+树能够存放的记录数量的计算规则如下: 根节点指针数*单个叶子节点记录行数。 我们假定页大小为
16K(InnoDB系统默认大小),主键为8个字节,指针为6个字节(InnoDB系统默认大小),数据库表的单行数据大小为1K。那么我们通过计算可知每个页能够存储16个数据(这里为了计算方
便,忽略页内的管理信息所占字节数)。每个页索引的大小为14个字节(8个字节主键+6个字节指针),每个页能够存储的索引个数为1170个。由此可见
当树高为2时,可以存储1170*16=18720条记录。
当树高为3时,可以存储1170*1170*16=21902400条记录。
当树高为4时,可以存储1170*1170*1170*16=25625808000条记录。
由此可见,我们常见的应用中单表的索引B+树层高基本为3-4级左右。
老鸟:数据库查询过程时,先将页加载到内存中,然后在页内采用折半查找。由于折半查找操作是在内存中实现,这部分耗时对比页加载可以忽略不计。因此影响查询效率的部分是页的加
载过程(从磁盘到内存的过程),所以IO的次数成为了重要的衡量指标。
小C:那根据你提供的这个公式计算,我今天把单表数据量从千万级降到分库分表的百万级,并没有降低树高。查找的IO次数也没有减少,那岂不是没有什么用?
老鸟看了垂头丧气的小C,说到:也不是没有用,采用分库分表的方式能够提升整个表的事务吞吐量,并且采用多机的方式能够保证数据表不会频繁的进行内存与外存之间切换,从而降低
系统的性能。
小C:看来分库分表对于系统也有很大帮助,但要根据场合进行使用。这种方法也不是提升查询效率的银弹!
老鸟:对,所有设计都是有利有弊的。需要根据场景进行取舍,不能一味的认为某种技术能够解决一切问题。