三种MySQL⼤表优化⽅案,我猜你不会!
问题概述
使⽤阿⾥云rds for MySQL数据库(就是MySQL5.6版本),有个⽤户上⽹记录表6个⽉的数据量近2000万,保留最近⼀年的数据量达到4000万,查询速度极慢,⽇常卡死。严重影响业务。
问题前提:⽼系统,当时设计系统的⼈⼤概是⼤学没毕业,表设计和sql语句写的不仅仅是垃圾,简直⽆法直视。原开发⼈员都已离职,到我来维护,这就是传说中的维护不了就跑路,然后我就是掉坑的那个
我尝试解决该问题,so,有个这个⽇志。
⽅案概述
⽅案⼀:优化现有mysql数据库。优点:不影响现有业务,源程序不需要修改代码,成本最低。缺点:有优化瓶颈,数据量过亿就玩完了。
⽅案⼆:升级数据库类型,换⼀种100%兼容mysql的数据库。优点:不影响现有业务,源程序不需要修改代码,你⼏乎不需要做任何操作就能提升数据库性能,缺点:多花钱
⽅案三:⼀步到位,⼤数据解决⽅案,更换newsql/nosql数据库。优点:扩展性强,成本低,没有数据容量瓶颈,缺点:需要修改源程序代码
以上三种⽅案,按顺序使⽤即可,数据量在亿级别⼀下的没必要换nosql,开发成本太⾼。三种⽅案我都试了⼀遍,⽽且都形成了落地解决⽅案。该过程⼼中慰问跑路的那⼏个开发者⼀万遍
⽅案⼀详细说明:优化现有mysql数据库
跟阿⾥云数据库⼤佬电话沟通 and Google解决⽅案 and 问⾥⼤佬,总结如下(都是精华):
1.数据库设计和表创建时就要考虑性能
2.sql的编写需要注意优化
3.分区
4.分表
5.分库
1.数据库设计和表创建时就要考虑性能
mysql数据库本⾝⾼度灵活,造成性能不⾜,严重依赖开发⼈员能⼒。也就是说开发⼈员能⼒⾼,则mysql性能⾼。这也是很多关系型数据库的通病,所以公司的dba通常⼯资巨⾼。
设计表时要注意:
1.表字段避免null值出现,null值很难查询优化且占⽤额外的索引空间,推荐默认数字0代替null。
2.尽量使⽤INT⽽⾮BIGINT,如果⾮负则加上UNSIGNED(这样数值容量会扩⼤⼀倍),当然能使⽤TINYINT、SMALLINT、
MEDIUM_INT更好。
3.使⽤枚举或整数代替字符串类型
4.尽量使⽤TIMESTAMP⽽⾮DATETIME
5.单表不要有太多字段,建议在20以内
6.⽤整型来存IP
索引
varchar2最大长度
1.索引并不是越多越好,要根据查询有针对性的创建,考虑在WHERE和ORDER BY命令上涉及的列建⽴索引,可根据EXPLAIN来查看是否⽤了索引还是全表扫描
2.应尽量避免在WHERE⼦句中对字段进⾏NULL值判断,否则将导致引擎放弃使⽤索引⽽进⾏全表扫描
3.值分布很稀少的字段不适合建索引,例如"性别"这种只有两三个值的字段
4.字符字段只建前缀索引
5.字符字段最好不要做主键
6.不⽤外键,由程序保证约束
7.尽量不⽤UNIQUE,由程序保证约束
8.使⽤多列索引时主意顺序和查询条件保持⼀致,同时删除不必要的单列索引
简⾔之就是使⽤合适的数据类型,选择合适的索引
选择合适的数据类型
(1)使⽤可存下数据的最⼩的数据类型,整型 < date,time < char,varchar < blob
(2)使⽤简单的数据类型,整型⽐字符处理开销更⼩,因为字符串的⽐较更复杂。如,int类型存储时间类型,bigint类型转ip函数
(3)使⽤合理的字段属性长度,固定长度的表会更快。使⽤enum、char⽽不是varchar
(4)尽可能使⽤not null定义字段
(5)尽量少⽤text,⾮⽤不可最好分表
选择合适的索引列
(1)查询频繁的列,在where,group by,order by,on从句中出现的列
(2)where条件中<,<=,=,>,>=,between,in,以及like 字符串+通配符(%)出现的列
(3)长度⼩的列,索引字段越⼩越好,因为数据库的存储单位是页,⼀页中能存下的数据越多越好(4)离散度⼤(不同的值多)的列,放在联合索引前⾯。查看离散度,通过统计不同的列值来实现,count越⼤,离散程度越⾼:
原开发⼈员已经跑路,该表早已建⽴,我⽆法修改,故:该措辞⽆法执⾏,放弃!
2.sql的编写需要注意优化
1.使⽤limit对查询结果的记录进⾏限定
2.避免select *,将需要查的字段列出来
3.使⽤连接(join)来代替⼦查询
4.拆分⼤的delete或insert语句
5.可通过开启慢查询⽇志来出较慢的SQL
6.不做列运算:SELECT id WHERE age + 1 = 10,任何对列的操作都将导致表扫描,它包括数据库教程函数、计算表达式等等,查询时要尽可能将操作移⾄等号右边
7.sql语句尽可能简单:⼀条sql只能在⼀个cpu运算;⼤语句拆⼩语句,减少锁时间;⼀条⼤sql可以堵死整个库
8.OR改写成IN:OR的效率是n级别,IN的效率是log(n)级别,in的个数建议控制在200以内
9.不⽤函数和触发器,在应⽤程序实现
10.避免%xxx式查询
11.少⽤JOIN
12.使⽤同类型进⾏⽐较,⽐如⽤’123’和’123’⽐,123和123⽐
13.尽量避免在WHERE⼦句中使⽤!=或<>操作符,否则将引擎放弃使⽤索引⽽进⾏全表扫描
14.对于连续数值,使⽤BETWEEN不⽤IN:SELECT id FROM t WHERE num BETWEEN 1 AND 5
15.列表数据不要拿全表,要使⽤LIMIT来分页,每页数量也不要太⼤
“原开发⼈员已经跑路,程序已经完成上线,我⽆法修改sql,故:该措辞⽆法执⾏,放弃!
引擎
引擎
⽬前⼴泛使⽤的是MyISAM和InnoDB两种引擎:
MyISAM
MyISAM引擎是MySQL 5.1及之前版本的默认引擎,它的特点是:
1.不⽀持⾏锁,读取时对需要读到的所有表加锁,写⼊时则对表加排它锁
2.不⽀持事务
3.不⽀持外键
4.不⽀持崩溃后的安全恢复
5.在表有读取查询的同时,⽀持往表中插⼊新纪录
6.⽀持BLOB和TEXT的前500个字符索引,⽀持全⽂索引
7.⽀持延迟更新索引,极⼤提升写⼊性能
8.对于不会进⾏修改的表,⽀持压缩表,极⼤减少磁盘空间占⽤
InnoDB
InnoDB在MySQL 5.5后成为默认索引,它的特点是:
1.⽀持⾏锁,采⽤MVCC来⽀持⾼并发
2.⽀持事务
3.⽀持外键
4.⽀持崩溃后的安全恢复
5.不⽀持全⽂索引
总体来讲,MyISAM适合SELECT密集型的表,⽽InnoDB适合INSERT和UPDATE密集型的表
“MyISAM速度可能超快,占⽤存储空间也⼩,但是程序要求事务⽀持,故InnoDB是必须的,故该⽅案⽆法执⾏,放弃!
3.分区
MySQL在5.1版引⼊的分区是⼀种简单的⽔平拆分,⽤户需要在建表的时候加上分区参数,对应⽤是透明的⽆需修改代码
对⽤户来说,分区表是⼀个独⽴的逻辑表,但是底层由多个物理⼦表组成,实现分区的代码实际上是通
过对⼀组底层表的对象封装,但对SQL层来说是⼀个完全封装底层的⿊盒⼦。MySQL实现分区的⽅式也意味着索引也是按照分区的⼦表定义,没有全局索引
⽤户的SQL语句是需要针对分区表做优化,SQL条件中要带上分区条件的列,从⽽使查询定位到少量的分区上,否则就会扫描全部分区,可以通过EXPLAIN PARTITIONS来查看某条SQL语句会落在那些分区上,从⽽进⾏SQL优化,我测试,查询时不带分区条件的列,也会提⾼速度,故该措施值得⼀试。
分区的好处是:
1.可以让单表存储更多的数据
2.分区表的数据更容易维护,可以通过清楚整个分区批量删除⼤量数据,也可以增加新的分区来⽀持新插⼊的数据。另外,还可以对⼀个独⽴分区进⾏优化、检查、修复等操作
3.部分查询能够从查询条件确定只落在少数分区上,速度会很快
4.分区表的数据还可以分布在不同的物理设备上,从⽽⾼效利⽤多个硬件设备
5.可以使⽤分区表赖避免某些特殊瓶颈,例如InnoDB单个索引的互斥访问、ext3⽂件系统的inode锁竞争
6.可以备份和恢复单个分区
分区的限制和缺点:
1.⼀个表最多只能有1024个分区
2.如果分区字段中有主键或者唯⼀索引的列,那么所有主键列和唯⼀索引列都必须包含进来
3.分区表⽆法使⽤外键约束
4.NULL值会使分区过滤⽆效
5.所有分区必须使⽤相同的存储引擎
分区的类型:
1.RANGE分区:基于属于⼀个给定连续区间的列值,把多⾏分配给分区
2.LIST分区:类似于按RANGE分区,区别在于LIST分区是基于列值匹配⼀个离散值集合中的某个值来进
⾏选择
3.HASH分区:基于⽤户定义的表达式的返回值来进⾏选择的分区,该表达式使⽤将要插⼊到表中的这些⾏的列值进⾏计算。这个函数可以包含MySQL中有效的、产⽣⾮负整数值的任何表达式
4.KEY分区:类似于按HASH分区,区别在于KEY分区只⽀持计算⼀列或多列,且MySQL服务器提供其⾃⾝的哈希函数。必须有⼀列或多列包含整数值
5.具体关于mysql分区的概念请⾃⾏google或查询官⽅⽂档,我这⾥只是抛砖引⽟了。
“我⾸先根据⽉份把上⽹记录表RANGE分区了12份,查询效率提⾼6倍左右,效果不明显,故:换id为HASH分区,分了64个分区,查询速度提升显著。问题解决!结果如下:PARTITION BY HASH (id)PARTITIONS 64select count() from readroom_website; --11901336⾏记录/ 受影响⾏数: 0 已到记录: 1 警告: 0 持续时间 1 查询: 5.734 sec. /select * from readroom_website where month(accesstime) =11 limit 10;/ 受影响⾏数: 0 已到记录: 10 警告: 0 持续时间 1 查询: 0.719 sec. */
4.分表
分表就是把⼀张⼤表,按照如上过程都优化了,还是查询卡死,那就把这个表分成多张表,把⼀次查询分成多次查询,然后把结果组合返回给⽤户。
分表分为垂直拆分和⽔平拆分,通常以某个字段做拆分项。⽐如以id字段拆分为100张表:表名为 table
Name_id%100
但:分表需要修改源程序代码,会给开发带来⼤量⼯作,极⼤的增加了开发成本,故:只适合在开发初期就考虑到了⼤量数据存在,做好了分表处理,不适合应⽤上线了再做修改,成本太⾼⽽且选择这个⽅案,都不如选择我提供的第⼆第三个⽅案的成本低!故不建议采⽤。
5.分库
把⼀个数据库分成多个,建议做个读写分离就⾏了,真正的做分库也会带来⼤量的开发成本,得不偿失!不推荐使⽤。
⽅案⼆详细说明:升级数据库,换⼀个100%兼容mysql的数据库
mysql性能不⾏,那就换个。为保证源程序代码不修改,保证现有业务平稳迁移,故需要换⼀个100%兼
容mysql的数据库。
开源选择
云数据选择
“官⽅介绍:云数据库HybridDB for MySQL (原名PetaData)是同时⽀持海量数据在线事务(OLTP)和在线分析(OLAP)的
HTAP(Hybrid Transaction/Analytical Processing)关系型数据库。
我也测试了⼀下,是⼀个olap和oltp兼容的解决⽅案,但是价格太⾼,每⼩时⾼达10块钱,⽤来做存储太浪费了,适合存储和分析⼀起⽤的业务。
⽅案三详细说明:去掉mysql,换⼤数据引擎处理数据
数据量过亿了,没得选了,只能上⼤数据了。
开源解决⽅案
hadoop家族。hbase/hive怼上就是了。但是有很⾼的运维成本,⼀般公司是玩不起的,没⼗万投⼊是不会有很好的产出的!
云解决⽅案
这个就⽐较多了,也是⼀种未来趋势,⼤数据由专业的公司提供专业的服务,⼩公司或个⼈购买服务,⼤数据就像⽔/电等公共设施⼀样,存在于社会的⽅⽅⾯⾯。
国内做的最好的当属阿⾥云。
我选择了阿⾥云的MaxCompute配合DataWorks,使⽤超级舒服,按量付费,成本极低。
MaxCompute可以理解为开源的Hive,提供sql/mapreduce/ai算法/python脚本/shell脚本等⽅式操作数据,数据以表格的形式展现,以分布式⽅式存储,采⽤定时任务和批处理的⽅式处理数据。DataWorks提供了⼀种⼯作流的⽅式管理你的数据处理任务和调度监控。
在这⾥插⼊代码⽚当然你也可以选择阿⾥云hbase等其他产品,我这⾥主要是离线处理,故选择MaxCompute,基本都是图形界⾯操作,⼤概写了300⾏sql,费⽤不超过100块钱就解决了数据处理问题。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。