Mysql千万级大表优化

Mysql的单张表的最大数据存储量尚没有定论,通常状况下mysql单表记录超过千万之后性能会变得不好。所以,总结一些相关的Mysql千万级大表的优化策略。java

 

1.优化sql以及索引

 

1.1优化sql

一、有索引但未被用到的状况(不建议)

(1)避免like的参数以通配符开头mysql

尽可能避免Like的参数以通配符开头,不然数据库引擎会放弃使用索引而进行全表扫描。算法

以通配符开头的sql语句,例如:select * from t_credit_detail where Flistid like '%0'\Gsql

这是全表扫描,没有使用到索引,不建议使用。数据库

不以通配符开头的sql语句,例如:select * from t_credit_detail where Flistid like '2%'\G后端

很明显,这使用到了索引,是有范围的查找了,比以通配符开头的sql语句效率提升很多。缓存

(2) 避免where条件不符合最左前缀原则。最左前缀原则:mysql会一直向右匹配直到遇到范围查询(>、<、between、like)就中止匹配,好比a = 1 and b = 2 and c > 3 and d = 4 若是创建(a,b,c,d)顺序的索引,d是用不到索引的,若是创建(a,b,d,c)的索引则均可以用到,a,b,d的顺序能够任意调整(IN和=能够乱序)。服务器

(3) 使用!= 或 <> 操做符时网络

尽可能避免使用!= 或 <>操做符,不然数据库引擎会放弃使用索引而进行全表扫描。使用>或<会比较高效。架构

select * from t_credit_detail where Flistid != '2000000608201108010831508721'\G

(4) 避免索引列参与计算

应尽可能避免在 where 子句中对字段进行表达式操做,这将致使引擎放弃使用索引而进行全表扫描。

select * from t_credit_detail where Flistid +1 > '2000000608201108010831508722'\G

(5) 避免对字段进行null值判断

应尽可能避免在where子句中对字段进行null值判断,不然将致使引擎放弃使用索引而进行全表扫描,如: 低效:select * from t_credit_detail where Flistid is null ;

能够在Flistid上设置默认值0,确保表中Flistid列没有null值,而后这样查询: 高效:select * from t_credit_detail where Flistid =0;

(6) 避免使用or来链接条件

应尽可能避免在where子句中使用or来链接条件,不然将致使引擎放弃使用索引而进行全表扫描,如: 低效:select * from t_credit_detail where Flistid = '2000000608201108010831508721' or Flistid = '10000200001';

能够用下面这样的查询代替上面的 or 查询: 高效:select from t_credit_detail where Flistid = '2000000608201108010831508721' union all select from t_credit_detail where Flistid = '10000200001';

二、避免select *

在解析的过程当中,会将'*' 依次转换成全部的列名,这个工做是经过查询数据字典完成的,这意味着将耗费更多的时间。

因此,应该养成一个须要什么就取什么的好习惯。

三、order by 语句优化

任何在Order by语句的非索引项或者有计算表达式都将下降查询速度。

方法:1.重写order by语句以使用索引;2.为所使用的列创建另一个索引 3.绝对避免在order by子句中使用表达式。

四、GROUP BY语句优化

提升GROUP BY 语句的效率, 能够经过将不须要的记录在GROUP BY 以前过滤掉(以下例,先用where语句过滤掉一部分数据)

低效:

SELECT JOB , AVG(SAL)
FROM EMP
GROUP by JOB
HAVING JOB = ‘PRESIDENT'
OR JOB = ‘MANAGER' 

高效:

SELECT JOB , AVG(SAL)
FROM EMP
WHERE JOB = ‘PRESIDENT'
OR JOB = ‘MANAGER'
GROUP by JOB

五、用 exists 代替 in

不少时候用 exists 代替 in 是一个好的选择: select num from a where num in(select num from b) 用下面的语句替换: select num from a where exists(select 1 from b where num=a.num)

六、使用 varchar/nvarchar 代替 char/nchar

尽量的使用 varchar/nvarchar 代替 char/nchar ,由于首先变长字段存储空间小,能够节省存储空间,其次对于查询来讲,在一个相对较小的字段内搜索效率显然要高些。

七、能用DISTINCT的就不用GROUP BY

SELECT OrderID FROM Details WHERE UnitPrice > 10 GROUP BY OrderID

可改成:

SELECT DISTINCT OrderID FROM Details WHERE UnitPrice > 10

八、能用UNION ALL就不要用UNION

UNION ALL不执行SELECT DISTINCT函数,这样就会减小不少没必要要的资源。(UNION ALL容许重复

九、在Join表的时候使用至关类型的例,并将其索引

若是应用程序有不少JOIN 查询,你应该确认两个表中Join的字段是被建过索引的。这样,MySQL内部会启动为你优化Join的SQL语句的机制。

并且,这些被用来Join的字段,应该是相同的类型的。例如:若是你要把 DECIMAL 字段和一个 INT 字段Join在一块儿,MySQL就没法使用它们的索引。对于那些STRING类型,还须要有相同的字符集才行。(两个表的字符集有可能不同)

SELECT Persons.LastName, Persons.FirstName, Orders.OrderNo
FROM Persons
INNER JOIN Orders
ON Persons.Id_P = Orders.Id_P
ORDER BY Persons.LastName

 

1.2优化索引

不少数据库系统性能不理想是由于系统没有通过总体优化,存在大量性能低下的SQL 语句。这类SQL语句性能很差的首要缘由是缺少高效的索引。没有索引除了致使语句自己运行速度慢外,更是致使大量的磁盘读写操做,使得整个系统性能都受之影响而变差。解决这类系统的首要办法是优化这些没有索引或索引不够好的SQL语句。优化SQL语句的关键是尽量减小语句的logical reads(是指语句执行时须要访问的单位为8K的数据页) logical reads 越少,其须要的内存和CPU时间也就越少,语句执行速度就越快。不言而喻,索引的最大好处是它能够极大减小SQL语句的logical reads数目,从而极大减小语句的执行时间。建立索引的关键是索引要可以大大减小语句的logical reads。一个索引好很差,主要看它减小的logical reads多很少。 运行set statistics io命令能够获得SQL语句的logical reads信息。Logical reads中包含该语句从内存数据缓冲区中访问的页数和从物理磁盘读取的页数。而physical reads表示那些没有驻留在内存缓冲区中须要从磁盘读取的数据页

1对出如今where子句中的字段加索引

 全表扫描的性能一般是不好的,要尽可能避免。 建立索引的技巧之一是对常常出如今where条件中的字段建立索引

 2.组合索引

 单字段索引是指只有一个字段的索引,而组合索引指有多个字段构成的索引。若是where语句中有多个字段,那么能够考虑建立组合索引。组合索引中字段的顺序是很是重要的,越是惟一的字段越是要靠前。(根据最左前缀准则)另外,不管是组合索引仍是单个列的索引,尽可能不要选择那些惟一性很低的字段。因此若是对单字段进行索引,建议使用set statistics profile(会输出语句的执行计划)来验证索引确实被充分使用。logical reads越少的索引越好。

 3.覆盖索引

 覆盖索引可以使得语句不须要访问表仅仅访问索引就可以获得全部须要的数据。 由于汇集索引叶子节点就是数据因此无所谓覆盖与否,因此覆盖索引主要是针对非汇集索引而言。执行计划中除了index seek外,还有一个Bookmark Lookup关键字。 Bookmark Lookup表示语句在访问索引后还须要对表进行额外的Bookmark Lookup操做才能获得数据。也就是说为获得一行数据起码有两次IO一次访问索引,一次访问基本表。 若是语句返回的行数不少,那么Bookmark Lookup操做的开销是很大的。 覆盖索引可以避免昂贵的Bookmark Lookup操做,减小IO的次数,提升语句的性能。 覆盖索引须要包含select子句和WHERE子句中出现的全部字段。因此建立覆盖索引是减小logical reads提高语句性能的很是有用的优化技巧。

 问题1,是否值得在identity字段(自增字段)上创建汇集索引。

 答案取决于identity 字段如何在语句中使用。若是你常常根据该字段搜索返回不多的行,那么在其上创建索引是值得的。反之若是identity字段根本不多在语句中使用,那么就不该该对其创建任何索引。

  问题2,一个表应该创建多少索引合适。

 若是表的80%以上的语句都是读操做,那么索引能够多些。可是不要太多。 特别是不要对那些更新频繁的表其创建不少的索引。不多表有超过5个以上的索引。过多的索引不但增长其占用的磁盘空间,也增长了SQL Server 维护索引的开销。

 问题4:为何SQL Server 在执行计划中没有使用你认为应该使用的索引?缘由是多样的。

 一种缘由是该语句返回的结果超过了表的20%数据,使得SQL Server 认为scanseek更有效。另外一种缘由多是表字段的statistics过时了,不能准确反映数据的分布状况。你可使用命令UPDATE STATISTICS tablename with FULLSCAN来更新它。只有同步的准确的statistics才能保证SQL Server 产生正确的执行计划。  

问题5、什么使用汇集索引,何时使用非汇集索引

 SQL Server 中索引有汇集索引和非汇集索引两种。它们的主要差异是前者的索引叶子就是数据自己,然后者的叶子节点包含的是指向数据的书签(即数据行号或汇集索引的key)。来自汇集索引的键值由全部非汇集索引做为查找键使用,所以存储在每一个非汇集索引的叶条目内。对一个表而言汇集索引只能有一个,而非汇集索引能够有多个。只是汇集索引没有Bookmark Lookup操做。

 在建立汇集索引以前,应先了解您的数据是如何被访问的。可考虑将汇集索引用于:

1.      包含大量非重复值的列。

2.      使用下列运算符返回一个范围值的查询:BETWEEN>>=< <=

3.      被连续访问的列。

4.      返回大型结果集的查询。

5.      常常被使用联接或 GROUP BY 子句的查询访问的列;通常来讲,这些是外键列。 ORDER BY GROUP BY 子句中指定的列进行索引,可使 SQL Server 没必要对数据进行排序,由于这些行已经排序。这样能够提升查询性能。

 汇集索引不适用于:

1.      频繁更改的列,这将致使整行移动(由于 SQL Server 必须按物理顺序保留行中的数据值)。这一点要特别注意,由于在大数据量事务处理系统中数据是易失的。 

 

 

1.3缓存

1.4主从复制、主主复制

MySQL主从复制是其最重要的功能之一。主从复制是指一台服务器充当主数据库服务器,另外一台或多台服务器充当从数据库服务器,主服务器中的数据自动复制到从服务器之中。MySQL主从复制的基础是主服务器对数据库修改记录二进制日志,从服务器经过主服务器的二进制日志自动执行更新。

主从复制的做用

一、作数据的热备,做为后备数据库,主数据库服务器故障后,可切换到从数据库继续工做,避免数据丢失。

二、架构的扩展。业务量愈来愈大,I/O访问频率太高,单机没法知足,此时作多库的存储,下降磁盘I/O访问的频率,提升单个机器的I/O性能。(请求发到多部机子上)

三、读写分离,使数据库能支撑更大的并发。一主多从的部署方案,将涉及数据写的操做放在Master端操做,而将数据读的操做分散到众多的Slave当中。下降了Master的负载,提升数据写入的响应效率;多台从服务器提供读,分担了请求,提升了读的效率。在报表中尤为重要。因为部分报表sql语句很是的慢,致使锁表,影响前台服务。若是前台使用master,报表使用slave,那么报表sql将不会形成前台锁,保证了前台速度。

 

主从复制的原理

1.数据库有个bin-log二进制文件,记录了全部sql语句。

2.咱们的目标就是把主数据库的bin-log文件的sql语句复制过来。

3.让其在从数据的relay-log重作日志文件中再执行一次这些sql语句便可。

 

主从复制步骤以及涉及的线程:

一:主库db的更新事件(update、insert、delete)被写到binlog
二:从库发起链接,链接到主库
三:此时主库建立一个binlog dump thread线程,把binlog的内容发送到从库
四:从库启动以后,建立一个I/O线程,读取主库传过来的binlog内容并写入到relay log.
五:还会建立一个SQL线程,从relay log里面读取内容,从Exec_Master_Log_Pos位置开始

1.binlog输出线程:每当有从库链接到主库的时候,主库都会建立一个线程输出binlog,而后发送binlog内容到从库。
2.从库I/O线程:当START SLAVE语句在从库开始执行以后,从库建立一个I/O线程,该线程链接到主库并请求主库发送binlog里面的更新记录到从库上。(从主库先传输下来)从库I/O线程读取主库的binlog输出线程发送的更新并拷贝这些更新到本地文件,其中包括relay log文件(再更新relay log)
3.从库的SQL线程:从库建立一个SQL线程,这个线程读取从库I/O线程写到relay log的更新事件并执行。

 

作主从后主服务器挂了怎么办

假设发生了突发事件,master宕机,如今的需求是要将从库提高为主库,另一个为从库:

1.确保全部的从库的relay log所有更新完毕,在每一个从库上执行stop slave io_thread; show processlist;直到看到Has read all relay log,则表示从库更新都执行完毕了
2.登录全部从库,查看master.info文件,选择一个从库为新的主库
3.登录该从库,执行stop slave; 并进入数据库目录,删除master.info和relay-log.info文件, 配置my.cnf文件,开启log-bin,若是有log-slaves-updates和read-only则要注释掉,执行reset master
4.建立用于同步的用户并受权slave,同第五大步骤
5.登陆另一台从库,执行stop slave中止同步
6.根据第七大步骤链接到新的主库
7.执行start slave;
8.修改新的master数据,测试slave是否同步更新

主从复制延迟

主库针对读写操做,顺序写 binlog,从库单线程去主库读"写操做的binlog",从库取到 binlog在本地原样执行(随机写),来保证主从数据逻辑上一致.mysql的主从复制都是单线程的操做,主库对全部DDL和DML产生 binlog,binlog是顺序写,因此效率很高,slave的Slave_IO_Running线程到主库取日志,效率比较高,下一步问题来了,slave的 slave_sql_running线程将主库的 DDL和DML操做在 slave实施。DML,DDL的IO操做是随机的,不能顺序的,成本高不少,还有可能slave上的其余查询产生 lock,因为 slave_sql_running也是单线程的,因此 一个 DDL卡住了,需求需求执行一段时间,那么全部以后的DDL会等待这个 DDL执行完才会继续执行,这就致使了延迟.因为master能够并发,Slave_sql_running线程却不能够,因此主库执行 DDL需求一段时间,在slave执行相同的DDL时,就产生了延迟.

主从同步延迟产生缘由
当主库的TPS并发较高时,产生的DDL数量超过Slave一个 sql线程所能承受的范围,那么延迟就产生了,固然还有就是可能与 slave的大型 query语句产生了锁等待
首要缘由:数据库在业务上读写压力太大,CPU计算负荷大,网卡负荷大,硬盘随机IO过高
次要缘由:读写 binlog带来的性能影响,网络传输延迟
主从同步延迟解决方案
架构方面:mysql压力变小,延迟天然会变小
1.业务的持久化层的实现采用分库架构,mysql服务可平行扩展分散压力
2.单个库读写分离,一主多从,主写从读,分散压力。
3.服务的基础架构在业务和mysql之间加放 cache层
4.不一样业务的mysql放在不一样的机器
5.使用比主加更好的硬件设备做slave

1.5读写分离

 MySQL的主从复制和MySQL的读写分离二者有着紧密联系,首先部署主从复制,只有主从复制完了,才能在此基础上进行数据的读写分离。读写分离就是只在主服务器上写,只在从服务器上读,基本的原理是让主数据库处理事务性查询,而从数据库处理select查询,数据库复制被用来把事务性查询致使的改变动新同步到集群中的从数据库,即主从复制。

1.基于程序代码内部实现
在代码中根据select,insert进行路由分类,这类方法也是目前生产环境应用最普遍的,优势是性能好,由于在程序代码中实现,不须要曾加额外的设备做为硬件开支,缺点是须要开发人员来实现,运维人员无从下手。
2.基于中间代理层实现
代理通常位于客户端和服务器之间,代理服务器接到客户端请求后经过判断后转发到后端数据库,有两个表明性程序。
(1)mysql-proxy 为mysql开源项目,经过其自带的lua脚本进行SQL判断,虽然是mysql的官方产品,可是mysql官方不建议将其应用到生产环境
(2)Amoeba (变形虫)由陈思儒开发,曾就任与阿里巴巴,该程序由java语言进行开发,阿里巴巴将其应用于生成环境,它不支持事物和存储过程
经过程序代码实现mysql读写分离天然是一个不错的选择,可是并非全部的应用都适合在程序代码中实现读写分离,像一些大型复杂的java应用,若是在程序代码中实现读写分离对代码改动就较大,像这种应用通常会考虑使用代理层来实现。

 

MySQL Proxy是一个处于你的client端和MySQL server端之间的简单程序,它能够监测、分析或改变它们的通讯。它使用灵活,没有限制,常见的用途包括:负载平衡,故障、查询分析,查询过滤和修改等等。MySQL Proxy就是这么一个中间层代理,简单的说,MySQL Proxy就是一个链接池,负责将前台应用的链接请求转发给后台的数据库,而且经过使用lua脚本,能够实现复杂的链接控制和过滤,从而实现读写分离和负载平衡。对于应用来讲,MySQL Proxy是彻底透明的,应用则只须要链接到MySQL Proxy的监听端口便可。固然,这样proxy机器可能单点失效,但彻底可使用多个proxy机器作为冗余,在应用服务器的链接池配置中配置到多个proxy的链接参数便可。MySQL Proxy更强大的一项功能是实现“读写分离”,基本原理是让主数据库处理事务性查询,让从库处理SELECT查询。数据库复制被用来把事务性查询致使的变动同步到集群中的从库。

读写分离的好处:
1
)物理服务器增长,负荷增长 2)主从只负责各自的写和读,极大程度的缓解X锁和S锁争用 3)从库可配置myisam引擎,提高查询性能以及节约系统开销 4)从库同步主库的数据和主库直接写仍是有区别的,经过主库发送来的binlog恢复数据,可是,最重要区别在于主库向从库发送binlog是异步的,从库恢复数据也是异步的 5)读写分离适用与读远大于写的场景,若是只有一台服务器,当select不少时,update和delete会被这些select访问中的数据堵塞,等待select结束,并发性能不高。 对于写和读比例相近的应用,应该部署双主相互复制 6)能够在从库启动是增长一些参数来提升其读的性能,例如--skip-innodb、--skip-bdb、--low-priority-updates以及--delay-key-write=ALL 固然这些设置也是须要根据具体业务需求来定得,不必定能用上 7)分摊读取。假如咱们有1主3从,不考虑上述1中提到的从库单方面设置,假设如今1 分钟内有10条写入,150条读取。那么,1主3从至关于共计40条写入,而读取总数没变,所以平均下来每台服务器承担了10条写入和50条读取(主库不 承担读取操做)。所以,虽然写入没变,可是读取大大分摊了,提升了系统性能。另外,当读取被分摊后,又间接提升了写入的性能。因此,整体性能提升了,说白 了就是拿机器和带宽换性能。MySQL官方文档中有相关演算公式:官方文档 见6.9FAQ之“MySQL复制可以什么时候和多大程度提升系统性能” 8)MySQL复制另一大功能是增长冗余,提升可用性,当一台数据库服务器宕机后能经过调整另一台从库来以最快的速度恢复服务,所以不能光看性能,也就是说1主1从也是能够的。

 

1.6分区、垂直分表、水平分表

  • 表分区

表分区其实就是将一张大数据量表中的数据按照不一样的分区策略分配到不一样的系统分区、硬盘或是不一样的服务器设备上,实现数据的均衡分配,这样作的好处是均衡大数据量数据到不一样的存储介子中,这样每一个分区均摊了一部分数据,而后能够定位到指定的分区中,对数据表进行需求操做,另外,也方便管理水表,好比要删除某个时间段的数据,就能够按照日期分区,而后直接删除该日期分区便可,而且效率相对于传统的DELETE数据效率高不少,这里以Mysql为例进行说明。

分区和分表的区别:

分区和分表针对的都是数据表,而分表是真正的生成数据表,是将一张大数据量的表分红多个小表实现数据均衡;

分区并非生成新的数据表,而是将表的数据均衡分摊到不一样的硬盘,系统或是不一样服务器存储介子中,实际上仍是一张表。

另外,分区和分表均可以作到将表的数据均衡到不一样的地方,提升数据检索的效率,下降数据库的频繁IO压力值,

分区的优势以下:

一、相对于单个文件系统或是硬盘,分区能够存储更多的数据;

二、数据管理比较方便,好比要清理或废弃某年的数据,就能够直接删除该日期的分区数据便可;

三、精准定位分区查询数据,不须要全表扫描查询,大大提升数据检索效率;

四、可跨多个分区磁盘查询,来提升查询的吞吐量;

五、在涉及聚合函数查询时,能够很容易进行数据的合并;

表的分区的原理理解起来比较简单,其实就是把一张大数据量的表,根据分区策略进行分区,分区设置完成以后,由数据库自身的储存引擎来实现分发数据到指定的分区中去,正如上图所示,一张数据表被分红了n个分区,而且分区被放入到不一样的介子disk中,每一个disk中包含自少一个分区,这就实现了数据的均衡以及经过跨分区介子检索提升了总体的数据操做IO吞吐率。

表分区的策略:

目前在MySql中支持四种表分区的方式,分别为HASH、RANGE、LIST及KEY,固然在其它的类型数据库中,分区的实现方式略有不一样,可是分区的思想原理是相同,具体以下。

Hash:HASH分区主要用来确保数据在预先肯定数目的分区中平均分布,而在RANGE和LIST分区中,必须明确指定一个给定的列值或列值集合应该保存在哪一个分区中,而在HASH分区中,MySQL自动完成这些工做,你所要作的只是基于将要被哈希的列值指定一个列值或表达式,以及指定被分区的表将要被分割成的分区数量。

CREATE TABLE t_product_item (
      id int(7) not null,
      title varchar(40) not null,
      subtitle varchar(60) null,
      price double not null,
      imgurl varchar(70) not null,
      producttype int(2) not null,
      createtime datetime not null
)ENGINE=InnoDB DEFAULT CHARSET=utf8
 PARTITION BY HASH(YEAR(createtime)) //指定Hash的列值或表达式
 PARTITIONS 10                        //指定分区数量

 

Range:基于属于一个给定连续区间的列值,把多行分配给同一个分区,这些区间要连续且不能相互重叠使用VALUES LESS THAN操做符来进行定义。

 CREATE TABLE t_product_item (
      id int(7) not null,
      title varchar(40) not null,
      subtitle varchar(60) null,
      price double not null,
      imgurl varchar(70) not null,
      producttype int(2) not null,
      createtime datetime not null
)ENGINE=InnoDB DEFAULT CHARSET=utf8
 PARTITION BY RANGE(producttype) (                     //指定producttype做为range划分的列,并对值进行区域划分
      PARTITIONP0 VALUES LESS THAN(2),
      PARTITIONP1 VALUES LESS THAN(4),
      PARTITIONp2 VALUES LESS THAN(6),
      PARTITIONp3 VALUES LESS THAN MAXVALUE
);

 

List:相似于按RANGE分区,区别在于LIST分区是基于列值匹配一个离散值集合中的某个值来进行选择分区的。LIST分区经过使用“PARTITION BY LIST(expr)”来实现,其中“expr” 是某列值或一个基于某个列值、并返回一个整数值的表达式,而后经过“VALUES IN (value_list)”的方式来定义每一个分区,其中“value_list”是一个经过逗号分隔的整数列表。

CREATE TABLE t_product_item (
      id int(7) not null,
      title varchar(40) not null,
      subtitle varchar(60) null,
      price double not null,
      imgurl varchar(70) not null,
      producttype int(2) not null,
      createtime datetime not null
)ENGINE=InnoDB DEFAULT CHARSET=utf8
 PARTITION BY LIST(producttype) (                              //利用枚举出列值或表达式-->整型集合
      PARTITIONP0 VALUES IN (0,1),                               //利用IN进行分区
      PARTITIONP1 VALUES IN (2,3),
      PARTITIONP2 VALUES IN (4,5),
      PARTITIONP3 VALUES IN (6,7,8,9,10,11,12)
 )

 

Key:相似于按HASH分区,区别在于KEY分区只支持计算一列或多列,且MySQL 服务器提供其自身的哈希函数。必须有一列或多列包含整数值。

表分区的注意:

一、引擎的统一
在对同一个表进行分区时,必须保证数据表的引擎相同,好比:不能对一个分区的表为InnoDB,而另外一个分区的引擎为MySIAM。
二、分区关联性
在对数据表分区时,不能只对数据进行分区,须要连同其对应的索引等属性一同分区动做,某种程度上能够保持数据属性的完整。
三、分区的级别
对表进行分区以后,若是某个分区中的数据量依然很大或是增加迅速,那么你一样能够再进行子分区操做,将该数据再分区到其它分区中。另外,若是在一个分区中使用了子分区,那么其它的子分区也必须定义。
四、LIST分区
LIST分区没有相似如“VALUESLESS THAN MAXVALUE”这样的包含其余值在内的定义。将要匹配的任何值都必须在值列表中找到。
五、Linear线性
分区策略KEY和HASH都支持使用线性LINEAR的算法,也就是分区的编号是经过2的幂(powers-of-two)算法获得,而不是经过模数算法。

  • 垂直分表、水平分表

垂直分表

1.减小记录的字段可以使内存加载更多行数据,有利于查询。
2.受限于操做系统中的文件大小限制。
切分原则:把不经常使用或业务逻辑不紧密或存储内容比较多的字段分到新的表中可以使表存储更多数据。另外垂直分割可使得数据行变小,一个数据页就能存放更多的数据,在查询时就会减小I/O次数。其缺点是须要管理冗余列,查询全部数据须要join操做。

水平分表

1.随着数据量的增大,table行数巨大,查询的效率愈来愈低。表很大,分割后能够下降在查询时须要读的数据和索引的页数,同时也下降了索引的层数,提升查询速度。
2.一样受限于操做系统中的文件大小限制,数据量不能无限增长,当到达必定容量时,须要水平切分以下降单表(文件)的大小。

切分原则:
增量区间或散列或其余业务逻辑。使用哪一种切分方法要根据实际业务逻辑判断:好比对表的访问可能是近期产生的新数据,历史数据访问较少,能够考虑根据时间增量把数据按照必定时间段(好比每一年)切分。若是对表的访问较均匀,没有明显的热点区域,则能够考虑用范围(好比每500w一个表)或普通Hash或一致性Hash来切分。

全局主键问题:本来依赖数据库生成主键(好比自增)的表在拆分后须要本身实现主键的生成,由于通常拆分规则是创建在主键上的(拆分后仍然要保证主键在全局的惟一性),因此在插入新数据时须要肯定主键后才能找到存储的表。

相关文章
相关标签/搜索