在这个项目中,由于一些原因没有使用orm进行数据库操作,而是使用Spring的JdbcTemplate
但在上线后发现效率很低,通过性能监视器发现SQL Compilations的比率很高,程序中大量使用动态拼SQL语句的情况
于是进行了一些性能测试
代码如下:
Main.log("SQL四种执行方式性能比较"); // Statement jt.execute("dbcc freeproccache"); start = System.currentTimeMillis(); sql = "select top {0} id, intStatus from tblInfo where charCityFrom=''{1}''"; for (int i = citys.size() -1; i >= 0; i--) { Map c = citys.get(i); String city = (String) c.get("charCityFrom"); jt.queryForList(MessageFormat.format(sql, i % 20 + 1, city)); } map = jt.queryForMap("Select Count(*) CNT,sum(size_in_bytes) TotalSize From sys.dm_exec_cached_plans"); Main.log("Statement:CNT=" + map.get("CNT") + " TotalSize=" + map.get("TotalSize"), start); // PreparedStatement jt.execute("dbcc freeproccache"); start = System.currentTimeMillis(); sql = "select top {0} id, intStatus from tblInfo where charCityFrom=?"; for (int i = citys.size() -1; i >= 0; i--) { Map c = citys.get(i); String city = (String) c.get("charCityFrom"); jt.queryForList(MessageFormat.format(sql, i % 20 + 1), new Object[]{city}); } map = jt.queryForMap("Select Count(*) CNT,sum(size_in_bytes) TotalSize From sys.dm_exec_cached_plans"); Main.log("PreparedStatement:CNT=" + map.get("CNT") + " TotalSize=" + map.get("TotalSize"), start); // EXEC sp_executesql jt.execute("dbcc freeproccache"); start = System.currentTimeMillis(); sql = "EXEC sp_executesql N''select top {0} id, intStatus from tblInfo where charCityFrom=@cityFrom'', N''@cityFrom nvarchar(10)'', ''{1}''"; for (int i = citys.size() -1; i >= 0; i--) { Map c = citys.get(i); String city = (String) c.get("charCityFrom"); jt.queryForList(MessageFormat.format(sql, i % 20 + 1, city)); } map = jt.queryForMap("Select Count(*) CNT,sum(size_in_bytes) TotalSize From sys.dm_exec_cached_plans"); Main.log("Sp_executesql:CNT=" + map.get("CNT") + " TotalSize=" + map.get("TotalSize"), start); // 存储过程 jt.execute("dbcc freeproccache"); start = System.currentTimeMillis(); sql = "exec sp_FindInfoByCitFrom {0},''{1}''"; for (int i = citys.size() -1; i >= 0; i--) { Map c = citys.get(i); String city = (String) c.get("charCityFrom"); jt.queryForList(MessageFormat.format(sql, i % 20 + 1, city)); } map = jt.queryForMap("Select Count(*) CNT,sum(size_in_bytes) TotalSize From sys.dm_exec_cached_plans"); Main.log("Procedure:CNT=" + map.get("CNT") + " TotalSize=" + map.get("TotalSize"), start);
得到结果(多次执行,结果相关不大):
2008-11-05 10:36:52.521 [main] - SQL四种执行方式性能比较
2008-11-05 10:36:53.365 [main] - Statement:CNT=224 TotalSize=9134080 t=829ms
2008-11-05 10:36:53.815 [main] - PreparedStatement:CNT=23 TotalSize=901120 t=450ms
2008-11-05 10:36:55.44 [main] - Sp_executesql:CNT=26 TotalSize=1351680 t=1625ms
2008-11-05 10:36:55.864 [main] - Procedure:CNT=25 TotalSize=933888 t=424ms
存储过程虽然性能最高,但维护确实有点麻烦
综合一下就我们的情况使用PreparedStatement最好,不过以前使用sql server 2000时有发现这个性能不好,看来跟生产环境还是有挺大关系
Sp_executesql的表现倒是出乎意料
经验主意害死人啊,就这个问题浪费了大量的时间