少年阿宾

那些青春的岁月

  BlogJava :: 首页 :: 联系 :: 聚合  :: 管理
  500 Posts :: 0 Stories :: 135 Comments :: 0 Trackbacks

#

反射只能读取类信息,而 ASM 除了读还能写。
反射读取类信息时需要进行类加载处理,而 ASM 则不需要将类加载到内存中。
反射相对于 ASM 来说使用方便,想直接操纵 ASM 的话需要有 JVM 指令基础。  
反射是读取持久堆上存储的类信息。而 ASM 是直接处理 .class 字节码的小工具(工具虽小,但是功能非常强大!) 
posted @ 2015-04-03 18:20 abin 阅读(1222) | 评论 (0)编辑 收藏

 If you are not sure about the string pool usage, try -XX:+PrintStringTableStatistics JVM argument. It will print you the string pool usage when your program terminates.
posted @ 2015-03-31 18:22 abin 阅读(338) | 评论 (0)编辑 收藏

基本概念:
      在软件系统中,“行为请求者”与“行为实现者”通常呈现一种“紧耦合”。但在某些场合,比如要对行为进行“记录、撤销/重做、事务”等处理,这种无法抵御变化的紧耦合是不合适的。在这种情况下,如何将“行为请求者”与“行为实现者”解耦?将一组行为抽象为对象实现二者之间的松耦合。这就是命令模式(Command Pattern)。

     将来自客户端的请求传入一个对象,从而使你可用不同的请求对客户进行参数化。用于“行为请求者”与“行为实现者”解耦,可实现二者之间的松耦合,以便适应变化。分离变化与不变的因素。

   在面向对象的程序设计中,一个对象调用另一个对象,一般情况下的调用过程是:创建目标对象实例;设置调用参数;调用目标对象的方法。

但在有些情况下有必要使用一个专门的类对这种调用过程加以封装,我们把这种专门的类称作command类。


特点
1)、command模式将调用操作的对象和实现该操作的对象解耦
2)、可以将多个命令装配成一个复合命令,复合命令是Composite模式的一个实例
3)、增加新的command很容易,无需改变已有的类

应用场景:

我们来分析下命令模式的使用场景吧,一般情况下如下几类场景中使用命令模式会达到很好的效果:

      1、当一个应用程序调用者与多个目标对象之间存在调用关系时,并且目标对象之间的操作很类似的时候。

      2、例如当一个目标对象内部的方法调用太复杂,或者内部的方法需要协作才能完成对象的某个特点操作时。

      3、有时候调用者调用目标对象后,需要回调一些方法。

     命令模式是将行为请求者和行为实现者解耦合的方式。对命令进行封装,将命令和执行命令分隔开。请求的一方发出命令,要求执行某些操作,接受一方收到命令,执行这些操作的真正实现。请求的一方不必知道接受方的接口,以及如何被操作。 


    命令模式可以应用到很多场景,比如实现do/undo功能、实现导航功能。

posted @ 2015-03-30 21:23 abin 阅读(2159) | 评论 (2)编辑 收藏

ApplicationContext 是 BeanFactory 接口的子接口,它增强了 BeanFactory 的功能,处于 context 包下。很多时候, ApplicationContext 允许以声明式方式操作容器,无须手动创建。可利用如 ContextLoader 的支持类,在 Web 应用启动时自动创建 ApplicationContext。当然,也可以采用编程方式创建 ApplicationContext。

ApplicationContext包括BeanFactory的全部功能,因此建议优先使用ApplicationContext。除非对于某些内存非常关键的应用,才考虑使用 BeanFactory。

spring为ApplicationContext提供的3种实现分别为:

1、  ClassPathXmlApplicationContext:利用类路径的XML文件来载入Bean定义的信息

[1]  ApplicationContext ctx = new ClassPathXmlApplicationContext("bean.xml");

[2]  String[] locations = {"bean1.xml", "bean2.xml", "bean3.xml"};

ApplicationContext ctx = new ClassPathXmlApplication(locations);

2、 FileSystemXmlApplicationContext:利用文件系统中的XMl文件来载入Bean

定义的信息

[1]  ApplicationContext ctx = new FileSystemXmlApplicationContext("bean.xml"); //加载单个配置文件

[2]  String[] locations = {"bean1.xml", "bean2.xml", "bean3.xml"};

 ApplicationContext ctx = new FileSystemXmlApplicationContext(locations );

//加载多个配置文件

[3]  ApplicationContext ctx =new FileSystemXmlApplicationContext("D:/project/bean.xml");

//根据具体路径加载

3、 XmlWebApplicationContext:从Web系统中的XML文件来载入Bean定义的信息。

 ServletContext servletContext = request.getSession().getServletContext();    

 ApplicationContext ctx = WebApplicationContextUtils.getWebApplicationContext(servletContext);

 

 

配置WebApplicationContext的两种方法:

(1)        利用Listener接口来实现

<listener>

       <listener-class>

org.springframework.web.context.ContextLoaderListener

</listener-class>

</listener>

<context-param>

       <param-name>contextConfigLocation</param-name>

       <param-value>classpath:applicationContext</param-value>

</context-param>

(2)        利用Servlet接口来实现

<context-param>

<param-name>contextConfigLocation</param-name>

<param-value>classpath:applicationContext</param-value>

</context-param>

<Servlet>

       <servlet-name>context</servlet-name>

       <servlet-class>

           org.springframework.web.context.ContextLoaderServlet

       </servlet-class>

</servlet>

posted @ 2015-03-27 14:53 abin 阅读(407) | 评论 (0)编辑 收藏

装饰者模式(Decorator Pattern),是在不必改变原类文件和使用继承的情况下,动态的扩展一个对象的功能。它是通过创建一个包装对象,也就是装饰来包裹真实的对象。
使用装饰者模式的时候需要注意一下几点内容:
(1)装饰对象和真实对象有相同的接口。这样客户端对象就可以以和真实对象相同的方式和装饰对象交互。
(2)装饰对象包含一个真实对象的引用。
(3)装饰对象接受所有的来自客户端的请求,它把这些请求转发给真实的对象。
(4)装饰对象可以在转发这些请求以前或以后增加一些附加功能。这样就确保了在运行时,不用修改给定对象的结构就可以在外部增加附加的功能。在面向对象的设计中,通常是通过继承来实现对给定类的功能扩展。然而,装饰者模式,不需要子类可以在应用程序运行时,动态扩展功能,更加方便、灵活。

适用装饰者模式场合:
1.当我们需要为某个现有的对象,动态的增加一个新的功能或职责时,可以考虑使用装饰模式。
2.当某个对象的职责经常发生变化或者经常需要动态的增加职责,避免为了适应这样的变化,而增加继承子类扩展的方式,因为这种方式会造成子类膨胀的速度过快,难以控制。

推荐你一本设计模式方面的优秀书籍:郑阿奇 主编的《软件秘笈-设计模式那点事》。里面讲解很到位,实例通俗易懂,看了收获很大!

posted @ 2015-03-27 00:11 abin 阅读(908) | 评论 (0)编辑 收藏

二分查找的基本思想是将n个元素分成大致相等的两部分,去a[n/2]与x做比较,如果x=a[n/2],则找到x,算法中止;如果x<a[n/2],则只要在数组a的左半部分继续搜索x,如果x>a[n/2],则只要在数组a的右半部搜索x.

时间复杂度无非就是while循环的次数!

总共有n个元素,

渐渐跟下去就是n,n/2,n/4,....n/2^k,其中k就是循环的次数

由于你n/2^k取整后>=1

即令n/2^k=1

可得k=log2n,(是以2为底,n的对数)

所以时间复杂度可以表示O()=O(logn)

posted @ 2015-03-26 16:30 abin 阅读(641) | 评论 (0)编辑 收藏

Static 静态:这里主要记录的是静态程序块和静态方法

如果有些代码必须在项目启动的时候就执行,就需要使用静态代码块,这种代码是主动执行的;需要在项目启动的时候就初始化但是不执行,在不创建对象的情况下,可以供其他程序调用,而在调用的时候才执行,这需要使用静态方法,这种代码是被动执行的. 静态方法在类加载的时候 就已经加载 可以用类名直接调用。

静态代码块和静态方法的区别是:

静态代码块是自动执行的;

静态方法是被调用的时候才执行的.

静态方法:如果我们在程序编写的时候需要一个不实例化对象就可以调用的方法,我们就可以使用静态方法,具体实现是在方法前面加上static,如下:

public static void method(){}

在使用静态方法的时候需要注意一下几个方面:

在静态方法里只能直接调用同类中其他的静态成员(包括变量和方法),而不能直接访问类中的非静态成员。这是因为,对于非静态的方法和变量,需要先创建类的实例对象后才可使用,而静态方法在使用前不用创建任何对象。(备注:静态变量是属于整个类的变量而不是属于某个对象的)

静态方法不能以任何方式引用this和super关键字,因为静态方法在使用前不用创建任何实例对象,当静态方法调用时,this所引用的对象根本没有产生。

静态程序块:当一个类需要在被载入时就执行一段程序,这样可以使用静态程序块。

public class DemoClass {

private DemoClass(){}

public static DemoClass _instance;

static{

if(null == _instance ){

_instance = new DemoClass();

}

}

public static DemoClass getInstance(){

return _instance;

}

}

这样的程序在类被加载的时候就执行了static中的代码。

Ps:java中类的装载步骤:

在Java中,类装载器把一个类装入Java虚拟机中,要经过三个步骤来完成:装载、链接和初始化,其中链接又可以分成校验、准备和解析三步,除了解析外,其它步骤是严格按照顺序完成的,各个步骤的主要工作如下:

所谓装载就是寻找一个类或是一个接口的二进制形式并用该二进制形式来构造代表这个类或是这个接口的class对象的过程。其中类或接口的名称是给定了的。

装载:查找和导入类或接口的二进制数据;

链接:执行下面的校验、准备和解析步骤,其中解析步骤是可以选择的;

校验:检查导入类或接口的二进制数据的正确性;

准备:给类的静态变量分配并初始化存储空间;

解析:将符号引用转成直接引用;

初始化:激活类的静态变量的初始化Java代码和静态Java代码块

posted @ 2015-03-25 15:24 abin 阅读(337) | 评论 (0)编辑 收藏

replication的限制:一旦数据库过于庞大,尤其是当写入过于频繁,很难由一台主机支撑的时候,我们还是会面临到扩展瓶颈。数据切分(sharding):通过某种特定的条件,将我们存放在同一个数据库中的数据分散存放到多个数据库(主机)上面,以达到分散单台设备负载的效果。。数据的切分同时还可以提高系统的总体可用性,因为单台设备Crash之后,只有总体数据的某部分不可用,而不是所有的数据。

数据的切分(Sharding)模式

一种是按照不同的表(或者Schema)来切分到不同的数据库(主机)之上,这种切可以称之为数据的垂直(纵向)切分;另外一种则是根据表中的数据的逻辑关系,将同一个表中的数据按照某种条件拆分到多台数据库(主机)上面,这种切分称之为数据的水平(横向)切分。

垂直切分:

一个架构设计较好的应用系统,其总体功能肯定是由很多个功能模块所组成的,而每一个功能模块所需要的数据对应到数据库中就是一个或者多个表。而在架构设计中,各个功能模块相互之间的交互点越统一越少,系统的耦合度就越低,系统各个模块的维护性以及扩展性也就越好。这样的系统,实现数据的垂直切分也就越容易。

一般来说,如果是一个负载相对不是很大的系统,而且表关联又非常的频繁,那可能数据库让步,将几个相关模块合并在一起减少应用程序的工作的方案可以减少较多的工作量,这是一个可行的方案。一个垂直拆分的例子:

1.用户模块表:user,user_profile,user_group,user_photo_album
2.群组讨论表:groups,group_message,group_message_content,top_message
3.相册相关表:photo,photo_album,photo_album_relation,photo_comment
4.事件信息表:event


  • 群组讨论模块和用户模块之间主要存在通过用户或者是群组关系来进行关联。一般关联的时候都会是通过用户的id或者nick_name以及group的id来进行关联,通过模块之间的接口实现不会带来太多麻烦;
  • 相册模块仅仅与用户模块存在通过用户的关联。这两个模块之间的关联基本就有通过用户id关联的内容,简单清晰,接口明确;
  • 事件模块与各个模块可能都有关联,但是都只关注其各个模块中对象的ID信息,同样可以做到很容易分拆。

垂直切分的优点

  • 数据库的拆分简单明了,拆分规则明确;
  • 应用程序模块清晰明确,整合容易;
  • 数据维护方便易行,容易定位;

垂直切分的缺点


  • 部分表关联无法在数据库级别完成,需要在程序中完成
  • 对于访问极其频繁且数据量超大的表仍然存在性能瓶颈,不一定能满足要求;
  • 事务处理相对更为复杂
  • 切分达到一定程度之后,扩展性会遇到限制;
  • 过读切分可能会带来系统过渡复杂而难以维护。

水平切分

将某个访问极其频繁的表再按照某个字段的某种规则来分散到多个表之中,每个表中包含一部分数据。

对于上面的例子:所有数据都是和用户关联的,那么我们就可以根据用户来进行水平拆分,将不同用户的数据切分到不同的数据库中。

现在互联网非常火爆的Web2.0类型的网站,基本上大部分数据都能够通过会员用户信息关联上,可能很多核心表都非常适合通过会员ID来进行数据的水平切分。而像论坛社区讨论系统,就更容易切分了,非常容易按照论坛编号来进行数据的水平切分。切分之后基本上不会出现各个库之间的交互。

水平切分的优点


  • 表关联基本能够在数据库端全部完成;
  • 不会存在某些超大型数据量和高负载的表遇到瓶颈的问题;
  • 应用程序端整体架构改动相对较少;
  • 事务处理相对简单;
  • 只要切分规则能够定义好,基本上较难遇到扩展性限制;

水平切分的缺点

  • 切分规则相对更为复杂,很难抽象出一个能够满足整个数据库的切分规则;
  • 后期数据的维护难度有所增加,人为手工定位数据更困难;
  • 应用系统各模块耦合度较高,可能会对后面数据的迁移拆分造成一定的困难。

两种切分结合用:

一般来说,我们数据库中的所有表很难通过某一个(或少数几个)字段全部关联起来,所以很难简单的仅仅通过数据的水平切分来解决所有问题。而垂直切分也只能解决部分问题,对于那些负载非常高的系统,即使仅仅只是单个表都无法通过单台数据库主机来承担其负载。我们必须结合“垂直”和“水平”两种切分方式同时使用

每一个应用系统的负载都是一步一步增长上来的,在开始遇到性能瓶颈的时候,大多数架构师和DBA都会选择先进行数据的垂直拆分,因为这样的成本最先,最符合这个时期所追求的最大投入产出比。然而,随着业务的不断扩张,系统负载的持续增长,在系统稳定一段时期之后,经过了垂直拆分之后的数据库集群可能又再一次不堪重负,遇到了性能瓶颈。

如果我们再一次像最开始那样继续细分模块,进行数据的垂直切分,那我们可能在不久的将来,又会遇到现在所面对的同样的问题。而且随着模块的不断的细化,应用系统的架构也会越来越复杂,整个系统很可能会出现失控的局面。

这时候我们就必须要通过数据的水平切分的优势,来解决这里所遇到的问题。而且,我们完全不必要在使用数据水平切分的时候,推倒之前进行数据垂直切分的成果,而是在其基础上利用水平切分的优势来避开垂直切分的弊端,解决系统复杂性不断扩大的问题。而水平拆分的弊端(规则难以统一)也已经被之前的垂直切分解决掉了,让水平拆分可以进行的得心应手。

示例数据库:

假设在最开始,我们进行了数据的垂直切分,然而随着业务的不断增长,数据库系统遇到了瓶颈,我们选择重构数据库集群的架构。如何重构?考虑到之前已经做好了数据的垂直切分,而且模块结构清晰明确。而业务增长的势头越来越猛,即使现在进一步再次拆分模块,也坚持不了太久。

==>选择了在垂直切分的基础上再进行水平拆分。

==>在经历过垂直拆分后的各个数据库集群中的每一个都只有一个功能模块,而每个功能模块中的所有表基本上都会与某个字段进行关联。如用户模块全部都可以通过用户ID进行切分,群组讨论模块则都通过群组ID来切分,相册模块则根据相册ID来进切分,最后的事件通知信息表考虑到数据的时限性(仅仅只会访问最近某个事件段的信息),则考虑按时间来切分。

数据切分以及整合方案.

数据库中的数据在经过垂直和(或)水平切分被存放在不同的数据库主机之后,应用系统面临的最大问题就是如何来让这些数据源得到较好的整合,其中存在两种解决思路:

  • 在每个应用程序模块中配置管理自己需要的一个(或者多个)数据源,直接访问各个数据库,在模块内完成数据的整合;
  • 通过中间代理层来统一管理所有的数据源,后端数据库集群对前端应用程序透明;

第二种方案,虽然短期内需要付出的成本可能会相对更大一些,但是对整个系统的扩展性来说,是非常有帮助的。针对第二种方案,可以选择的方法和思路有:

1.利用MySQLProxy 实现数据切分及整合.

可用来监视、分析或者传输他们之间的通讯信息。他的灵活性允许你最大限度的使用它,目前具备的功能主要有连接路由,Query分析,Query过滤和修改,负载均衡,以及基本的HA机制等。MySQLProxy 本身并不具有上述所有的这些功能,而是提供了实现上述功能的基础。要实现这些功能,还需要通过我们自行编写LUA脚本来实现。

原理:MySQLProxy 实际上是在客户端请求与MySQLServer 之间建立了一个连接池。所有客户端请求都是发向MySQLProxy,然后经由MySQLProxy 进行相应的分析,判断出是读操作还是写操作,分发至对应的MySQLServer 上。对于多节点Slave集群,也可以起做到负载均衡的效果。

2.利用Amoeba实现数据切分及整合

Amoeba是一个基于Java开发的,专注于解决分布式数据库数据源整合Proxy程序的开源框架,Amoeba已经具有Query路由,Query过滤,读写分离,负载均衡以及HA机制等相关内容。Amoeba主要解决的以下几个问题:

  • 数据切分后复杂数据源整合;
  • 提供数据切分规则并降低数据切分规则给数据库带来的影响;
  • 降低数据库与客户端的连接数;
  • 读写分离路由;

AmoebaFor MySQL 主要是专门针对MySQL数据库的解决方案,前端应用程序请求的协议以及后端连接的数据源数据库都必须是MySQL。对于客户端的任何应用程序来说,AmoebaForMySQL 和一个MySQL数据库没有什么区别,任何使用MySQL协议的客户端请求,都可以被AmoebaFor MySQL 解析并进行相应的处理。

Proxy程序常用的功能如读写分离,负载均衡等配置都在amoeba.xml中进行。Amoeba已经支持了实现数据的垂直切分和水平切分的自动路由,路由规则可以在rule.xml进行设置。

3.利用HiveDB实现数据切分及整合


HiveDB同样是一个基于Java针对MySQL数据库的提供数据切分及整合的开源框架,只是目前的HiveDB仅仅支持数据的水平切分。主要解决大数据量下数据库的扩展性及数据的高性能访问问题,同时支持数据的冗余及基本的HA机制。

HiveDB的实现机制与MySQLProxy 和Amoeba有一定的差异,他并不是借助MySQL的Replication功能来实现数据的冗余,而是自行实现了数据冗余机制,而其底层主要是基于HibernateShards 来实现的数据切分工作。数据切分与整合中可能存在的问题

引入分布式事务的问题?

一旦数据进行切分被分别存放在多个MySQLServer中之后,不管我们的切分规则设计的多么的完美(实际上并不存在完美的切分规则),都可能造成之前的某些事务所涉及到的数据已经不在同一个MySQLServer 中了。

==>将一个跨多个数据库的分布式事务分拆成多个仅处于单个数据库上面的小事务,并通过应用程序来总控各个小事务。

跨节点Join的问题?


==>先从一个节点取出数据,然后根据这些数据,再到另一个表中取数据.
==>使用Federated存储引擎,问题是:乎如果远端的表结构发生了变更,本地的表定义信息是不会跟着发生相应变化的。

跨节点合并排序分页问题?

==>Join本身涉及到的多个表之间的数据读取一般都会存在一个顺序关系。但是排序分页就不太一样了,排序分页的数据源基本上可以说是一个表(或者一个结果集),本身并不存在一个顺序关系,所以在从多个数据源取数据的过程是完全可以并行的。这样,排序分页数据的取数效率我们可以做的比跨库Join更高,所以带来的性能损失相对的要更小。  
posted @ 2015-03-24 16:13 abin 阅读(857) | 评论 (0)编辑 收藏

前言

有人反馈之前几篇文章过于理论缺少实际操作细节,这篇文章就多一些可操作性的内容吧。

注:这篇文章是以 MySQL 为背景,很多内容同时适用于其他关系型数据库,需要有一些索引知识为基础。

 

优化目标

  1.减少 IO 次数

  IO永远是数据库最容易瓶颈的地方,这是由数据库的职责所决定的,大部分数据库操作中超过90%的时间都是 IO 操作所占用的,减少 IO 次数是 SQL 优化中需要第一优先考虑,当然,也是收效最明显的优化手段。

  2.降低 CPU 计算

  除了 IO 瓶颈之外,SQL优化中需要考虑的就是 CPU 运算量的优化了。order by, group by,distinct … 都是消耗 CPU 的大户(这些操作基本上都是 CPU 处理内存中的数据比较运算)。当我们的 IO 优化做到一定阶段之后,降低 CPU 计算也就成为了我们 SQL 优化的重要目标

 

优化方法

  改变 SQL 执行计划

  明确了优化目标之后,我们需要确定达到我们目标的方法。对于 SQL 语句来说,达到上述2个目标的方法其实只有一个,那就是改变 SQL 的执行计划,让他尽量“少走弯路”,尽量通过各种“捷径”来找到我们需要的数据,以达到 “减少 IO 次数” 和 “降低 CPU 计算” 的目标

 

常见误区

 

1.count(1)和count(primary_key) 优于 count(*)

  很多人为了统计记录条数,就使用 count(1) 和 count(primary_key) 而不是 count(*) ,他们认为这样性能更好,其实这是一个误区。对于有些场景,这样做可能性能会更差,应为数据库对 count(*) 计数操作做了一些特别的优化。

 

2.count(column) 和 count(*) 是一样的

  这个误区甚至在很多的资深工程师或者是 DBA 中都普遍存在,很多人都会认为这是理所当然的。实际上,count(column) 和 count(*) 是一个完全不一样的操作,所代表的意义也完全不一样。

  count(column) 是表示结果集中有多少个column字段不为空的记录

  count(*) 是表示整个结果集有多少条记录

 

3.select a,b from … 比 select a,b,c from … 可以让数据库访问更少的数据量

  这个误区主要存在于大量的开发人员中,主要原因是对数据库的存储原理不是太了解。

  实际上,大多数关系型数据库都是按照行(row)的方式存储,而数据存取操作都是以一个固定大小的IO单元(被称作 block 或者 page)为单位,一般为4KB,8KB… 大多数时候,每个IO单元中存储了多行,每行都是存储了该行的所有字段(lob等特殊类型字段除外)。

  所以,我们是取一个字段还是多个字段,实际上数据库在表中需要访问的数据量其实是一样的。

  当然,也有例外情况,那就是我们的这个查询在索引中就可以完成,也就是说当只取 a,b两个字段的时候,不需要回表,而c这个字段不在使用的索引中,需要回表取得其数据。在这样的情况下,二者的IO量会有较大差异。

 

4.order by 一定需要排序操作

  我们知道索引数据实际上是有序的,如果我们的需要的数据和某个索引的顺序一致,而且我们的查询又通过这个索引来执行,那么数据库一般会省略排序操作,而直接将数据返回,因为数据库知道数据已经满足我们的排序需求了。

  实际上,利用索引来优化有排序需求的 SQL,是一个非常重要的优化手段

  延伸阅读:MySQL ORDER BY 的实现分析,MySQL 中 GROUP BY 基本实现原理以及 MySQL DISTINCT 的基本实现原理这3篇文章中有更为深入的分析,尤其是第一篇

 

5.执行计划中有 filesort 就会进行磁盘文件排序

  有这个误区其实并不能怪我们,而是因为 MySQL 开发者在用词方面的问题。filesort 是我们在使用 explain 命令查看一条 SQL 的执行计划的时候可能会看到在 “Extra” 一列显示的信息。

  实际上,只要一条 SQL 语句需要进行排序操作,都会显示“Using filesort”,这并不表示就会有文件排序操作。

 

基本原则

1.尽量少 join

  MySQL 的优势在于简单,但这在某些方面其实也是其劣势。MySQL 优化器效率高,但是由于其统计信息的量有限,优化器工作过程出现偏差的可能性也就更多。对于复杂的多表 Join,一方面由于其优化器受限,再者在 Join 这方面所下的功夫还不够,所以性能表现离 Oracle 等关系型数据库前辈还是有一定距离。但如果是简单的单表查询,这一差距就会极小甚至在有些场景下要优于这些数据库前辈。

 

2.尽量少排序

  排序操作会消耗较多的 CPU 资源,所以减少排序可以在缓存命中率高等 IO 能力足够的场景下会较大影响 SQL 的响应时间。

  对于MySQL来说,减少排序有多种办法,比如:

  上面误区中提到的通过利用索引来排序的方式进行优化

  减少参与排序的记录条数

  非必要不对数据进行排序

  …

 

3.尽量避免 select *

  很多人看到这一点后觉得比较难理解,上面不是在误区中刚刚说 select 子句中字段的多少并不会影响到读取的数据吗?

  是的,大多数时候并不会影响到 IO 量,但是当我们还存在 order by 操作的时候,select 子句中的字段多少会在很大程度上影响到我们的排序效率,这一点可以通过我之前一篇介绍 MySQL ORDER BY 的实现分析的文章中有较为详细的介绍。

  此外,上面误区中不是也说了,只是大多数时候是不会影响到 IO 量,当我们的查询结果仅仅只需要在索引中就能找到的时候,还是会极大减少 IO 量的。

 

4.尽量用 join 代替子查询

  虽然 Join 性能并不佳,但是和 MySQL 的子查询比起来还是有非常大的性能优势。MySQL 的子查询执行计划一直存在较大的问题,虽然这个问题已经存在多年,但是到目前已经发布的所有稳定版本中都普遍存在,一直没有太大改善。虽然官方也在很早就承认这一问题,并且承诺尽快解决,但是至少到目前为止我们还没有看到哪一个版本较好的解决了这一问题。

 

5.尽量少 or

  当 where 子句中存在多个条件以“或”并存的时候,MySQL 的优化器并没有很好的解决其执行计划优化问题,再加上 MySQL 特有的 SQL 与 Storage 分层架构方式,造成了其性能比较低下,很多时候使用 union all 或者是union(必要的时候)的方式来代替“or”会得到更好的效果。

 

6.尽量用 union all 代替 union

  union 和 union all 的差异主要是前者需要将两个(或者多个)结果集合并后再进行唯一性过滤操作,这就会涉及到排序,增加大量的 CPU 运算,加大资源消耗及延迟。所以当我们可以确认不可能出现重复结果集或者不在乎重复结果集的时候,尽量使用 union all 而不是 union。

 

7.尽量早过滤

  这一优化策略其实最常见于索引的优化设计中(将过滤性更好的字段放得更靠前)。

  在 SQL 编写中同样可以使用这一原则来优化一些 Join 的 SQL。比如我们在多个表进行分页数据查询的时候,我们最好是能够在一个表上先过滤好数据分好页,然后再用分好页的结果集与另外的表 Join,这样可以尽可能多的减少不必要的 IO 操作,大大节省 IO 操作所消耗的时间。

 

8.避免类型转换

  这里所说的“类型转换”是指 where 子句中出现 column 字段的类型和传入的参数类型不一致的时候发生的类型转换:

  人为在column_name 上通过转换函数进行转换

  直接导致 MySQL(实际上其他数据库也会有同样的问题)无法使用索引,如果非要转换,应该在传入的参数上进行转换

  由数据库自己进行转换

  如果我们传入的数据类型和字段类型不一致,同时我们又没有做任何类型转换处理,MySQL 可能会自己对我们的数据进行类型转换操作,也可能不进行处理而交由存储引擎去处理,这样一来,就会出现索引无法使用的情况而造成执行计划问题。

 

9.优先优化高并发的 SQL,而不是执行频率低某些“大”SQL

  对于破坏性来说,高并发的 SQL 总是会比低频率的来得大,因为高并发的 SQL 一旦出现问题,甚至不会给我们任何喘息的机会就会将系统压跨。而对于一些虽然需要消耗大量 IO 而且响应很慢的 SQL,由于频率低,即使遇到,最多就是让整个系统响应慢一点,但至少可能撑一会儿,让我们有缓冲的机会。

 

10.从全局出发优化,而不是片面调整

  SQL 优化不能是单独针对某一个进行,而应充分考虑系统中所有的 SQL,尤其是在通过调整索引优化 SQL 的执行计划的时候,千万不能顾此失彼,因小失大。

 

11.尽可能对每一条运行在数据库中的SQL进行 explain

  优化 SQL,需要做到心中有数,知道 SQL 的执行计划才能判断是否有优化余地,才能判断是否存在执行计划问题。在对数据库中运行的 SQL 进行了一段时间的优化之后,很明显的问题 SQL 可能已经很少了,大多都需要去发掘,这时候就需要进行大量的 explain 操作收集执行计划,并判断是否需要进行优化。

 

原文地址:http://isky000.com/database/mysql-performance-tuning-sql

posted @ 2015-03-24 15:51 abin 阅读(374) | 评论 (0)编辑 收藏

一,单一Bean

  • 装载

1. 实例化; 
2. 设置属性值; 
3. 如果实现了BeanNameAware接口,调用setBeanName设置Bean的ID或者Name; 
4. 如果实现BeanFactoryAware接口,调用setBeanFactory 设置BeanFactory; 
5. 如果实现ApplicationContextAware,调用setApplicationContext设置ApplicationContext 
6. 调用BeanPostProcessor的预先初始化方法; 
7. 调用InitializingBean的afterPropertiesSet()方法; 
8. 调用定制init-method方法; 
9. 调用BeanPostProcessor的后初始化方法;

  • spring容器关闭

1. 调用DisposableBean的destroy(); 
2. 调用定制的destroy-method方法;

 

二,多个Bean的先后顺序

  • 优先加载BeanPostProcessor的实现Bean
  • 按Bean文件和Bean的定义顺序按bean的装载顺序(即使加载多个spring文件时存在id覆盖)
  • “设置属性值”(第2步)时,遇到ref,则在“实例化”(第1步)之后先加载ref的id对应的bean
  • AbstractFactoryBean的子类,在第6步之后,会调用createInstance方法,之后会调用getObjectType方法
  • BeanFactoryUtils类也会改变Bean的加载顺序
posted @ 2015-03-23 22:10 abin 阅读(634) | 评论 (0)编辑 收藏

仅列出标题
共50页: First 上一页 2 3 4 5 6 7 8 9 10 下一页 Last