java运行的程序占用哪些资源如何优化
引子:
也许你听过这样一句话,java程序是很吃内存的.
仔细思考这句话为什么呢?
首先我们分析,java程序的运行需要什么资源?如何优化呢?
1.java程序的运行需要什么资源?
答:占据着CPU和内存空间
2.如何优化?
优化一个很显著的感官现象就是加快速度。
2.1 java代码优化
1. 避免在循环条件中使用复杂表达式
在不做编译优化的情况下,在循环中,循环条件会被反复计算,如果不使用复杂表达式,而使循环条件值不变的话,程序将会运行的更快。
例子:
class cel {
void method (String str) {
for (int i = 0; i < str.size (); i++) // violation
; // ...
}
}
更class cel_fixed {
void method (String str) {
int size = str.size ()
for (int i = 0; i < size; i++)
; // …
}
} 在多重循环中,如果有可能,尽量将最长的循环放在最内层,最短的循环放在最外层,以减少循环层间的变换次数。
2. 尽量避免随意使用静态变量
要知道,当某个对象被定义为stataic变量所引用,那么gc通常是不会回收这个对象所占有的内存,如
Java代码
public class A{
static B b = new B();
}时静态变量b的生命周期与A类同步,如果A类不会卸载,那么b对象会常驻内存,直到程序终止。
尽量避免过多过常的创建Java对象
尽量避免在经常调用的方法,循环中new对象,由于系统不仅要花费时间来创建对象,而且还要花时间对这些对象进行垃圾回收和处理,在我们可以控制的范围内,最大限度的重用对象,最好能用基本的数据类型或数组来替代对象。尽量使用基本数据类型代替对象
String str = “hello”;
上面这种方式会创建一个”hello”字符串,而且JVM的字符缓存池还会缓存这个字符串;
String str = new String(“hello”);
此时程序除创建字符串外,str所引用的String对象底层还包含一个char[]数组,这个char[]数组依次存放了h,e,l,l,o- 尽量避免不必要的创建
如
A a = new A();
if(i==1){list.add(a);}
应该改为
if(i==1){
A a = new A();
list.add(a);} - 尽量在finally块中释放资源
程序中使用到的资源应当被释放,以避免资源泄漏。这最好在finally块中去做。不管程序执行的结果如何,finally块总是会执行的,以确保资源的正确关闭。 - 尽量缓存经常使用的对象
尽可能将经常使用的对象进行缓存,可以使用数组,或HashMap的容器来进行缓存,但这种方式可能导致系统占用过多的缓存,性能下降,推荐可以使用一些第三方的开源工具,如EhCache,Oscache或者使用freemakeer进行缓存,他们基本都实现了FIFO/FLU等缓存算法。 - 如果if判断中多个条件用’||’或者’&&’连接,请将出现频率最高的条件放在表达式最前面。
这个小技巧往往能有效的提高程序的性能,尤其是当if判断放在循环体里面时,效果更明显。
9.使用池的概念:数据库连接池和线程池 - 最好通过Class.forname() 动态的装载类
- 尽量使用移位来代替’a/b’的操作
“/”是一个代价很高的操作,使用移位的操作将会更快和更有效
如
int num = a / 4;
int num = a / 8;
应该改为
int num = a 》 2;
int num = a 》 3; - 尽量使用局部变量
调用方法时传递的参数以及在调用中创建的临时变量都保存在栈(Stack)中,速度较快。其他变量,如静态变量、实例变量等,都在堆(Heap)中创建,速度较慢。 - 尽量使用StringBuilder和StringBuffer进行字符串连接
- 尽量早释放无用对象的引用
大部分时,方法局部引用变量所引用的对象 会随着方法结束而变成垃圾,因此,大部分时候程序无需将局部,引用变量显式设为null.
例如:
Java代码
Public void test(){
Object obj = new Object();
……
Obj=null;
}
上面这个就没必要了,随着方法test()的执行完成,程序中obj引用变量的作用域就结束了。但是如果是改成下面:
Java代码
Public void test(){
Object obj = new Object();
……
Obj=null;
//执行耗时,耗内存操作;或调用耗时,耗内存的方法
……
}
这时候就有必要将obj赋值为null,可以尽早的释放对Object对象的引用。 尽量使用System.arraycopy ()代替通过来循环复制数组
System.arraycopy() 要比通过循环来复制数组快的多。详解:http://blog.csdn.net/ochangwen/article/details/50587937慎用异常
当创建一个异常时,需要收集一个栈跟踪(stack track),这个栈跟踪用于描述异常是在何处创建的。构建这些栈跟踪时需要为运行时栈做一份快照,正是这一部分开销很大。当需要创建一个 Exception 时,JVM 不得不说:先别动,我想就您现在的样子存一份快照,所以暂时停止入栈和出栈操作。栈跟踪不只包含运行时栈中的一两个元素,而是包含这个栈中的每一个元素。
如 果您创建一个 Exception ,就得付出代价。好在捕获异常开销不大,因此可以使用 try-catch 将核心内容包起来。从技术上讲,您甚至可以随意地抛出异常,而不用花费很大的代价。招致性能损失的并不是 throw 操作–尽管在没有预先创建异常的情况下就抛出异常是有点不寻常。真正要花代价的是创建异常。幸运的是,好的编程习惯已教会我们,不应该不管三七二十一就 抛出异常。异常是为异常的情况而设计的,使用时也应该牢记这一原则。(1)用Boolean.valueOf(boolean b)代替new Boolean()
包装类的内存占用是很恐怖的,它是基本类型内存占用的N倍(N>2),同时new一个对象也是性能的消耗。
我们再看看JDK对于Boolean.valueOf(boolean b)的实现:
Boolean类提供了两个常量:
Java代码
public static final Boolean TRUE = new Boolean(true);
public static final Boolean FALSE = new Boolean(false);而valueOf(boolean b)的内部实现是:
Java代码
return (b ? TRUE : FALSE);
因此用Boolean.valueOf(boolean b)代替new Boolean()既能节省空间,又能提高性能。(2) 用Integer.valueOf(int i)代替new Integer()
和Boolean类似,java开发中使用Integer封装int的场合也非常多,并且通常用int表示的数值都非常小。SUN SDK中对Integer的实例化进行了优化,Integer类缓存了-128到127这256个状态的Integer,如果使用 Integer.valueOf(int i),传入的int范围正好在此内,就返回静态实例。这样如果我们使用Integer.valueOf代替new Integer的话也将大大降低内存的占用。
17.当做数组拷贝操作时,采用System.arraycopy()方法完成拷贝操作要比采用循环的办法完成数组拷贝操作效率高
18. 如果预知长度,就设置ArrayList的长度。
其他办法:
http://www.jb51.net/article/62885.htm
http://developer.51cto.com/art/201511/496263.htm
http://blog.csdn.net/liushuijinger/article/details/41546347
http://www.cnblogs.com/feichexia/p/3495554.html
就这章给出相关代码(以数据库为例)
//原始的jdbc连接方式
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import com.mysql.jdbc.Driver;
//最原始的jdbc连接数据库
public class JavaDemo2 {
public static void main(String[] args) throws SQLException {
// 1.注册驱动
DriverManager.registerDriver(new Driver());
// 2.获取连接对象
Connection con = DriverManager.getConnection(
"jdbc:mysql://localhost:3306/Demo", "root", "root");
// 3.通过连接对象获取操作sql语句Statement
Statement st = con.createStatement();
// 4.操作sql语句
String sql = "select * from users";
// 操作sql语句(select语句),会得到一个ResultSet结果集
ResultSet rs = st.executeQuery(sql);
// 5.遍历结果集
while(rs.next()){
int id=rs.getInt("id");
String username=rs.getString("username");
String password=rs.getString("password");
String email=rs.getString("email");
System.out.println(id+" "+username+" "+password+" "+email);
}
//6.释放资源
rs.close();
st.close();
con.close();
}
}
//改进的连接方式
//1.我们用反射来获取驱动,好处有两个1.只加载一次,装入一个对象2.降低耦合不依赖于驱动
//con以上的代码用工具类集合写下来
//使用c3p0进行管理当然需要导入c3p0的jar包
package com.just4s;
//c3p0连接池
import java.beans.PropertyVetoException;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import javax.sql.DataSource;
import org.junit.Test;
import com.mchange.v2.c3p0.ComboPooledDataSource;
//c3p0连接池
public class JavaDemo6 {
//
@Test
public void test1() throws PropertyVetoException, SQLException {
ComboPooledDataSource cpds = new ComboPooledDataSource();
// 得到一个Connection
Connection con = cpds.getConnection();
ResultSet rs = con.createStatement().executeQuery(
"select * from users");
while (rs.next()) {
int id = rs.getInt("id");
String username = rs.getString("username");
String password = rs.getString("password");
String email = rs.getString("email");
System.out.println(id + " " + username + " " + password + " "
+ email);
}
rs.close();
con.close(); // 将Connection对象重新装入到连接池.
}
}
package com.just4s.Utils;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ResourceBundle;
//使用配置文件
public class JdbcUtils1 {
private static final String DRIVERCLASS;
private static final String URL;
private static final String USERNAME;
private static final String PASSWORD;
static {
DRIVERCLASS = ResourceBundle.getBundle("jdbc").getString("driverClass");
URL = ResourceBundle.getBundle("jdbc").getString("url");
USERNAME = ResourceBundle.getBundle("jdbc").getString("username");
PASSWORD = ResourceBundle.getBundle("jdbc").getString("password");
}
static {
try {
// 将加载驱动操作,放置在静态代码块中.这样就保证了只加载一次.
Class.forName(DRIVERCLASS);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
public static Connection getConnection() throws SQLException {
// 2.获取连接
Connection con = DriverManager.getConnection(URL, USERNAME, PASSWORD);
return con;
}
//关闭操作
public static void closeConnection(Connection con) throws SQLException{
if(con!=null){
con.close();
}
}
public static void closeStatement(Statement st) throws SQLException{
if(st!=null){
st.close();
}
}
public static void closeResultSet(ResultSet rs) throws SQLException{
if(rs!=null){
rs.close();
}
}
}
package com.just4s.Utils;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ResourceBundle;
//使用配置文件
public class JdbcUtils1 {
private static final String DRIVERCLASS;
private static final String URL;
private static final String USERNAME;
private static final String PASSWORD;
static {
DRIVERCLASS = ResourceBundle.getBundle("jdbc").getString("driverClass");
URL = ResourceBundle.getBundle("jdbc").getString("url");
USERNAME = ResourceBundle.getBundle("jdbc").getString("username");
PASSWORD = ResourceBundle.getBundle("jdbc").getString("password");
}
static {
try {
// 将加载驱动操作,放置在静态代码块中.这样就保证了只加载一次.
Class.forName(DRIVERCLASS);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
public static Connection getConnection() throws SQLException {
// 2.获取连接
Connection con = DriverManager.getConnection(URL, USERNAME, PASSWORD);
return con;
}
//关闭操作
public static void closeConnection(Connection con) throws SQLException{
if(con!=null){
con.close();
}
}
public static void closeStatement(Statement st) throws SQLException{
if(st!=null){
st.close();
}
}
public static void closeResultSet(ResultSet rs) throws SQLException{
if(rs!=null){
rs.close();
}
}
}
driverClass=com.mysql.jdbc.Driver
url=jdbc\:mysql\:///Demo
username=root
password=root
#driverClass=oracle.jdbc.driver.OracleDriver
#url=jdbc:oracle:thin:@localhost:1521:XE
#username=system
#password=system
2.2 javaweb优化策略:
简单地来看一个浏览器用户访问的流程: 浏览器->服务器->返回结果显示
这么简单地看,可能想得到的优化手段很少,但是细分开来看每一个步骤:
1 浏览器发起一个请求,如果本地有缓存会请求本地缓存文件,没有缓存会请求服务器。所以这里就有一个优化点:需要把常用的css和js文件独立成独立的静态文件,一次加载以后,后面直接加载本地缓存。另外IE浏览器内核在请求图片下载时会限制一次只能同时从同一个域名下载两个文件,这里又有优化点,分散图片存储的域名。使用静态文件,减少计算的同时增加本地缓存的使用,减少请求。静态化是常见的一种优化手段。
2 浏览器真实发起请求服务器时,首先被请求到的是服务器的操作系统层,那么服务器的操作系统对外界连接的响应能力,就是你需要了解的东西了。比如linux的内核参数的调整如何影响最大连接数,简单的一个例子就是在一个默认最大文件句柄数只有1024的服务器上,超过这个压力的时候,你如何优化你的程序,也都没有意义。入口只有那么窄,你得把口给扩开。熟悉服务器的性能,调优系统内核也是一个必要的手段。
3 系统层再把连接交给你的server做处理的时候,server的配置这个时候也相当重要。比如apache的最大连接数,tomcat的最大连接数。对server的配置调优很影响性能。比如tomcat在处理静态文件上的能力比apache要差很多,所以在apache+tomcat的负载均衡就能很好地进行动静请求的分离,提高响应速度。又比如tomcat新版本里的NIO技术又比普通IO性能好上不少。对server的了解,要保持跟踪最新动态。
4 server再把数据交给你的程序处理的时候,就到了考验你编程能力的时候了。你得对你的程序的执行效率非常清楚。必须保证每个响应都在尽量短的时间内执行成功。还有比较常见的一些对不常更新的数据使用内存缓存来加快访问。内存永远是最快的。这方面的优化也有非常非常多的事情可以去做,而且跟你的编程息息相关。
5 程序处理的时候,数据库连接池的使用,连接池大小的配置,连接池性能的优化,sql语句的优化,等等都可能影响你的程序的效率,这些地方永远是值得关注的。当然,优秀的算法在这个地方是少不了的。一个好的业务逻辑设计,可能极大提升你的程序性能。对数据库操作的调优也是一个永远的话题。
6 数据传递到数据库进行保存和查询的时候,你就必须对你的数据库的使用有所了解,知道数据库本身的哪些配置可以优化从而带来性能的提升。一个简单的例子就是在内存足够大的时候,增大mysql的内存缓存就可以极大提升它的响应速度。
7 现在server把数据返回给用户了,那么返回的数据的大小又同样影响着结果的显示速度。尽量减小数据的大小,比如开启apache的gzip就能极大压缩常见的静态文件,可以保证用户更快完出数据的下载,同时节省你的服务器使用带宽,老板一定会很高兴的。
8 ajax技术也是在减少大请求,使用更小的局部数据更新来代替整个页面的刷新,加快用户的响应速度,结合静态化能完美改善性能。
一些细节:
1.:禁止servlet和JSP 自动重载(auto-reloading) Servlet/JSP提供了一个实用的技术,即自动重载技术,它为开发人员提供了一个好的开发环境,当你改变servlet和JSP页面后而不必重启应用服务器。然而,这种技术在产品运行阶段对系统的资源是一个极大的损耗,因为它会给JSP引擎的类装载器(classloader)带来极大的负担。因此关闭自动重载功能对系统性能的提升是一个极大的帮助。
server.xml中有个选项autoDeploy,改为false,
再看看context中reloadable是否设为true了(应该设置为false,默认是false)。
2.: 不要滥用HttpSession 在很多应用中,我们的程序需要保持客户端的状态,以便页面之间可以相互联系。但不幸的是由于HTTP具有天生无状态性,从而无法保存客户端的状态。因此一般的应用服务器都提供了session来保存客户的状态。在JSP应用服务器中,是通过HttpSession对像来实现session的功能的,但在方便的同时,它也给系统带来了不小的负担。因为每当你获得或更新session时,系统者要对它进行费时的序列化操作。你可以通过对HttpSession的以下几种处理方式来提升系统的性能: 如果没有必要,就应该关闭JSP页面中对HttpSession的缺省设置: 如果你没有明确指定的话,每个JSP页面都会缺省地创建一个HttpSession。如果你的JSP中不需要使用session的话,那可以通过如下的JSP页面指示符来禁止它:<%@ page session=”false”%> 不要在HttpSession中存放大的数据对像:如果你在HttpSession中存放大的数据对像的话,每当对它进行读写时,应用服务器都将对其进行序列化,从而增加了系统的额外负担。你在HttpSession中存放的数据对像越大,那系统的性能就下降得越快。 当你不需要HttpSession时,尽快地释放它:当你不再需要session时,你可以通过调用HttpSession.invalidate()方法来释放它。 尽量将session的超时时间设得短一点:在JSP应用服务器中,有一个缺省的session的超时时间。当客户在这个时间之后没有进行任何操作的话,系统会将相关的session自动从内存中释放。超时时间设得越大,系统的性能就会越低,因此最好的方法就是尽量使得它的值保持在一个较低的水平。
3.: 将页面输出进行压缩 压缩是解决数据冗余的一个好的方法,特别是在网络带宽不够发达的今天。有的浏览器支持gzip(GNU zip)进行来对HTML文件进行压缩,这种方法可以戏剧性地减少HTML文件的下载时间。因此,如果你将servlet或JSP页面生成的HTML页面进行压缩的话,那用户就会觉得页面浏览速度会非常快。但不幸的是,不是所有的浏览器都支持gzip压缩,但你可以通过在你的程序中检查客户的浏览器是否支持它。下面就是关于这种方法实现的一个代码片段:public void doGet(HttpServletRequest request, HttpServletResponse response)throws IOException, ServletException{ OutputStream out = null String encoding = request.getHeader(“Accept-Encoding”); if (encoding != null && encoding.indexOf(“gzip”) != -1) { request.setHeader(“Content-Encoding” , “gzip”); out = new GZIPOutputStream(request.getOutputStream()); } else if (encoding != null && encoding.indexOf(“compress”) != -1) { request.setHeader(“Content-Encoding” , “compress”); out = new ZIPOutputStream(request.getOutputStream()); } else { out = request.getOutputStream(); } …… ……}
4.: 使用线程池 应用服务器缺省地为每个不同的客户端请求创建一个线程进行处理,并为它们分派service()方法,当service()方法调用完成后,与之相应的线程也随之撤消。由于创建和撤消线程会耗费一定的系统资源,这种缺省模式降低了系统的性能。但所幸的是我们可以通过创建一个线程池来改变这种状况。另外,我们还要为这个线程池设置一个最小线程数和一个最大线程数。在应用服务器启动时,它会创建数量等于最小线程数的一个线程池,当客户有请求时,相应地从池从取出一个线程来进行处理,当处理完成后,再将线程重新放入到池中。如果池中的线程不够地话,系统会自动地增加池中线程的数量,但总量不能超过最大线程数。通过使用线程池,当客户端请求急剧增加时,系统的负载就会呈现的平滑的上升曲线,从而提高的系统的可伸缩性。
6.ServletOutputStream 与 PrintWriter的权衡:使用PrintWriter可能会带来一些小的开销,因为它将所有的原始输出都转换为字符流来输出,因此如果使用它来作为页面输出的话,系统要负担一个转换过程。而使用ServletOutputStream作为页面输出的话就不存在一个问题,但它是以二进制进行输出的。因此在实际应用中要权衡两者的利弊。
等等。。。
2.3 数据库优化策略
1 通过查询缓冲提高查询速度
2 MySQL对查询的自动优化
3 基于索引的排序
4 不可达查询的检测
5 使用各种查询选择来提高性能
一、 通过查询缓冲提高查询速度
一 般我们使用SQL语句进行查询时,数据库服务器每次在收到客户端发来SQL后,都会执行这条SQL语句。但当在一定间隔内(如1分钟内),接到完全一样的 SQL语句,也同样执行它。虽然这样可以保证数据的实时性,但在大多数时候,数据并不要求完全的实时,也就是说可以有一定的延时。如果是这样的话,在短时 间内执行完全一样的SQL就有些得不偿失。
幸好MySQL为我们提供了查询缓冲的功能(只能在MySQL 4.0.1及以上版本使用查询缓冲)。我们可以通过查询缓冲在一定程度上提高查询性能。
我 们可以通过在MySQL安装目录中的my.ini文件设置查询缓冲。设置也非常简单,只需要将query_cache_type设为1即可。在设置了这个 属性后,MySQL在执行任何SELECT语句之前,都会在它的缓冲区中查询是否在相同的SELECT语句被执行过,如果有,并且执行结果没有过期,那么 就直接取查询结果返回给客户端。但在写SQL语句时注意,MySQL的查询缓冲是区分大小写的。如下列的两条SELECT语句:
SELECT * from TABLE1
SELECT * FROM TABLE1
上面的两条SQL语句对于查询缓冲是完全不同的SELECT。而且查询缓冲并不自动处理空格,因此,在写SQL语句时,应尽量减少空格的使用,尤其是在SQL首和尾的空格(因为,查询缓冲并不自动截取首尾空格)。
虽 然不设置查询缓冲,有时可能带来性能上的损失,但有一些SQL语句需要实时地查询数据,或者并不经常使用(可能一天就执行一两次)。这样就需要把缓冲关 了。当然,这可以通过设置query_cache_type的值来关闭查询缓冲,但这就将查询缓冲永久地关闭了。在MySQL 5.0中提供了一种可以临时关闭查询缓冲的方法:SQL_NO_CACHE。
SELECT SQL_NO_CACHE field1, field2 FROM TABLE1
以上的SQL语句由于使用了SQL_NO_CACHE,因此,不管这条SQL语句是否被执行过,服务器都不会在缓冲区中查找,每次都会执行它。
我们还可以将my.ini中的query_cache_type设成2,这样只有在使用了SQL_CACHE后,才使用查询缓冲。
SELECT SQL_CALHE * FROM TABLE1
二、MySQL对查询的自动优化
索引对于数据库是非常重要的。在查询时可以通过索引来提高性能。但有时使用索引反而会降低性能。我们可以看如下的SALES表:
CREATE TABLE SALES
(
ID INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
NAME VARCHAR(100) NOT NULL,
PRICE FLOAT NOT NULL,
SALE_COUNT INT NOT NULL,
SALE_DATE DATE NOT NULL,
PRIMARY KEY(ID),
INDEX (NAME),
INDEX (SALE_DATE)
)
假设这个表中保存了数百万条数据,而我们要查询商品号为1000的商品在2004年和2005年的平均价格。我们可以写如下的SQL语句:
SELECT AVG(PRICE) FROM SALES
WHERE ID = 1000 AND SALE_DATE BETWEEN ‘2004-01-01’ AND ‘2005-12-31’;
如果这种商品的数量非常多,差不多占了SALES表的记录的50%或更多。那么使用SALE_DATE字段上索引来计算平均数就有些慢。因为如果使用索 引,就得对索引进行排序操作。当满足条件的记录非常多时(如占整个表的记录的50%或更多的比例),速度会变慢,这样还不如对整个表进行扫描。因此, MySQL会自动根据满足条件的数据占整个表的数据的比例自动决定是否使用索引进行查询。
对于MySQL来说,上述的查询结果占整个表的记录的比例是30%左右时就不使用索引了,这个比例是MySQL的开发人员根据他们的经验得出的。然而,实际的比例值会根据所使用的数据库引擎不同而不同。
三、 基于索引的组合
MySQL的弱点之一是它的排序。虽然MySQL可以在1秒中查询大约15,000条记录,但由于MySQL在查询时最多只能使用一个索引。因此,如果 WHERE条件已经占用了索引,那么在排序中就不使用索引了,这将大大降低查询的速度。我们可以看看如下的SQL语句:
SELECT * FROM SALES WHERE NAME = “name” ORDER BY SALE_DATE DESC;
在以上的SQL的WHERE子句中已经使用了NAME字段上的索引,因此,在对SALE_DATE进行排序时将不再使用索引。为了解决这个问题,我们可以对SALES表建立复合索引:
ALTER TABLE SALES DROP INDEX NAME, ADD INDEX (NAME, SALE_DATE)
这样再使用上述的SELECT语句进行查询时速度就会大副提升。但要注意,在使用这个方法时,要确保WHERE子句中没有排序字段,在上例中就是不能用 SALE_DATE进行查询,否则虽然排序快了,但是SALE_DATE字段上没有单独的索引,因此查询又会慢下来。
SELECT * FROM SALES WHERE NAME = “name1” AND NAME = “name2”
以上的查询语句要查找NAME既等于name1又等于name2的记录。很明显,这是一个不可达的查询,WHERE条件一定是假。MySQL在执行SQL 语句之前,会先分析WHERE条件是否是不可达的查询,如果是,就不再执行这条SQL语句了。为了验证这一点。我们首先对如下的SQL使用EXPLAIN 进行测试:
EXPLAIN SELECT * FROM SALES WHERE NAME = “name1”
上面的查询是一个正常的查询,我们可以看到使用EXPLAIN返回的执行信息数据中table项是SALES。这说明MySQL对SALES进行操作了。再看看下面的语句:
EXPLAIN SELECT * FROM SALES WHERE NAME = “name1” AND NAME = “name2”
我们可以看到,table项是空,这说明MySQL并没有对SALES表进行操作。
五、 使用各种查询选择来提高性能
SELECT语句除了正常的使用外,MySQL还为我们提供了很多可以增强查询性能的选项。如上面介绍的用于控制查询缓冲的SQL_NO_CACHE和SQL_CACHE就是其中两个选项。在这一部分,我将介绍几个常用的查询选项。
1. STRAIGHT_JOIN:强制连接顺序
当我们将两个或多个表连接起来进行查询时,我们并不用关心MySQL先连哪个表,后连哪个表。而这一切都是由MySQL内部通过一系列的计算、评估,最后得出的一个连接顺序决定的。如下列的SQL语句中,TABLE1和TABLE2并不一定是谁连接谁:
SELECT TABLE1.FIELD1, TABLE2.FIELD2 FROM TABLE1 ,TABLE2 WHERE …
如果开发人员需要人为地干预连接的顺序,就得使用STRAIGHT_JOIN关键字,如下列的SQL语句:
SELECT TABLE1.FIELD1, TABLE2.FIELD2 FROM TABLE1 STRAIGHT_JOIN TABLE2 WHERE …
由上面的SQL语句可知,通过STRAIGHT_JOIN强迫MySQL按TABLE1、TABLE2的顺序连接表。如果你认为按自己的顺序比MySQL推荐的顺序进行连接的效率高的话,就可以通过STRAIGHT_JOIN来确定连接顺序。
2. 干预索引使用,提高性能
在上面已经提到了索引的使用。一般情况下,在查询时MySQL将自己决定是否使用索引,使用哪一个索引。但在一些特殊情况下,我们希望MySQL只使用一个或几个索引,或者不希望使用某个索引。这就需要使用MySQL的控制索引的一些查询选项。
(1) 限制使用索引的范围
有时我们在数据表里建立了很多索引,当MySQL对索引进行选择时,这些索引都在考虑的范围内。但有时我们希望MySQL只考虑几个索引,而不是全部的索引,这就需要用到USE INDEX对查询语句进行设置。
SELECT * FROM TABLE1 USE INDEX (FIELD1, FIELD2) …
从以上SQL语句可以看出,无论在TABLE1中已经建立了多少个索引,MySQL在选择索引时,只考虑在FIELD1和FIELD2上建立的索引。
(2) 限制不使用索引的范围
如果我们要考虑的索引很多,而不被使用的索引又很少时,可以使用IGNORE INDEX进行反向选取。在上面的例子中是选择被考虑的索引,而使用IGNORE INDEX是选择不被考虑的索引。
SELECT * FROM TABLE1 IGNORE INDEX (FIELD1, FIELD2) …
在上面的SQL语句中,TABLE1表中只有FIELD1和FIELD2上的索引不被使用。
(3) 强迫使用某一个索引
上面的两个例子都是给MySQL提供一个选择,也就是说MySQL并不一定要使用这些索引。而有时我们希望MySQL必须要使用某一个索引(由于 MySQL在查询时只能使用一个索引,因此只能强迫MySQL使用一个索引)。这就需要使用FORCE INDEX来完成这个功能。
SELECT * FROM TABLE1 FORCE INDEX (FIELD1) …
以上的SQL语句只使用建立在FIELD1上的索引,而不使用其它字段上的索引。
3. 使用临时表提供查询性能(零时表有大作用)
当我们查询的结果集中的数据比较多时,可以通过SQL_BUFFER_RESULT.选项强制将结果集放到临时表中,这样就可以很快地释放MySQL的表锁(这样其它的SQL语句就可以对这些记录进行查询了),并且可以长时间地为客户端提供大记录集。
SELECT SQL_BUFFER_RESULT * FROM TABLE1 WHERE …
和SQL_BUFFER_RESULT.选项类似的还有SQL_BIG_RESULT,这个选项一般用于分组或DISTINCT关键字,这个选项通知MySQL,如果有必要,就将查询结果放到临时表中,甚至在临时表中进行排序。
SELECT SQL_BUFFER_RESULT FIELD1, COUNT(*) FROM TABLE1 GROUP BY FIELD1
六、 结论
在程序设计中同样存在一个“二八原则”,即20%的代码用去了80%的时间。数据库应用程序的开发亦然。数据库应用程序的优化,重点在于SQL的执行效率。而数据查询优化的重点,则是使得数据库服务器少从磁盘中读数据以及顺序读页而不是非顺序读页。
- 其它技巧:
http://www.cnblogs.com/nokiaguy/archive/2008/05/24/1206469.html
http://www.cnblogs.com/suchshow/archive/2011/12/15/2289182.html
http://www.cnblogs.com/cy163/archive/2009/05/28/1491473.html
http://www.cnblogs.com/younggun/articles/1719943.html
http://wenku.baidu.com/view/f57c7041be1e650e52ea9985.html
2.4 Myeclipse优化
MyEclipse ,新版本的特性能够大大提高开发者的效率。但同时,由于电脑配置的原因,很多开发者在使用MyEclipse的时候,速度都不是很快,需要我们对MyEclipse进行一些必要的优化。
1、老是弹出Quick update error 、关闭MyEclipse的Quick Update自动更新功能
这个问题的解决办法是关闭自动更新:
Windows > Preferences > MyEclipse Enterprise Workbench > Community Essentials,然后把选项 ”Search for new features on startup”的前勾去掉即可。
2 、关闭updating indexes
Window > Preferences > Myeclipse Enterprise Workbench > Maven4Myeclipse > Maven>
禁用Download repository index updates on startup 。
注意:强调一个问题,很多人发现无法找到这个,原因其实是它已经关闭了。
3 、关闭MyEclipse的自动validation
validation有很多,包括xml、jsp、jsf、js等等,我们没有必要全部都去自动校验一下,只是需要的时候才会手工校验一下,速度将很快提升好几个档次。
windows > perferences > myeclipse > validation
将Build下全部勾取消,如果你需要验证某个文件的时候,我们可以单独去验证它。方法是:在需要验证的文件上( 右键 -> MyEclipse -> Run Validation 。
4、 启动优化,关闭不需要使用的模块
一个系统20%的功能往往能够满足80%的需求,MyEclipse也不例外,我们在大多数时候只需要20%的系统功能,所以可以将一些不使用的模块禁止加载启动。
Window > Preferences > General > Startup andy Shutdown 在这里列出的是MyEclipse启动时加载的模块。
我这里只让它加载tomcat5,勾选MyEclipse EASIE Tomcat 5。接下来,关闭工作空间启动刷新:
接下来关闭拼写检查:
只需要取消Enable spell checking:
看到auto activation triggers for Java之后,在里面输入a-z这些字幕吧,然后选择应用,接着去编辑器里查看提示,上面那个选项是延迟多少时间提示,建议不修改。
如图那样选择就完成了,然后我们到myeclipse安装目录>myeclipse.ini打开修改这个文件,建议在做之前备份,不然错了没法启动。
1. -startup
2. ../Common/plugins/org.eclipse.equinox.launcher_1.0.201.R35x_v20090715.jar
3. –launcher.library
4. ../Common/plugins/org.eclipse.equinox.launcher.win32.win32.x86_1.0.200.v20090519
5. -install
6. E:/develop/MYEC85/MyEclipse 8.5 M2
7. -vm
8. E:/develop/MYEC85/Common/binary/com.sun.java.jdk.win32.x86_1.6.0.013/jre/bin/client/jvm.dll
9. -vmargs
10. -Xmx512m
11. -XX:MaxPermSize=512m
12. -XX:ReservedCodeCacheSize=256m
主要是修改:
1. -Xmx512m
2. -XX:MaxPermSize=512m
3. -XX:ReservedCodeCacheSize=256m
这三个优化方案,最好按照自己的内存来选择,选择合适的话,相信效果会很不错。如果修改后无法使用就能把备份覆盖回来吧。
2.5 tomcat性能优化
http://www.cnblogs.com/ggjucheng/archive/2013/04/16/3024731.html