如何优化Mysql千万级快速分页,limit优化快?
select * from collect where id in (9000,12,50,7000); 竟然 0秒便可以查完!id in (str) 很快,根基还是0秒。若是这样,千万级的数据,mysql应该也很轻易应付。
Mysql某个表有近千万数据,CRUD比较慢,该如何优化呢?
MySQL 数据库某张表近千万的数据,CRUD比较慢,如何优化?最常见的是线程池优化、索引优化、缓存优化、读写分离、数据库拆分等,上述4种优化可以从不同角度来优化我们的数据库操作,其中的可操作性性要看团队的技术能力和应用的维护能力,我就以自己遇到过的应用场景简单谈谈自己的优化流程。
换到新的团队,遇到的第一个棘手问题就是数据库不定时的出现“Cannot get a connection, pool error Timeout waiting for idle object”,经和DBA沟通,其反馈数据库group(数据库量级4kw+)中的查询逻辑很多,qps达1w+,并且慢sql积压,拖垮了数据库。从慢sql和上述查询异常着手,进行千万级的数据库优化。
1. 线程池优化。线上的读线程池16,写线程池池16,考虑到数据查询时获取不到数据库连接,将读线程池调整为32,其优化效果不明显,数据库建立连接的异常仍然存在。
2.索引优化。经和DBA分析相关的慢sql语句,发现其索引都是完备的,也就是说每个查询都可以落到对应的索引逻辑,这点儿我们心里是有数的,毕竟线上正常运行了2年多数据库,当时建库和查询时肯定考虑到了索引的情况。也就是说,在这方面没有优化的余地。
3.缓存优化。经排查,线上的相关操作采用缓存加速,缓存时间1h或24h不等,考虑到数据库瓶颈和更新数据删缓存的逻辑,将缓存时间延长至7天。该优化逻辑上线后,数据库异常有所减弱,但问题仍未解决。偶尔发现,客户端偶尔会请求服务端不存在的数据,引发缓存穿透。而针对该库涉及到的可能存在缓存穿透的逻辑,进行了一系列优化。优化之后,效果特别明显,也就是在线上业务达到一定量级时,要特别注意缓存穿透,这点在业务刚开始时很容易被忽略。
4.读写分离。虽然通过缓存穿透的优化处理,解决了数据库连接异常的问题,但是读写分离仍然值得尝试,读写分离是应对读多写少业务的一大利器,一主多从的读写分离模式被引入弹性数据库体系,让我们在特殊节点的业务保障更有信心。
5.数据库拆分,也就是分库分表。业务发展到一定程度,分库分表是优化的必经之路,也是我们团队一项很重要的优化业务,但限于业务场景、分库分表规则、多维度查询、团队研发资源等,目前正在规划中。
综上所述,通过优化缓存穿透和读写分离解决了我们线上业务的数据库性能问题,可操作性强,风险相对降低。
作者:夕阳雨晴,欢迎关注我的头条号:偶尔美文,主流Java,为你讲述不一样的码农生活。
这个数据量,建索引,会影响插入更新的性能。遇到复杂多变的业务场景,那么多的索引是很恐惧的。
减少数据量,只有分库分表,提高插入速度。
但是分库分表,会给正常的查询带来影响,也就是老的代码要重构了,还要考虑主键的生成。
如果业务简单,建议加索引,读写分离,加缓存解决。
如果业务复杂,还是直接上elasticsearch把。
crud慢。。。insert慢你就分区,不影响业务分表分实例也行;update delete看你什么模式了,如果是大数据量带复杂条件的跟select一样分析访问路径,总之先分析,别盲目的上方案,我见过更新数据花四十多分钟,开发一群人讨论分库分表,后来调整了index变成四分钟的,凡事都先分析一下,虽说工程师不是科学家,但是也别太无脑
调整mysql配置参数
若是读为主,可以考虑打开query_cache,以及调整一些参数值:sort_buffer_size,read_buffer_size,read_rnd_buffer_size,join_buffer_size
优化索引
对出现在where子句中的字段加索引, 全表扫描的性能通常是很差的,要尽量避免。
组合索引和覆盖索引
硬件升级
更多的内存和更快的硬盘。如果是InnoDB引擎,多利用点内存,减轻磁盘IO负载,因为IO往往是数据库服务器的瓶颈;
分区分表
mysql自带分区表,对应用是透明的,无需更改代码, 但是sql语句是需要针对分区表做优化的,sql的where条件中要带上分区条件的列,从而使查询定位到少量的分区上,否则就会扫描全部分区
分表和分区的思路是差不多的,都是将查询固定到一个范围,降低数据读取量,相对分区来说,分表不需要知道分区字段,但是需要知道分表规则。就导致需要修改现有代码来适配现有的分表逻辑,而且当数据量增加的时候,分表数量会一直递增,导致后期数据处理困难。
读写分离
主从复制,对主库进行CUD,对从库进行R,保证R不会受到CUD的影响,保证了查询性能,可以在应用层修改,也可以用第三方工具。
由于Mysql主从复制是异步的,主从在同一时刻难免存在数据不一致的问题,特别是主从机器是跨机房或者跨地域,网络延迟大,数据很难保持强一致性。所以若是要求数据强一致性,这种方法就不合适
crud同时在一张表上并发进行,由于事务的隔离性,当表中数据很大时是肯定不行的。
有人说使用读写分离,但对于写来讲,多个并发事务对同一张大表执行并发的事务性操作也会对性能造成极大影响。
还有人说表分区,横向分区只是减少了事务性操作的数据规模,把对一个数据集的操作分摊到多个数据集而已,对于千万甚至上亿数量级而言效果并不明显。
可以考虑使用事件溯源(Event Souring)+读写分离(CQRS)相结合的方法。事件溯源保证了只执行插入操作,而且插入的并不是数据本身,而是在事件表中插入新增数据的事件event,数据是以这个事件的属性保存的。对数据的修改和删除也同样是以事件形式插入事件表,这种只插入不修改或删除保证了极其强大的时间性能。如果我们想获取某一时刻的数据历史值,则把这个数据从它的起始时刻到特定时刻之间的所有事件回放一遍,即可获得当时的数据值。为了事件表本身的规模不至于太大,我们还可以定期生成它的快照,将在此之前的所有事件应用回放从而获得每个数据的现场值并压缩了事件表。
除了事件溯源以外,我们还应该使用数据库提供的数据复制功能(所有关系型数据库都提供,例如mysql和mariadb的binlog)或使用第三方组件(例如阿里云的canal)将事件实时复制到其他数据库中,从而实现读写分离。这时也可以使用eventuate事件溯源框架,并结合kafka或rabbitmq作它的事件消息总线。在用于读的数据库中我们一般使用物化视图,也就是说,把接收到的事件直接应用在物化视图上,最终用户看到的是物化视图中的统计分析数据。
MYSQL千万级大表的常规为难问题,如何1秒查出?
不知道数据库情况,综合处理,调大缓存,做索引优化,读写分离。然后先筛选主表记录,再联子表记录,启用连接池,如果主表数据变动较小,可以借助Redis缓存,如果网络不卡,一秒可以搞定。