`

提升数据库性能的重要手段--冗余

阅读更多

前言

 

在程序设计中有一种常用的提升数据查询性能的手段以--空间换时间。典型的场景就是使用缓存,在查询数据库之前加一层全局共享缓存(如:redis),更有甚者在应用实例内部在加一层本地缓存。以java应用+mysql数据库为例,该架构设计方式如下:



 

 

数据查询逻辑为:

 



 

 

本地缓存的查询速度是纳秒级

Redis缓存的查询速度是毫秒级

Msyql数据的查询速度是毫秒级-秒级

 

有人会说既然本地缓存是最快的为什么不直接用本地缓存,还要使用redis缓存呢?本地缓存说白就是jvm内存,空间毕竟是有限的,再者分布式多实例部署的应用有多个jvm实例,本地缓存分散在各个实例内部不便于同步更新,使用上存在局限。具体怎么去权衡“本地缓存”和全局共享缓存不是本次讨论的重点,不再过多介绍。

 

所以为了提高性能需要把同一份数据存放三份,这就是数据冗余,典型的以空间换时间的使用场景。

 

可以发现在该场景中,最终瓶颈还是msyql数据库(在缓存失效时都会落到数据库),如果想要进一步的优化性能,一个重要的优化点还是在msyql数据库查询性能优化上(当然还有一个点就是优化程序本身)。

 

以空间换时间的方式同样适用运用到mysql数据库的性能优化中,主要体现在三个地方:表字段冗余、读写分离之镜像复制、读写分离之非对称复制。下面根据不同的场景,分别进行讲解。

 

表字段冗余

 

读书期间,在数据库表设计章节,相信大家都学习过“范式”。如果完全遵循“三范式”设计的数据库,对于数据存储来说可以极大的降低数据的存储量。但对于数据查询来说,会有很多联表查询,这会非常影响性能。对于高频查询的sql语句来说 “联表查询”绝对是个灾难。

 

这时的常用手段就是“表字段冗余”,举个真实的案例:在一个项目初期,使用一张表名为“sale_info”的表存放活动信息。随着业务的发展,该表的字段越来越多,为了防止一张表的字段太多,最简单的做法就是新增一个扩展表“sale_info_ext”,后续新增的字段都放到这张扩展表里。

 

这种简单的处理方式,解决了宽表问题。但同时又引入了新的问题,在查询活动信息时,由于业务数据分散在两张表里,经常需要做联表查询select a.xx,b.xx from sale_info a left join sale_info_ext b on a.id=b.sale_id where “省略其他条件。刚开始没有发现问题,但随着业务的增长,两张表的数据越来越多,应用程序经常出现“timeout”现象,通过分析慢查询日志有一条高频联表查询语句在中暴露出来。发现该问题后,初步做法是优化索引,也就是对省略其他条件字段加索引,但效果并不明显。

 

最后的做法是:分析者两张表的所有联表查询”sql语句,把主业务相关的字段迁移到sale_info表,把副业务相关的字段迁移到sale_info_ext表,对于主副业务都需要的常用字段 在两张表中做冗余存储。从而保证高频查询的sql语句,都是单表查询,最终解决该问题。对于一些低频查询的sql语句,仍然联表查询已经无所谓了(有时还应防止这些低频查询的sql语句转为高频)。

 

“表字段冗余”说起来原理简单,但实际操作有时会比较复杂。最重要的原则还是要根据业务划分,找准冗余点才能做到以空间换时间,否则空间消耗了时间减少--这就不是我们想要的效果了。

 

读写分离之镜像复制

 

对于“读多写少”的业务(其实大部分业务都是这种场景),最常见的以空间换时间的做法就是“读写分离”,要做读写分离 首先要做主备。对应“写”业务直接写主库,对于延迟要求不高的业务读从库。现在的问题就变为 主从同步问题,数据同步始终会有延迟(即便是采用数据库自带的,如mysqlReplication)。所以,对于不允许延迟的业务,只能读主库

 

所谓“镜像复制”就是所有备库的内容,跟主库内容完全一致。“镜像复制”,又存在两种情况一主多备多主多备。对于,延迟要求不高的业务,可以采用一主多备;对于,延迟要求高的业务,可以采用多主多备,具体做法是:写入数据时,写入多个主库(或者说写库),对于不允许延迟的业务直接从主库中读取数据,对于延迟要求不高的业务到从库读取数据。多主多备的架构设计如下:



 

 

这时会出现在同一个应用中有多个数据源的情况,一般做法是:在spring配置文件中配置多个数据源,获取数据源时通过一个工具类获取:

 

public class DataSourceUtil {
    private List<DataSource> readDatasources;//通过spring配置注入
    private List<DataSource> writeDatasources;//通过spring配置注入
    private Random random = new Random();
 
    public List<DataSource> getALLWrite(){//获取所有的写数据源
        return readDatasources;
    }
 
    public DataSource getOneWrite(){//随机获取一个写数据源 用于“非延时”读
        return readDatasources.get(random.nextInt(readDatasources.size()));
    }
 
    public DataSource getOneRead(){//随机获取一个写数据源 用于“可延时”读
        return readDatasources.get(random.nextInt(readDatasources.size()));
    }
}

 

最后这些数据源配置可以放到配置管理系统,可以实现在线切换数据库

 

读写分离之非对称复制

 

前一种镜像同步方式,是主库和备库的内容是完全相同的。在分库分表的系统中,做数据冗余还有另外一种数据冗余方式:非对称复制,主要作用就是减少查询时多张表的join操作。下面看一个真实的场景:

 

在笔者所在的一个活动页cms系统中,需要记录每个页面上的sku(商品编码),每天上线的活动页数量成千上万个,每个页面上对应的sku从几十个到几百个不等。可见数据量,是比较大,一般会进行分表存储。

 

应用中经常会 根据“活动页”id查询页面上的sku列表,为了减少表的join次数,我们用“活动页”idhash(可以直接取模,或者使用一致性hash) 进行分表,保证每个“活动页”id对应的sku都存在同一张表中。假设分8张表存储,分表方式如下:



 

 

现在要查询某个“活动页id”下的所有sku,首先通过“活动页idmod 8,计算出数据所在的表,然后通过一条简单的select语句查询该表就搞定。

 

但现在问题来了,“业务方”想要知道某个sku 今天在哪些页面上出现过,用来对比各个不同的页面推广效果。怎么办呢?如果按照上述分表,包含某个sku的的活动页id”分散在8张表里,需要进行7join操作或者查询8次进行合并 采用获取到所有的活动页id”

 

这种场景就可以使用“非对称复制”,在写入数据时,我们可以用另外的8张表存储上述相同的数据,唯一不同的地方就是分表规则改为对 sku编号进行hash(取模或者一致性hash都可以),分表方式如下:



 

 

好了,现在要查询某天某个sku出现过的活动页面有哪些,也就同样简单了,首先通过sku编号 mod 8获取到所在表,再通过一个简单的selec语句查询该表就搞定。

 

也就是说:如果查询条件是“活动页id”就使用第一种分表规则;反正就是使用第二种分表规则。都是单表唯一索引查询,查询速度也非常快。只是存储空间翻倍,这也是典型的空间换时间的场景。

 

这里讲的是单库操作,按照第二冗余方式所讲,如果需要做读写分离,这时有两种方案。方案一:两种分表方式的写入操作,都在同一个主库中进行,再通过数据库自带的同步工具同步到读库,查询时直接读读库。方案二:在写入数据时,两种分表方式分别写入不同的数据库,这时直接借助程序自己实现,也可以借助一些数据库中间件来完成。第二种方式虽然麻烦些,但如果数据量大 同时查询又很频繁,采用这种方式可以进一步实现不同的查询业务分库,单个数据库可以存储更多数据 并且降低单个数据库并发查询压力。

 

总结

 

仅对sql语句层面进行优化始终有局限,作为项目里的架构师一定要从更高层次出发,根据不同的业务场景采用不同架构设计手段,以减轻数据库的压力。这里不是说优化sql语句不重要,优化sql是需要首先做。

 

 

另外以空间换时间是架构设计中的常用手段,可以在各种不同的场景下使用,达到以多个廉价的pc机(空间),换取需要使用昂贵的大中型机采用达到的性能(时间)。

 

出处:

http://moon-walker.iteye.com/blog/2405545

 

  • 大小: 33.2 KB
  • 大小: 38 KB
  • 大小: 35.6 KB
  • 大小: 19.8 KB
  • 大小: 20.9 KB
0
0
分享到:
评论

相关推荐

    数据库设计规范 数据库高效设计的好东西

    - 通过索引优化、查询优化、存储过程的使用、分区策略等手段提升数据库性能。此外,合理设计数据库的事务处理机制,平衡并发性能和数据一致性。 7. **数据库设计规范**: - 遵循一些最佳实践,例如,使用有意义的...

    mysql面试题-mysql经典面试题目-数据库的基本概念-SQL语法-事务处理-索引优化-性能调优-mysql-面试题目

    数据库连接池是管理数据库连接的机制,通过复用已存在的连接而不是每次请求时创建新的连接,从而提升数据库访问性能。 事务隔离级别有读未提交(READ UNCOMMITTED)、读已提交(READ COMMITTED)、可重复读...

    数据库原理及应用-SQLServer2008版)-马桂婷-武洪萍-袁淑玲-pdf

    最后,性能调优部分会教导读者如何通过索引、查询优化、资源管理等手段提升数据库的运行效率。 此外,书中可能还包含了一些实战项目和练习题,以帮助读者将所学知识运用到实际场景中,提升解决实际问题的能力。例如...

    数据库性能优化方案

    数据库性能优化是IT领域中的一个核心议题,尤其对于处理大量数据的企业级应用而言,高效的数据库性能至关重要。在SQL Server、MySQL和Oracle这三大主流数据库系统中,优化策略各有其特点和技巧。以下将针对这些...

    数据库性能优化方法.pptx

    - **重要性**:优化数据库性能不仅能够提升系统的稳定性和可靠性,还能改善用户体验,是IT项目成功的关键因素之一。 #### 二、数据库性能的影响因素 - **数据库设计**:包括表结构、索引设计等方面,直接影响到...

    数据库原理讲义6-12章

    本章可能讲解如何通过索引、查询优化、数据分区和缓存等手段提升数据库的性能。 第十一章:数据库应用开发 这部分可能涵盖了数据库应用程序的开发过程,包括使用ODBC/JDBC接口、数据库连接池、存储过程和触发器的...

    数据库性能诊断

    调整内存分配、设置合适的连接池大小、控制线程并发数量,以及优化I/O调度,都是提升数据库性能的重要手段。例如,为频繁访问的数据分配更多缓存,可以减少磁盘I/O,提高响应速度。 第五种武器:监控与调优工具 ...

    数据库课程设计报告-酒店管理系统.doc

    此外,安全性也是数据库设计的重要方面。酒店管理系统涉及客户隐私,需要设置权限控制,确保只有授权人员可以访问和修改数据。这可能包括用户认证、角色管理以及访问权限的设定。 再者,性能优化是提高系统效率的...

    数据库性能问题定位

    4. **查询优化**:优化查询是提升数据库性能的重要手段。这包括合理使用索引,避免全表扫描,减少JOIN操作,以及优化子查询等。使用EXPLAIN或类似功能来分析查询执行计划,可以帮助找出查询的低效之处。 5. **索引...

    OCP 中文资料-数据库性能优化

    理解范式理论,合理划分实体关系,以及在适当的地方使用分区和分片,都是提升数据库性能的重要手段。 5. **资源管理**:数据库管理系统需要有效地分配CPU、内存、磁盘I/O等资源。Oracle的Automatic Workload ...

    Oracle数据库性能优化实践指南

    《Oracle数据库性能优化实践指南》是一本专注于提升Oracle数据库运行...通过阅读《Oracle数据库性能优化实践指南》,读者将能够掌握一系列实用的优化技巧,提升数据库系统的整体效能,为企业信息化建设提供强大的后盾。

    数据库优化方法论-梁敬彬 优化的思路PPT教案.pptx

    1. **意识**:这包括对数据库性能问题的敏感度,以及对整个流程的理解。就像小余反思自己的买鱼过程,我们需要对数据库操作的每个环节有深入认识,才能发现问题并提出解决方案。 2. **技能**:小余通过参加DTCC...

    基于Oracle的数据库系统性能优化策略.pdf

    - 操作系统和数据库参数调优,例如调整Oracle的初始化参数文件,根据系统负载进行合理配置,有助于提升数据库性能。 - 使用Oracle的内置性能分析工具,如SQL Trace、AWR(Automatic Workload Repository)和ASH...

    数据库性能调优 原理与技术

    数据库性能调优是IT领域中的一个关键话题,特别是在大数据量和高并发的业务环境中,优化数据库性能至关重要。...通过深入学习并实践这些技术,可以显著提升数据库性能,为企业的数据服务提供坚实保障。

    中国数据库技术大会数据库性能优化专场PPT资料.rar

    总之,"中国数据库技术大会数据库性能优化专场PPT资料"包含了丰富的理论知识和实践经验,无论是对于数据库管理员还是开发人员,都是提升数据库性能的宝贵资源。通过深入学习和实践,我们可以有效地提升数据库系统的...

    数据库性能优化详解数据库性能优化详解.doc

    优化硬件配置,如使用SSD硬盘、增加内存或使用更快的处理器,可以显著提升数据库性能。 5. **数据库参数调优**:每个数据库系统都有许多可调整的参数,如缓冲池大小、连接池设置、事务隔离级别等。合理设置这些参数...

    DB2 UDB AS400数据库性能和查询优化.rar

    本资料集“DB2 UDB AS400数据库性能和查询优化.rar”着重探讨了如何在AS/400环境中提升DB2 UDB的性能并优化查询。 1. **数据库性能优化**:性能优化涉及多个方面,如数据库设计、索引策略、存储配置、SQL语句优化等...

    数据库实训报告(数据库结课报告)

    - 数据库性能监控:使用工具(如MySQL的SHOW STATUS、EXPLAIN)分析查询效率,找出性能瓶颈。 - 故障排查:遇到问题时,通过日志分析、调试等手段定位问题并解决。 以上是数据库实训报告可能涉及的主要知识点,...

    (Oracle数据库性能优化

    在Oracle数据库性能优化中,以下几个核心概念和技术是至关重要的: 1. **SQL优化**:SQL查询是数据库操作的基础,优化SQL语句可以显著提升性能。这包括使用合适的索引、避免全表扫描、减少子查询以及利用绑定变量等...

    数据库性能afhfgahgjh5687879

    磁盘阵列能够显著提高数据读写速度以及数据的安全性,因此是提升数据库性能的重要手段之一。 #### 磁盘阵列RAID简介 RAID是一种将多个独立磁盘组合成一个逻辑单元的技术,旨在通过数据冗余来提高数据的可靠性和...

Global site tag (gtag.js) - Google Analytics