【数据库优化汇总】使用这8招后,数据库查询从191s优化到30ms!

news2025/2/6 9:56:52

为什么数据库会慢?

慢的本质


 

查找的时间复杂度

查找算法

存储数据结构

存储数据结构

数据总量

数据拆分

高负载

CPU、磁盘繁忙

无论是关系型数据库还是NoSQL,任何存储系统决定于其查询性能的主要有三种:

  • 查找的时间复杂度
  • 数据总量
  • 高负载

而决定于查找时间复杂度主要有两个因素:

  • 查找算法
  • 存储数据结构

无论是哪种存储,数据量越少,自然查询性能就越高,随着数据量增多,资源的消耗(CPU、磁盘读写繁忙)、耗时也会越来越高。

从关系型数据库角度出发,索引结构基本固定是B+Tree,时间复杂度是O(log n),存储结构是行式存储。因此咱们对于关系数据库能优化的一般只有数据量。

而高负载造成原因有高并发请求、复杂查询等,导致CPU、磁盘繁忙等,而服务器资源不足则会导致慢查询等问题。该类型问题一般会选择集群、数据冗余的方式分担压力。

应该站在哪个层面思考优化?

从上图可见,自顶向下的一共有四层,分别是硬件、存储系统、存储结构、具体实现。层与层之间是紧密联系的,每一层的上层是该层的载体;因此越往顶层越能决定性能的上限,同时优化的成本也相对会比较高,性价比也随之越低。以最底层的具体实现为例,那么索引的优化的成本应该是最小的,可以说加了索引后无论是CPU消耗还是响应时间都是立竿见影降低;然而一个简单的语句,无论如何优化加索引也是有局限的,当在具体实现这层没有任何优化空间的时候就得往上一层【存储结构】思考,思考是否从物理表设计的层面出发优化(如分库分表、压缩数据量等),如果是文档型数据库得思考下文档聚合的结果;如果在存储结构这层优化得没效果,得继续往再上一次进行考虑,是否关系型数据库应该不适合用在现在得业务场景?如果要换存储,那么得换怎样得NoSQL?

所以咱们优化的思路,出于性价比的优先考虑具体实现,实在没有优化空间了再往上一层考虑。当然如果公司有钱,直接使用钞能力,绕过了前面三层,这也是一种便捷的应急处理方式。

该篇文章不讨论顶与底的两个层面的优化,主要从存储结构、存储系统中间两层的角度出发进行探讨

八大方案总结

数据库的优化方案核心本质有三种:减少数据量用空间换性能选择合适的存储系统,这也对应了开篇讲解的慢的三个原因:数据总量、高负载、*查找的时间复杂度。*

这里大概解释下收益类型:短期收益,处理成本低,能紧急应对,久了则会有技术债务;长期收益则跟短期收益相反,短期内处理成本高,但是效果能长久使用,扩展性会更好。

静态数据意思是,相对改动频率比较低的,也无需过多联表的,where过滤比较少。动态数据与之相反,更新频率高,通过动态条件筛选过滤。

减少数据量

减少数据量类型共有四种方案:数据序列化存储、数据归档、中间表生成、分库分表。

就如上面所说的,无论是哪种存储,数据量越少,自然查询性能就越高,随着数据量增多,资源的消耗(CPU、磁盘读写繁忙)、耗时也会越来越高。目前市面上的NoSQL基本上都支持分片存储,所以其天然分布式写的能力从数据量上能得到非常的解决方案。而关系型数据库,查找算法与存储结构是可以优化的空间比较少,因此咱们一般思考出发点只有从如何减少数据量的这个角度进行选择优化,因此本类型的优化方案主要针对关系型数据库进行处理。

数据归档

注意点:别一次性迁移数量过多,建议低频率多次限量迁移。像MySQL由于删除数据后是不会释放空间的,可以执行命令OPTIMIZE TABLE释放存储空间,但是会锁表,如果存储空间还满足,可以不执行。

建议优先考虑该方案,主要通过数据库作业把非热点数据迁移到历史表,如果需要查历史数据,可新增业务入口路由到对应的历史表(库)。

中间表(结果表)

中间表(结果表)其实就是利用调度任务把复杂查询的结果跑出来存储到一张额外的物理表,因为这张物理表存放的是通过跑批汇总后的数据,因此可以理解成根据原有的业务进行了高度的数据压缩。以报表为例,如果一个月的源数据有数十万,我们通过调度任务以月的维度生成,那么等于把原有的数据压缩了几十万分之一;接下来的季报和年报可以根据月报*N来进行统计,以这种方式处理的数据,就算三年、五年甚至十年数据量都可以在接受范围之内,而且可以精确计算得到。

那么数据的压缩比率是否越低越好?下面有一段口诀:

  • 字段越多,粒度越细,灵活性越高,可以以中间表进行不同业务联表处理。
  • 字段越少,粒度越粗,灵活性越低,一般作为结果表查询出来。

数据序列化存储

在数据库以序列化存储的方式,对于一些不需要结构化存储的业务来说是一种很好减少数据量的方式,特别是对于一些M*N的数据量的业务场景,如果以M作为主表优化,那么就可以把数据量维持最多是M的量级。另外像订单的地址信息,这种业务一般是不需要根据里面的字段检索出来,也比较适合。

这种方案我认为属于一种临时性的优化方案,无论是从序列化后丢失了部份字段的查询能力,还是这方案的可优化性都是有限的。

分库分表

分库分表作为数据库优化的一种非常经典的优化方案,特别是在以前NoSQL还不是很成熟的年代,这个方案就如救命草一般的存在。

如今也有不少同行也会选择这种优化方式,但是从我角度来看,分库分表是一种优化成本很大的方案。这里我有几个建议:

  1. 分库分表是实在没有办法的办法,应放到最后选择。
  2. 优先选择NoSQL代替,因为NoSQL诞生基本上为了扩展性与高性能。
  3. 究竟分库还是分表?量大则分表,并发高则分库
  4. 不考虑扩容,一部做到位。因为技术更新太快了,每3-5年一大变。

拆分方式

只要涉及到这个拆,那么无论是微服务也好,分库分表也好,拆分的方式主要分两种:垂直拆分、水平拆分

垂直拆分更多是从业务角度进行拆分,主要是为了降低业务耦合度;此外以SQL Server为例,一页是8KB存储,如果在一张表里字段越多,一行数据自然占的空间就越大,那么一页数据所存储的行数就自然越少,那么每次查询所需要IO则越高因此性能自然也越慢;因此反之,减少字段也能很好提高性能。之前我听说某些同行的表有80个字段,几百万的数据就开始慢了。

水平拆分更多是从技术角度进行拆分,拆分后每张表的结构是一模一样的,简而言之就是把原有一张表的数据,通过技术手段进行分片到多张表存储,从根本上解决了数据量的问题。

路由方式

进行水平拆分后,根据分区键(sharding key)原来应该在同一张表的数据拆解写到不同的物理表里,那么查询也得根据分区键进行定位到对应的物理表从而把数据给查询出来。

路由方式一般有三种区间范围、Hash、分片映射表,每种路由方式都有自己的优点和缺点,可以根据对应的业务场景进行选择。

区间范围根据某个元素的区间的进行拆分,以时间为例子,假如有个业务我们希望以月为单位拆分那么表就会拆分像 table_2022-04,这种对于文档型、ElasticSearch这类型的NoSQL也适用,无论是定位查询,还是日后清理维护都是非常的方便的。那么缺点也明显,会因为业务独特性导致数据不平均,甚至不同区间范围之间的数据量差异很大。

Hash也是一种常用的路由方式,根据Hash算法取模以数据量均匀分别存储在物理表里,缺点是对于带分区键的查询依赖特别强,如果不带分区键就无法定位到具体的物理表导致相关所有表都查询一次,而且在分库的情况下对于Join、聚合计算、分页等一些RDBMS的特性功能还无法使用。

一般分区键就一个,假如有时候业务场景得用不是分区键的字段进行查询,那么难道就必须得全部扫描一遍?其实可以使用分片映射表的方式,简单来说就是额外有一张表记录额外字段与分区键的映射关系。举个例子,有张订单表,原本是以UserID作为分区键拆分的,现在希望用OrderID进行查询,那么得有额外得一张物理表记录了OrderID与UserID的映射关系。因此得先查询一次映射表拿到分区键,再根据分区键的值路由到对应的物理表查询出来。可能有些朋友会问,那这映射表是否多一个映射关系就多一张表,还是多个映射关系在同一张表。我优先建议单独处理,如果说映射表字段过多,那跟不进行水平拆分时的状态其实就是一致的,这又跑回去的老问题。

用空间换性能

该类型的两个方案都是用来应对高负载的场景,方案有以下两种:分布式缓存、一主多从。

与其说这个方案叫用空间换性能,我认为用空间换资源更加贴切一些。因此两个方案的本质主要通数据冗余、集群等方式分担负载压力。

对于关系型数据库而言,因为他的ACID特性让它天生不支持写的分布式存储,但是它依然天然的支持分布式读

分布式缓存

缓存层级可以分好几种:客户端缓存API服务本地缓存分布式缓存,咱们这次只聊分布式缓存。一般我们选择分布式缓存系统都会优先选择NoSQL的键值型数据库,例如Memcached、Redis,如今Redis的数据结构多样性,高性能,易扩展性也逐渐占据了分布式缓存的主导地位。

缓存策略也主要有很多种:Cache-AsideRead/Wirte-ThroughWrite-Back,咱们用得比较多的方式主要Cache-Aside,具体流程可看下图:

我相信大家对分布式缓存相对都比较熟悉了,但是我在这里还是有几个注意点希望提醒一下大家:

避免滥用缓存

缓存应该是按需使用,从28法则来看,80%的性能问题由主要的20%的功能引起。滥用缓存的后果会导致维护成本增大,而且有一些数据一致性的问题也不好定位。特别像一些动态条件的查询或者分页,key的组装是多样化的,量大又不好用keys指令去处理,当然我们可以用额外的一个key把记录数据的key以集合方式存储,删除时候做两次查询,先查Key的集合,然后再遍历Key集合把对应的内容删除。这一顿操作下来无疑是非常废功夫的,谁弄谁知道。

避免缓存击穿

当缓存没有数据,就得跑去数据库查询出来,这就是缓存穿透。假如某个时间临界点数据是空的例如周排行榜,穿透过去的无论查找多少次数据库仍然是空,而且该查询消耗CPU相对比较高,并发一进来因为缺少了缓存层的对高并发的应对,这个时候就会因为并发导致数据库资源消耗过高,这就是缓存击穿。数据库资源消耗过高就会导致其他查询超时等问题。

该问题的解决方案也简单,对于查询到数据库的空结果也缓存起来,但是给一个相对快过期的时间。有些同行可能又会问,这样不就会造成了数据不一致了么?一般有数据同步的方案像分布式缓存、后续会说的一主多从、CQRS,只要存在数据同步这几个字,那就意味着会存在数据一致性的问题,因此如果使用上述方案,对应的业务场景应允许容忍一定的数据不一致。

不是所有慢查询都适用

一般来说,慢的查询都意味着比较吃资源的(CPU、磁盘I/O)。举个例子,假如某个查询功能需要3秒时间,串行查询的时候并没什么问题,我们继续假设这功能每秒大概QPS为100,那么在第一次查询结果返回之前,接下来的所有查询都应该穿透到数据库,也就意味着这几秒时间有300个请求到数据库,如果这个时候数据库CPU达到了100%,那么接下来的所有查询都会超时,也就是无法有第一个查询结果缓存起来,从而还是形成了缓存击穿。

一主多从

常用的分担数据库压力还有一种常用做法,就是读写分离、一主多从。咱们都是知道关系型数据库天生是不具备分布式分片存储的,也就是不支持分布式写,但是它天然的支持分布式读。一主多从是部署多台从库只读实例,通过冗余主库的数据来分担读请求的压力,路由算法可有代码实现或者中间件解决,具体可以根据团队的运维能力与代码组件支持视情况选择。

一主多从在还没找到根治方案前是一个非常好的应急解决方案,特别是在现在云服务的年代,扩展从库是一件非常方便的事情,而且一般情况只需要运维或者DBA解决就行,无需开发人员接入。当然这方案也有缺点,因为数据无法分片,所以主从的数据量完全冗余过去,也会导致高的硬件成本。从库也有其上限,从库过多了会主库的多线程同步数据的压力。

选择合适的存储系统

NoSQL主要以下五种类型:键值型、文档型、列型、图型、搜素引擎,不同的存储系统直接决定了查找算法存储数据结构,也应对了需要解决的不同的业务场景。NoSQL的出现也解决了关系型数据库之前面临的难题(性能、高并发、扩展性等)。

例如,ElasticSearch的查找算法是倒排索引,可以用来代替关系型数据库的低性能、高消耗的Like搜索(全表扫描)。而Redis的Hash结构决定了时间复杂度为O(1),还有它的内存存储,结合分片集群存储方式以至于可以支撑数十万QPS。

因此本类型的方案主要有两种:CQRS、替换(选择)存储,这两种方案的最终本质基本是一样的主要使用合适存储来弥补关系型数据库的缺点,只不过切换过渡的方式会有点不一样。

CQRS

CQS(命令查询分离)指同一个对象中作为查询或者命令的方法,每个方法或者返回的状态,要么改变状态,但不能两者兼备

讲解CQRS前得了解CQS,有些小伙伴看了估计还没不是很清晰,我这里用通俗的话解释:某个对象的数据访问的方法里,要么只是查询,要么只是写入(更新)。而CQRS(命令查询职责分离)基于CQS的基础上,用物理数据库来写入(更新),而用另外的存储系统来查询数据。因此我们在某些业务场景进行存储架构设计时,可以通过关系型数据库的ACID特性进行数据的更新与写入,用NoSQL的高性能与扩展性进行数据的查询处理,这样的好处就是关系型数据库和NoSQL的优点都可以兼得,同时对于某些业务不适于一刀切的替换存储的也可以有一个平滑的过渡。

从代码实现角度来看,不同的存储系统只是调用对应的接口API,因此CQRS的难点主要在于如何进行数据同步。

数据同步方式

一般讨论到数据同步的方式主要是分拉:

推指的是由数据变更端通过直接或者间接的方式把数据变更的记录发送到接收端,从而进行数据的一致性处理,这种主动的方式优点是实时性高。

拉指的是接收端定时的轮询数据库检查是否有数据需要进行同步,这种被动的方式从实现角度来看比推简单,因为推是需要数据变更端支持变更日志的推送的。

而推的方式又分两种:CDC(变更数据捕获)和领域事件。对于一些旧的项目来说,某些业务的数据入口非常多,无法完整清晰的梳理清楚,这个时候CDC就是一种非常好的方式,只要从最底层数据库层面把变更记录取到就可。

对于已经服务化的项目来说领域事件是一种比较舒服的方式,因为CDC是需要数据库额外开启功能或者部署额外的中间件,而领域事件则不需要,从代码可读性来看会更高,也比较开发人员的维护思维模式。

替换(选择)存储系统

因为从本质来看该模式与CQRS的核心本质是一样的,主要是要对NoSQL的优缺点有一个全面认识,这样才能在对应业务场景选择与判断出一个合适的存储系统。这里我像大家介绍一本书马丁.福勒《NoSQL精粹》,这本书我重复看了好几遍,也很好全面介绍各种NoSQL优缺点和使用场景。

当然替换存储的时候,我这里也有个建议:加入一个中间版本,该版本做好数据同步与业务开关,数据同步要保证全量与增加的处理,随时可以重来,业务开关主要是为了后续版本的更新做的一个临时型的功能,主要避免后续版本更新不顺利或者因为版本更新时导致的数据不一致的情况出现。在跑了一段时间后,验证了两个不同的存储系统数据是一致的后,接下来就可以把数据访问层的底层调用替换了。如此一来就可以平滑的更新切换。

结束

本文到这里就把八大方案介绍完了,在这里再次提醒一句,每个方案都有属于它的应对场景,咱们只能根据业务场景选择对应的解决方案,没有通吃,没有银弹。

这八个方案里,大部分都存在数据同步的情况,只要存在数据同步,无论是一主多从、分布式缓存、CQRS都好,都会有数据一致性的问题导致,因此这些方案更多适合一些只读的业务场景。当然有些写后既查的场景,可以通过过渡页或者广告页通过用户点击关闭切换页面的方式来缓解数据不一致性的情况。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1336774.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

越南语翻译中文有什么特点,怎样翻译比较好?

近年来,随着中越经济贸易的日益频繁,语言交流已无法避免,越南语翻译的需求也持续增加。那么,越南语有何独特之处?越南语翻译成中文时,又该如何处理呢? 专业人士指出,在进行越南语翻译…

cefsharp120.1.110(cef120.1.10,Chromium120.0.6099.129)升级测试及其他H264版本

一、版本变化 v120.1.80–>v120.1.110 相对于120.1.80 更新了一个安全更新,针对Google 获悉存在针对 CVE-2023-7024 的漏洞。 说明:本版本暂时不支持264,其他H264版本参考119,116,115,114,111,110,109,107,100等版本 v109是支持win7/8/8.1最后一个版本(推荐v100版本) v…

鸿蒙4升级进展:共137款产品加入升级,Mate 20也能升级了

从华为官方发布的鸿蒙升级进展来看,2018年发布的Mate 20系列机型也开始了鸿蒙4系统升级的测试招募。 5年之期已到,再战5年不是梦想? 另外,从明年一季度的升级预告来看,春节前后升级的主要为穿戴手表产品。 目前&…

spring security oauth2搭建认证服务器

如图(上面图片的代码在业务项目中),第一步在独立的业务项目中,先获取授权码(也叫jsessionId)、获取授权码的路径就是 /oauth2/authorize,这个路径是oauth2的框架中被OAuth2AuthorizationEndpoin…

YOLOv7训练数据报错

YOLOv7训练数据报错 错误提示1解决方案问题2解决方案成功运行 错误提示1 fatal: not a git repository (or any of the parent directories): .git Traceback (most recent call last):File "/home/ubuntu/code/yolov7-main/utils/google_utils.py", line 26, in att…

为什么说依赖抽象就变得更加灵活呢?举例

说依赖抽象变得更加灵活的主要原因在于它提供了更大的替换和扩展的空间。让我们通过一个简单的例子来说明: 考虑一个电商系统,其中有一个OrderProcessor类负责处理订单,它依赖于一个PaymentGateway用于处理支付。最初的设计可能如下所示&…

前端,build后index报错,noscript

解决方法: npx update-browserslist-dblatest

CSS、JavaScript实现进度条效果HTML

CSS、JavaScript实现进度条效果HTML 效果图 代码如下&#xff1a; <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><title>ProgressBar</title><style>* {margin: 0;padding: 0;}body {position…

【HTML5】第2章 HTML5标签和属性

学习目标 掌握文本控制标签的用法&#xff0c;能够使用文本控制标签设置文本样式。 掌握图像标签的用法&#xff0c;能够使用图像标签在网页中嵌入图片。 掌握超链接标签的用法&#xff0c;能够使用超链接实现页面的跳转。 掌握列表标签的用法&#xff0c;能够使用列表标签设…

AMEYA360:思瑞浦发布全新并联基准芯片—:TPR43x系列产品

聚焦高性能模拟芯片和嵌入式处理器的半导体公司——思瑞浦(3PEAK, 股票代码&#xff1a;688536)推出全新并联基准芯片TPR433/TPR434。 TPR433/TPR434基于BCD工艺&#xff0c;电压精度0.5%25C&#xff0c;可广泛应用于电源、照明、工业设备等领域。 TPR433/434产品特性 *通过外部…

互联网加竞赛 YOLOv7 目标检测网络解读

文章目录 0 前言1 yolov7的整体结构2 关键点 - backbone关键点 - head3 训练4 使用效果5 最后 0 前言 世界变化太快&#xff0c;YOLOv6还没用熟YOLOv7就来了&#xff0c;如果有同学的毕设项目想用上最新的技术&#xff0c;不妨看看学长的这篇文章&#xff0c;学长带大家简单的…

右值引用和移动语义以及C++11新增的类功能

正文开始前给大家推荐个网站&#xff0c;前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站。 右值引用和左值引用 传统的C语法中就有引用的语法&#xff0c;而C11中新增了的右值引用语法特…

移动端防截屏录屏技术在百度账户系统实践

作者 | Seven 导读 在移动端应用的开发过程中&#xff0c;保护用户隐私和应用内敏感信息安全是一个不可忽视的课题。随着诈骗手段的升级&#xff0c;“共享屏幕”被诈骗分子频频使用&#xff0c;因为密码被泄露而导致受害者财物受损的事情层出不穷。只要开启了“共享屏幕”–本…

vue3使用Cascader联级选择器的懒加载+回显

效果图 页面代码 // separator是改变文字链接的方式&#xff0c; <el-cascaderseparator"-"v-model"currentRegionList":props"DeptRegionList":options"getRegionList"change"handleRegionListFun"ref"deptRegio…

Java——Windows系统怎么查看某个端口被占用和杀死进程解除占用,看这一篇就够了!!!

Windows系统端口占用 1. netstat -ano2. 查看某端口占用的PID3. tasklist|findstr "PID"4. 解除端口占用 总结 本篇文章介绍一下windows系统中怎么查看某个端口被占用以及如何解除占用。 1. netstat -ano 作用&#xff1a;查看系统中所有端口的占用情况 可以看到本…

面对勒索,金融机构该怎么办?

就在近期&#xff0c;某大行美国子公司被勒索软件攻击&#xff0c;使得部分交易系统中断&#xff0c;该行也在网站确认遭受了勒索软件攻击。这再次引发了金融机构对勒索软件的警惕与担忧&#xff0c;也凸显了一个重要的安全问题&#xff1a;犯罪分子不仅能窃取财产&#xff0c;…

MessageBox和HubSpot:数字化时代综合营销引擎

在数字时代&#xff0c;社交媒体已经成为企业与客户互动的重要平台。然而&#xff0c;随着信息的爆炸性增长&#xff0c;有效管理社交互动变得愈发具有挑战性。企业需要在海量信息中找到并回应关键的用户消息&#xff0c;这正是数字时代社交互动面临的主要挑战。为了解决这一问…

搭建Nginx文件下载站点

一、下载Nginx 首先&#xff0c;确保你的服务器上已经安装了Nginx&#xff0c;使用编译安装&#xff0c;下载最新版Nginx。 wget https://nginx.org/download/nginx-1.25.3.tar.gz tar -xf nginx-1.25.3.tar.gz二、安装Fancyindex和Nginx-Fancyindex-Theme模块 # 下载Fancyin…

k8s中的整体架构 ,pod含义,服务类型,网络通讯等

k8s中的整体架构 &#xff0c;pod含义&#xff0c;服务类型&#xff0c;网络通讯等 k8s整体架构pod内部和pod之间的通讯k8s的组件 k8s整体架构 上图中&#xff0c;较大的红框是k8s中的master节点&#xff0c;负责接受请求&#xff0c;调度任务&#xff0c;管理节点等&#xff0…

【网络奇缘】——奈氏准则和香农定理从理论到实践一站式服务|计算机网络

&#x1f308;个人主页: Aileen_0v0 &#x1f525;热门专栏: 华为鸿蒙系统学习|计算机网络|数据结构与算法 &#x1f4ab;个人格言:"没有罗马,那就自己创造罗马~" 目录 失真 - 信号的变化 影响信号失真的因素&#xff1a; ​编辑 失真的一种现象&#xff1a;码间…