当前位置: 首页 > 后端技术 > PHP

使用三种方案优化MySQL的2000万数据表

时间:2023-03-30 01:53:44 PHP

问题概述使用阿里云rdsforMySQL数据库(即MySQL5.6版本),有一个用户在线记录表近2000万数据6个月,reserved过去一年的数据量达到了4000万条,查询速度极慢,日常卡顿。严重影响生意。问题前提:老系统,当时设计系统的人很可能大学没毕业,表设计和SQL语句不就是垃圾,直接看不出来。原来的开发人员走了,我来维护。这就是传说中的养不起就跑,到时候掉坑里的就是我!!!我试图解决这个问题,所以,有这个日志。方案概述方案一:优化现有的mysql数据库。优点:不影响现有业务,源程序无需修改代码,成本最低。缺点:存在优化瓶颈,数据量过亿就完蛋了。方案二:升级数据库类型,换成100%兼容mysql的数据库。优点:不影响现有业务,无需修改源码,无需任何操作即可提升数据库性能。缺点:钱多。方案三:一步到位,大数据方案,更换newsql/nosql数据库。优点:扩展性强,成本低,无数据容量瓶颈。缺点:以上三种方案需要修改源码,依次使用即可。如果数据量小于1亿,没必要改成nosql,开发成本太高。三个方案我都试过了,都形成了落地方案。在此过程中,对跑路10000次的开发者表示慰问:)方案一详细:优化现有mysql数据库,电话与阿里云数据库大佬交流,谷歌解决方案,群里请教大佬。总结如下(都是精髓):设计数据库和创建表时必须考虑性能。写SQL时要注意优化分区、表和数据库。1、设计数据库和创建表时必须考虑性能。人员能力。也就是说开发者的能力高,mysql的性能就高。这也是很多关系型数据库的通病,所以公司的dba通常都有着丰厚的薪水。在设计表格时要注意:避免表格字段出现空值。空值难以查询和优化,占用额外的索引空间。建议使用默认数字0而不是null。尝试使用INT而不是BIGINT。如果是非负数,加上UNSIGNED(这样值容量就会翻倍)。当然,最好使用TINYINT、SMALLINT和MEDIUM_INT。使用枚举或整型代替字符串类型尽量使用TIMESTAMP代替DATETIME单表字段不要太多,建议使用整型存储20以内的IP索引,考虑在WHERE和WHERE涉及的列上建立索引ORDERBY命令,可以根据EXPLAIN查看是否使用了索引或者全表扫描。尽量避免在WHERE子句中判断字段的NULL值,否则引擎会放弃使用索引,但是不适合在全表扫描时为值分布非常稀少的字段建立索引。比如像“gender”这样只有两个或三个取值的字段,只能为字符字段建立前缀索引。尽量不要使用UNIQUE,程序在使用多列索引时保证思路和查询条件的顺序一致,删除不需要的单列索引。使用能存储数据的最小数据类型,integer=,between,in,andcolumnsappearinglikestrings+wildcards(%)(3)长度较小的列,越小索引字段,越好,因为数据库的存储单位是页,一页能存放的数据越多越好(4)分散度大(很多不同值)的列应该放在前面联合指数。检查分散程度,这是通过计算不同的列值来实现的。count越大,分散度越高:原开发者跑路了,表已经建好,无法修改,所以:这种写法无法实现,放弃!2、写SQL需要注意优化。使用limit限制查询结果的记录,避免select*,列出需要查询的字段。通过启用慢速查询,使用连接而不是子查询来拆分大型删除或插入语句。登录发现较慢的SQL不做列操作:SELECTidWHEREage+1=10,对列的任何操作都会引起表扫描,其中包括数据库教程函数,计算表达式等,查询时试试尽可能将操作移到等号的右边。sql语句越简单越好:一个sql只能在一个CPU上运行;一个大语句可以分成多个小语句,以减少锁定时间;一个大的sql可以阻塞整个库OR重写成IN:OR的效率是n级,IN的效率是log(n)级,IN的个数建议控制在200以内,没有函数和触发器,避免%应用中的xxx查询,少用JOIN,使用同类型进行比较,比如'123'和'123'比较,123和123要尽量避免在WHERE子句中使用!=或<>运算符,否则引擎将放弃使用索引并执行全表扫描。连续值,用BETWEEN代替IN:SELECTidFROMtWHEREnumBETWEEN1AND5list数据不要用全表,用LIMIT分页,每页数不要太大!目前广泛使用的引擎有MyISAM和InnoDB两种引擎:MyISAMMyISAM引擎是MySQL5.1及更早版本的默认引擎。它的特点是:不支持行锁,读取时锁定所有需要读取的表,并对表加排它锁,不支持事务,不支持外键,不支持崩溃后安全恢复,支持在表有读查询的情况下向表中插入新记录,支持BLOB和TEXT前500个字符的索引,支持全文索引,支持延迟索引更新,大大提高了写入性能。对于不会修改的表,支持压缩表,大大减少磁盘空间占用。InnoDBInnoDB在MySQL5.5之后成为默认索引。MVCC支持高并发,支持事务,支持外键,支持崩溃后安全恢复,不支持全文索引。一般来说,MyISAM适用于SELECT密集型表,而InnoDB适用于INSERT和UPDATE密集型表。MyISAM可能速度超快,占用存储空间小,但是程序需要事务支持,所以需要InnoDB,所以这个方案无法实现,放弃!3、分区MySQL在5.1版本中引入的分区是一种简单的水平分割。用户创建表时需要添加分区参数,对应用透明,不需要修改代码。对于用户来说,分区表是一个独立的逻辑表,但底层是由多个物理子表组成的。实现分区的代码实际上是由一组底层表对象封装的,但是对于SQL层来说,它是一个完全封装了底层的黑盒。MySQL实现分区的方式也是意味着索引也是根据分区的子表来定义的。没有全局索引的用户的SQL语句需要针对分区表进行优化。SQL条件中必须包含分区条件的列,这样查询才能定位到少数分区上,否则扫描所有分区,可以使用EXPLAINPARTITIONS查看某条SQL语句会落在哪些分区上,从而优化SQL。我测试过不带分区条件的列在查询时也会提高速度,所以这个措施值得一试。分区的好处是:可以让一张表存储更多的数据,而且分区表中的数据更容易维护。通过清除整个分区可以批量删除大量数据,并可以添加新分区来支持新插入的数据。此外,您还可以对独立的分区进行优化、检查、修复等操作。有些查询可以从查询条件判断只落在少数分区上,速度会很快。分区表中的数据还可以分布在不同的物理设备上,这很有趣。多个硬件设备可以使用分区表来避免一些特殊的瓶颈,比如InnoDB的单个索引的互斥访问,ext3文件系统的inode锁竞争可以备份和恢复单个分区分区的限制和缺点:一张表最多只能有1024个分区如果分区字段中有主键或唯一索引列,则必须包括所有主键列和唯一索引列。分区表不能使用外键约束。NULL值将使分区过滤失效。所有分区必须使用相同的存储引擎。类型:RANGE分区:根据属于给定连续区间的列值,将多行分配给分区LIST分区:类似于RANGE分区,不同的是LIST分区是根据列值匹配一个值在asetofdiscretevaluesforselectionHASHpartitioning:Partitioningforselectionbasedonthereturnvalueofauser-definedexpressioncalculatedusingthecolumnvaluesoftherowstoinsertedintotable.一组用于选择的离散值的分区HASH分区:根据使用要插入表的行的列值计算的用户定义表达式的返回值进行分区选择。这个函数可以包含任何在MySQL中有效的表达式,它产生非负整数值。KEY分区:类似于HASH分区,不同的是KEY分区只支持计算一列或多列,MySQL服务器提供了自己的哈希函数。必须有一个或多个包含整数值的列。关于mysql分区的概念请自行google或查询官方文档。我只是在这里扔砖头。我先把在线记录表RANGE按照月份分成12个分区,查询效率提高了6倍左右,但是效果不明显。所以将id改为HASH分区,划分了64个分区,查询速度明显提升。问题解决了!结果如下:PARTITIONBYHASH(id)PARTITIONS64selectcount()fromreadroom_website;--11901336受影响的行/行:找到0条记录:1条警告:0持续时间1次查询:5.734秒。/select*fromreadroom_websitewheremonth(accesstime)=11limit10;/受影响的行:0找到的记录:10警告:0持续时间1查询:0.719秒。*/4。表分表就是按照上面的流程把一个大表进行分表如果所有的东西都优化了,但是查询还是卡住了,那就分表为多张表,将一个查询分成多个查询,然后将合并后的结果返回给用户。表格拆分分为垂直拆分和水平拆分,通常以某个字段作为拆分项。比如id字段拆分成100张表:表名是tableName_id%100但是:分表需要修改源程序代码,会给开发带来很大的工作量,大大增加开发成本,所以:只适用于开发初期考虑到大量数据的存在,分表处理,不适合上线后修改的应用。成本太高了!!!而且选择这个方案还不如选择我提供的第二个和第三个方案划算!不建议使用。5、分库将一个数据库分成多个。建议读写分开。真正的分库也会带来大量的开发成本,得不偿失!不建议。方案二详解:升级数据库,换成100%兼容mysql的数据库。如果mysql性能不好,那就换吧。为了保证不修改源程序代码,顺利迁移现有业务,需要换成100%兼容mysql的数据库。开源选择tiDBhttps://github.com/pingcap/tidbCubridhttps://www.cubrid.org/开源数据库会带来大量的运维成本,而且其工业品质还远不及MySQL,有很多坑上一步,如果你的公司需要自建数据库的话,选择这类产品。选择阿里云POLARDBhttps://www.aliyun.com/product/polardb?spm=a2c4g.11174283.cloudEssentials.47.7a984b5cS7h4wH官方介绍:POLARDB是阿里云开发的下一代关系型分布式云原生数据库。100%兼容MySQL,存储容量高达100T,性能高达MySQL的6倍。POLARDB既结合了商业数据库稳定、可靠、高性能的特点,又具有开源数据库简单、可扩展、持续迭代的优势,成本仅为商业数据库的1/10。我打开它并测试了它。支持免费mysql数据迁移,无运行成本,性能提升10倍左右。价格和rds差不多。这是一个很好的替代解决方案!淘宝用的是阿里云OceananBase,能顶双十一,性能出众,但是公测中,我还不能试,不过阿里云HybridDBforMySQL(原PetaData)值得期待https://www.aliyun.com/product/petadata?spm=a2c4g.11174283.cloudEssentials.54.7a984b5cS7h4wH官方介绍:云数据库HybridDBforMySQL(原名PetaData)是一种支持海量HTAP(HybridTransaction/AnalyticalProcessing)关系数据在线交易(OLTP)和在线分析(OLAP)类型的数据库。我也测试了它。是olap和oltp兼容的方案,但是价格太高,高达10元/小时。用它来储存太浪费了。适用于存储和分析业务。腾讯云DCDBhttps://cloud.tencent.com/product/dcdb_for_tdsql官方介绍:DCDB又称TDSQL,是兼容MySQL协议和语法的高性能分布式数据库,支持自动水平拆分——即业务展示是完整的逻辑表,但是数据被平分到多个分片;每个shard默认采用主备架构,提供容灾、恢复、监控、不停机扩容等全套解决方案,适用于TB级或PB级海量数据场景。我不喜欢用腾讯的,就不多说了。原因是出了问题找不到人,网上的问题也解决不了头疼的问题!但是他便宜,适合超小公司,好玩。方案三详细解释:去掉mysql,换成大数据引擎,处理上亿量级的数据,只好用大数据了。Hadoop开源解决方案系列。只是hbase/配置单元。但运维成本高,一般企业承担不起。没有10万元的投入,就没有好的产出!云解决方案更多,也是未来的趋势。专业公司为大数据提供专业服务,小公司或个人购买服务。大数据就像水/电等公共设施一样,存在于社会的方方面面。中国最好的是阿里云。我选择了阿里云的MaxCompute来配合DataWorks。使用超级舒服,按量付费,成本极低。MaxCompute可以理解为一个开源的Hive,提供sql/mapreduce/ai算法/python脚本/shell脚本来操作数据。数据以表格形式展示,分布式存储,定时任务和批处理。DataWorks提供了一个工作流来管理您的数据处理任务和调度监控。当然你也可以选择阿里云hbase等其他产品。我主要是用MaxCompute做离线处理,所以选择MaxCompute,基本都是图形界面操作。写完300行左右的SQL,不超过100元的成本就可以解决数据处理问题。大家注意点,别迷路了,以上就是本文的全部内容,能看到这里的都是人才。前面说了PHP的技术点很多,也是因为太多了,写的太多了,写完了也不会看太多,所以我这里整理成了PDF和文档,有需要的可以点击进入密码:想了解更多内容可以访问【比大厂】优质PHP架构师教程目录,只要会看,就可以保证你的薪水会上升到一个更高的水平(不断更新)。以上内容希望对大家有所帮助,很多PHPer在进阶的时候总会遇到一些问题和瓶颈。业务代码写多了,没有方向感,就不知道从哪里入手改进。我整理了一些这方面的资料,包括但不限于:高扩展、高性能、高并发、服务器性能调优、TP6、laravel、YII2、Redis、Swoole、Swoft、Kafka、Mysql优化、shell脚本、Docker、微服务,Nginx等知识点进阶进阶干货需要的可以免费分享给大家,需要的可以加我的PHP技术交流群953224940