`
wbj0110
  • 浏览: 1603461 次
  • 性别: Icon_minigender_1
  • 来自: 上海
文章分类
社区版块
存档分类
最新评论

ORM对象缓存探讨

阅读更多

对象缓存和n+1问题分析

我们常见的OLTP类型的web应用,性能瓶颈往往是数据库查询,因为应用服务器层面可以水平扩展,但是数据库是单点的,很难水平扩展,当数据库服务器发生磁盘IO,往往无法有效提高性能,因此如何有效降低数据库查询频率,减轻数据库磁盘IO压力,是web应用性能问题的根源。

对象缓存是所有缓存技术当中适用场景最广泛的,任何OLTP应用,即使实时性要求很高,你也可以使用对象缓存,而且好的ORM实现,对象缓存是完全透明的,完全不需要你的程序代码进行硬编码。

用不用对象缓存,怎么用对象缓存,不是一个简单的代码调优技巧,而是整个应用的架构问题。在你开发一个应用之前,你就要想清楚,这个应用最终的场景是什么?会有多大的用户量和数据量。你将采用什么方式来架构这个应用:

也许你偏好对SQL语句级别的优化,数据库设计当大表有很多冗余字段,会尽量消除大表之间的关联关系,当数据量很大以后,选择分库分表的优化方式,这是目前业界常规做法。但是也可以选择使用ORM的对象缓存优化方式:数据库设计避免出现大表,比较多的表关联关系,通过ORM以对象化方式操作,利用对象缓存提升性能。举个例子:

论坛的列表页面,需要显示topic的分页列表,topic作者的名字,topic最后回复帖子的作者,常规做法:

select ... from topic left join user left join post .....  

你需要通过join user表来取得topic作者的名字,然后你还需要join post表取得最后回复的帖子,post再join user表取得最后回贴作者名字。也许你说,我可以设计表冗余,在topic里面增加username,在post里面增加username,所以通过大表冗余字段,消除了复杂的表关联:

select ... from topic left join post... 

OK,且不说冗余字段的维护问题,现在仍然是两张大表的关联查询。然后让我们看看ORM怎么做?

select * from topic where ... --分页条件

就这么一条SQL搞定,比上面的关联查询对数据库的压力小多了。 也许你说,不对阿,作者信息呢?回贴作者信息呢?这些难道不会发送SQL吗?如果发送SQL,这不就是臭名昭著的n+1条问题吗? 你说的对,最坏情况下,会有很多条SQL:

select * from user where id = topic_id...;
....
select * from user where id = topic_id...;

select * from post where id = last_topic_id...;
....
select * from post where id = last_topic_id...;

select * from user where id = post_id...;
....
select * from user where id = post_id...;

事实上何止n+1,根本就是3n+1条SQL了。那你怎么还说ORM性能高呢? 因为对象缓存在起作用,你可以观察到后面的3n条SQL语句全部都是基于主键的单表查询,这3n条语句在理想状况下(比较繁忙的web网站的热点数据),全部都可以命中缓存。所以事实上只有一条SQL,就是:

select * from topic where ...--分页条件 

这条单表的条件查询和直接使用join查询SQL通过字段冗余简化过后的大表关联查询相比,当数据量大到一定程度以后对数据库磁盘IO的压力很小,这就是对象缓存的真正威力!

更进一步分析,使用ORM,我们不考虑缓存的情况,那么就是3n+1条SQL。但是这3n+1条SQL的执行速度一定比SQL的大表关联查询慢吗?不一定!因为使用ORM的情况下,第一条SQL是单表的条件查询,在有索引的情况下,速度很快,后面的3n条SQL都是单表的主键查询,在繁忙的数据库系统当中,3n条SQL几乎可以全部命中数据库的data buffer。但是使用SQL的大表关联查询,很可能会造成大范围的表扫描,造成频繁的数据库服务器磁盘IO,性能有可能是非常差的。

因此,即使不使用对象缓存,ORM的n+1条SQL性能仍然很有可能超过SQL的大表关联查询,而且对数据库磁盘IO造成的压力要小很多。这个结论貌似令人难以置信,但经过我的实践证明,就是事实。前提是数据量和访问量都要比较大,否则看不出来这种效果。

对象缓存的命中率

应用场景

是OLTP还是OLAP应用,即使是OLTP,也要看访问的频度,一个极少被访问到的缓存等于没有什么效果。一般来说,互联网网站是非常适合缓存应用的场景。

缓存的粒度

毫无疑问,缓存的粒度越小,命中率就越高,对象缓存是目前缓存粒度最小的,因此被命中的几率更高。举个例子来说吧:你访问当前这个页面,浏览帖子,那么对于ORM来说,需要发送n条SQL,取各自帖子user的对象。很显然,如果这个user在其他帖子里面也跟贴了,那么在访问那个帖子的时候,就可以直接从缓存里面取这个user对象了。

架构的设计

架构的设计对于缓存命中率也有至关重要的影响。例如你应该如何去尽量避免缓存失效的问题,如何尽量提供频繁访问数据的缓存问题,这些都是考验架构师水平的地方。再举个例子来说,对于论坛,需要记录每个topic的浏览次数,所以每次有人访问这个topic,那么topic表就要update一次,这意味着什么呢?对于topic的对象缓存是无效的,每次访问都要更新缓存。那么可以想一些办法,例如增加一个中间变量记录点击次数,每累计一定的点击,才更新一次数据库,从而减低缓存失效的频率。

缓存的容量和缓存的有效期

缓存太小,造成频繁的LRU,也会降低命中率,缓存的有效期太短也会造成缓存命中率下降。

所以缓存命中率问题不能一概而论,一定说命中率很低或者命中率很高。但是如果你对于缓存的掌握很精通,有意识的去调整应用的架构,去分解缓存的粒度,总是会带来很高的命中率的。

分享到:
评论

相关推荐

    php中的orm

    在IT行业中,ORM(Object-Relational Mapping)是一种软件设计技术,它允许程序员用面向对象的方式来操作数据库,而无需直接编写SQL语句。在PHP中,ORM被广泛应用于Web开发,使得开发人员能够以更加抽象和高效的方式...

    ORM实验(超级详细!)(期末复习很管用!!!).zip

    7. **缓存机制**:探讨ORM框架中的缓存技术,MyBatis的一级缓存和二级缓存的原理及配置,以及如何优化缓存策略。 8. **性能优化**:分析ORM框架可能带来的性能问题,比如N+1查询问题,以及相应的优化措施,如批处理...

    sqlite3的ORM框架

    在本案例中,我们将深入探讨SQLite3的ORM框架以及它如何与C++结合使用。 首先,SQLite3是一个轻量级的、无服务器、自包含的、非常可靠的嵌入式SQL数据库引擎。它的设计目标是提供一个易于嵌入到各类应用中的数据库...

    手写orm

    【描述】:虽然没有具体的描述,但可以推测这篇博客可能探讨了作者自己实现ORM框架的过程,可能涉及了以下内容:理解ORM的基本原理,设计数据模型与数据库表之间的映射,如何处理对象的持久化,以及事务管理等核心...

    Doctrine2 ORM 官方文档

    - **缓存**:探讨了不同级别的缓存机制,以及如何利用它们来减少数据库访问次数。 - **部分对象**:介绍了如何仅加载实体的部分属性,以节省内存消耗。 - **变更追踪策略**:讨论了不同的变更追踪机制,以满足不同的...

    基于ORM模型的物资管理系统的设计和实现

    本文将深入探讨如何利用ORM模型设计并实现一个高效、便捷的物资管理系统。 ORM,即对象关系映射,是一种编程技术,它将数据库的表结构映射为程序中的对象,使得开发者可以使用面向对象的方式来操作数据库,降低了...

    基于java 简易ORM 框架实现(二)

    在本篇“基于Java简易ORM框架实现(二)”中,我们将深入探讨如何构建一个简单的对象关系映射(Object-Relational Mapping,ORM)框架。ORM框架是Java开发中常用的一种技术,它允许开发者以面向对象的方式操作数据库,...

    org.springframework.orm.jar.zip

    本文将深入探讨Spring ORM模块的核心概念、功能以及实际应用。 一、ORM(对象关系映射)简介 ORM是一种技术,用于将数据库的关系模型映射到面向对象的编程语言中,以减轻开发者的数据库操作负担。Spring ORM模块...

    ORM自定义框架

    在这个自定义的ORM框架"MyOrm"中,我们可以深入探讨ORM的核心概念和实现方式。 首先,ORM框架的核心思想是将数据库表与Java类映射,表中的每一行对应一个对象实例,表字段对应对象的属性。在"MyOrm"中,我们需要...

    galbanum.orm.cache,logger,ioc

    ORM提供对象化的数据库操作,缓存提升性能,日志记录辅助问题排查,而依赖注入则有利于代码的可测试性和可扩展性。这四个核心概念都是现代.NET开发中不可或缺的部分,它们共同推动着高效、灵活和可维护的软件开发...

    hibernate-orm-3.2.zip

    下面,我们将深入探讨Hibernate ORM 3.2中的关键知识点。 一、对象关系映射(ORM) ORM是将数据库中的表映射为Java对象的过程,使得开发者可以使用面向对象的方式来操作数据,而无需关心底层的SQL语句。Hibernate ...

    ORM、DB面试题

    在IT行业中,数据库(DB)和对象关系映射(ORM)是两个至关重要的概念,尤其在面试中常常被考察。本文将深入探讨这两个主题,帮助你准备相关的面试问题。 首先,我们来理解数据库(DB)。数据库是存储和管理数据的...

    单独提取django_orm

    本篇文章将深入探讨Django ORM的基础知识、主要特点以及如何在实际项目中使用它。 一、Django ORM的基本概念 Django ORM通过模型(Model)类来定义数据库表结构。模型类是Python类,继承自django.db.models.Model...

    orm工具策略和最佳实践源代码

    标题"ORM工具策略和最佳实践源代码"意味着我们将探讨ORM工具,特别是Hibernate框架在实际应用中的策略和最佳实践,同时提供了相关的源代码供学习参考。ORM工具的主要目标是消除数据访问层(DAO,Data Access Object...

    巧用工具封装属于自己的ORM框架【XutilsDbUtil】分装

    在这个主题中,我们将探讨如何封装一个自定义的ORM框架,以XutilsDbUtil为例。 XutilsDbUtil是基于XUtils框架的一个数据库操作组件,它简化了Android开发中的数据库操作。XUtils是由百度开源的一个综合性框架,包含...

    day37 05-HIbernate二级缓存:一级缓存更新同步到二级缓存及二级缓存配置文件

    本篇文章将深入探讨Hibernate的二级缓存机制,以及如何进行一级缓存与二级缓存的同步,同时还会介绍二级缓存的配置文件设置。 一级缓存是Hibernate默认提供的缓存,每个SessionFactory实例都有一个一级缓存。当对象...

    4. Android 开发框架, 包含_ 图片缓存, ORM,异步任务

    本资源包主要涵盖了三个关键领域:图片缓存、ORM(对象关系映射)和异步任务处理。接下来,我们将深入探讨这些知识点。 首先,图片缓存是Android应用中不可或缺的部分,尤其在处理大量图片展示时。Android设备的...

    Android ORM 数据库的使用

    本篇将深入探讨Android中ORM数据库的使用,特别是以ActiveAndroid为例。 **ORM框架介绍** ORM是一种编程技术,它可以将关系型数据库的数据映射到对象上,使得开发者可以像操作普通对象一样操作数据库。ORM框架消除...

    hibernate-framework-orm-4.2.4.Final.zip

    Hibernate,作为一个强大的对象关系映射(ORM)框架,自推出以来就深受Java开发者喜爱。4.2.4.Final是Hibernate的一个稳定版本,它提供了诸多改进和新特性,旨在优化开发效率,提升应用程序性能。本文将详细探讨该...

    orm.rar_orm

    现在我们将深入探讨这三个框架以及它们在ORM中的作用。 Struts是Apache组织开发的一个MVC(Model-View-Controller)框架,主要用于构建Web应用程序。它将业务逻辑、数据访问和用户界面分离,提高了代码的可维护性和...

Global site tag (gtag.js) - Google Analytics