在进行SQL优化时,很重要的一点就是要看到底层执行的具体SQL,虽然可以通过打印日志的方式获取具体的SQL和SQL的执行效率,但是这样做很不方便,尤其在是使用Hibernate作为持久层时,大量的占位符让人很是头痛
P6Spy
P6Spy是一款开源的SQL监控工具,可以记录所有数据库操作及其消耗的时间
下载地址:http://sourceforge.net/projects/p6spy/files/p6spy/
使用起来非常简单(以下配置只适用于单独使用Hibernate的,对于Hibernate+Spring的项目不适用):
1,将p6spy.jar加入项目工程classpath中
2,将p6spy配置文件spy.properties加入项目工程/src目录下
3,将项目工程的数据库驱动修改为P6Spy提供的驱动(修改Hibernate配置文件hibernate.cfg.xml):
<!-- <property name="connection.driver_class">com.mysql.jdbc.Driver</property> --> <property name="connection.driver_class">com.p6spy.engine.spy.P6SpyDriver</property>
4,修改p6spy配置文件:
realdriver项修改为项目工程实际使用的驱动
# oracle driver # realdriver=oracle.jdbc.driver.OracleDriver # mysql Connector/J driver # realdriver=com.mysql.jdbc.Driver # informix driver # realdriver=com.informix.jdbc.IfxDriver # ibm db2 driver # realdriver=COM.ibm.db2.jdbc.net.DB2Driver # the mysql open source driver #realdriver=org.gjt.mm.mysql.Driver realdriver=com.mysql.jdbc.Driver
deregisterdrivers项一定要修改为true,原因注释已经说的很清楚了
#the DriverManager class sequentially tries every driver that is #it's possible to registered to find the right driver.In some instances, #load up the realdriver before the p6spy driver, in which case #your connections will not get wrapped as the realdriver will "steal" #the connection before p6spy sees it. Set the following property to "true" #to cause p6spy to explicitily deregister the realdrivers deregisterdrivers=true
修改P6Spy的日志记录方式,可选择根据Log4j配置控制日志输出(Log4jLogger)、控制台输出日志信息(StdoutLogger)、文件记录日志信息(FileLogger),示例中将日志信息输出到了日志文件中:
#specifies the appender to use for logging #appender=com.p6spy.engine.logging.appender.Log4jLogger #appender=com.p6spy.engine.logging.appender.StdoutLogger appender=com.p6spy.engine.logging.appender.FileLogger #name of logfile to use, note Windows users should make sure #to use forward slashes in their pathname (e:/test/spy.log) #(used for file logger only) logfile=./log/spy.log # append to the p6spy log file. if this is set to false the # log file is truncated every time. (file logger only) append=true #The following are for log4j logging only log4j.appender.STDOUT=org.apache.log4j.ConsoleAppender log4j.appender.STDOUT.layout=org.apache.log4j.PatternLayout log4j.appender.STDOUT.layout.ConversionPattern=p6spy - %m%n #log4j.appender.CHAINSAW_CLIENT=org.apache.log4j.net.SocketAppender #log4j.appender.CHAINSAW_CLIENT.RemoteHost=localhost #log4j.appender.CHAINSAW_CLIENT.Port=4445 #log4j.appender.CHAINSAW_CLIENT.LocationInfo=true log4j.logger.p6spy=INFO,STDOUT
日志文件spy.log中记录的信息如下(第一个“|”右边的数字是SQL消耗的时间,单位为ms):
1399255288210|4|0|statement|select user0_.id as id0_, user0_.name as name0_, user0_.age as age0_ from TEST_USER user0_ where user0_.id>2|select user0_.id as id0_, user0_.name as name0_, user0_.age as age0_ from TEST_USER user0_ where user0_.id>2 1399255288217|-1||resultset|select user0_.id as id0_, user0_.name as name0_, user0_.age as age0_ from TEST_USER user0_ where user0_.id>2|age0_ = 30, id0_ = 3, name0_ = ll
事实上,单独使用Hibernate的项目很少,大多数项目会同时使用Hibernate和Spring,此时数据库连接通常由Spring管理
无论是何种架构方式,只要保证在进行数据库操作之前,调用P6Spy的相关类,就可以让P6Spy监控到所有数据库操作并进行记录
所以本质上要做就是在每次数据库操作之前增加对P6Spy的调用:
1,将p6spy.jar加入Web工程WebRoot/WEB_INF/lib目录下
2,将p6spy配置文件spy.properties加入Web工程/src目录下
3,spy.properties的修改方式同上
4,修改Spring配置文件applicationContext.xml,对数据库连接进行封装(这里Spring通过JNDI查找数据源):
<bean id="dataSource" class="com.p6spy.engine.spy.P6DataSource" destroy-method="close"> <constructor-arg> <ref local="dataSourceTarget"/> </constructor-arg> </bean> <bean id="dataSourceTarget" class="org.springframework.jndi.JndiObjectFactoryBean"> <property name="jndiName"> <value>java:/comp/env/DB</value> </property> </bean> <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"> <property name="dataSource"> <ref bean="dataSource" /> </property> <property name="configLocation"> <value>classpath:hibernate.cfg.xml</value> </property> </bean>
Tomcat中数据源配置:
<Resource name="DB" type="javax.sql.DataSource" maxWait="5000" maxActive="100" maxIdle="40" username="admin" password="admin" url="jdbc:oracle:thin:@127.0.0.1:1521:oracle" driverClassName="oracle.jdbc.driver.OracleDriver"/> <Context docBase="D:\eclipseProject\Test\WebRoot" path="/" reloadable="true"> <ResourceLink global="DB" name="DB" type="javax.sql.DataSource"/> </Context>
SQL Profiler
SQL Profiler是一款基于P6Spy的图形化监控工具,不但能够监控SQL执行,统计SQL的执行结果,还能根据SQL的执行效能提供优化建议,比起P6Spy的日志信息更加直观好用
下载地址:http://sourceforge.net/projects/sqlprofiler/files/sqlprofiler/
使用SQLProfiler自带的spy.properties文件覆盖上面的spy.properties文件,spy.properties文件中的realdriver项修改为项目工程实际使用的驱动,deregisterdrivers项修改为true
SQLProfiler要求P6Spy使用Log4j下的SocketAppender方式记录日志:
#specifies the appender to use for logging appender=com.p6spy.engine.logging.appender.Log4jLogger #appender=com.p6spy.engine.logging.appender.StdoutLogger #appender=com.p6spy.engine.logging.appender.FileLogger #The following are for log4j logging only #log4j.appender.STDOUT=org.apache.log4j.ConsoleAppender #log4j.appender.STDOUT.layout=org.apache.log4j.PatternLayout #log4j.appender.STDOUT.layout.ConversionPattern=p6spy - %m%n log4j.appender.SQLPROFILER_CLIENT=org.apache.log4j.net.SocketAppender log4j.appender.SQLPROFILER_CLIENT.RemoteHost=localhost log4j.appender.SQLPROFILER_CLIENT.Port=4445 log4j.appender.SQLPROFILER_CLIENT.LocationInfo=true #log4j.logger.p6spy=INFO,STDOUT log4j.logger.p6spy=DEBUG, SQLPROFILER_CLIENT
将sqlprofiler.jar放至e盘下,打开cmd运行java -Xms200m -Xmx512m -jar sqlprofiler.jar即可弹出图形化监控界面
特别需要注意的是要先运行SQL Profiler,再运行需要进行监控的应用程序
Profile标签页包含所有P6Spy日志的详细信息和对每条日志信息的分析结果
Logger标签页中包含所有P6Spy记录的日志,并且可以根据日志级别,线程名等条件过滤出特定的日志条目
Analysis标签页则是图形化的分析结果
IronTrack SQL
SQL Profiler虽好用,但却是被动连接的,即SQL Profiler监测不到在其启动前启动的应用程序,并且如果SQL Profiler意外关闭,再次启动后必须重启其监控的应用程序,这一点不是很方便,在这一点上,IronTrack SQL就要好很多,IronTrack SQL是主动去监控应用程序的
1,使用IronTrack SQL自带的spy.properties文件覆盖上面的spy.properties文件,spy.properties文件中的realdriver项修改为项目工程实际使用的驱动,deregisterdrivers项修改为true,monitorport项为监控端口,默认值是2000
2,将irontracksql.jar加入项目工程classpath中/将irontracksql.jar加入Web工程WebRoot/WEB_INF/lib目录下(不需要添加其依赖包)
3,双击irontracksql.jar即可打开监控页面
点击Config按钮,在弹出的Configuration框中输入连接信息,输入完成后点击OK按钮,最后点击Connect按钮即可开始监控
更加详细的介绍,参见:http://www.ibm.com/developerworks/cn/java/j-lo-p6spy/