Skip to content

Commit a200701

Browse files
committed
refactor: 增加SQL解析缓存,以提升性能
之前除SqlServerDialect外,其他Dialect之前没有sql解析缓存. 优化前项目中每次此plugin的SQL解析基本在7/8到几十毫秒之间,有时比sql本身数据库执行还慢时! 经分析这个慢原因是其依赖的jsqlparser本身解析就慢,且在4.5时有反向优化(采用线程池却没每次重新线程!) ``` jad net.sf.jsqlparser.parser.CCJSqlParserUtil parseStatement ``` 测试发现jsqlparser 4.7和pagehelper不兼容, 4.6 和4.5有同样的问题 增加SQL解析缓存后,重复访问的耗时基本0.5毫秒以下 *需要说明的这次重构目前只在mysql下测试,其他Dialect未经测试*
1 parent 30dd0f3 commit a200701

10 files changed

+187
-52
lines changed

src/main/java/com/github/pagehelper/dialect/AbstractHelperDialect.java

Lines changed: 128 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,15 @@
2424

2525
package com.github.pagehelper.dialect;
2626

27+
import org.slf4j.Logger;
28+
import org.slf4j.LoggerFactory;
29+
2730
import com.github.pagehelper.Constant;
2831
import com.github.pagehelper.Page;
2932
import com.github.pagehelper.PageHelper;
3033
import com.github.pagehelper.PageRowBounds;
34+
import com.github.pagehelper.cache.Cache;
35+
import com.github.pagehelper.cache.CacheFactory;
3136
import com.github.pagehelper.util.ExecutorUtil;
3237
import com.github.pagehelper.util.MetaObjectUtil;
3338
import com.github.pagehelper.util.StringUtil;
@@ -48,6 +53,16 @@
4853
* @since 2016-12-04 14:32
4954
*/
5055
public abstract class AbstractHelperDialect extends AbstractDialect implements Constant {
56+
/**
57+
* Logger for this class.
58+
*/
59+
private static final Logger logger = LoggerFactory.getLogger(AbstractHelperDialect.class);
60+
61+
protected Cache<String, String> CACHE_COUNTSQL;
62+
protected Cache<String, String> CACHE_PAGESQL;
63+
64+
public static boolean cacheOnFlag = true;// 临时性开关,为了方便切换,以验证缓存前后对比.
65+
public static boolean tracingOn = false;// 临时性开关
5166

5267
/**
5368
* 获取分页参数
@@ -61,7 +76,7 @@ public <T> Page<T> getLocalPage() {
6176

6277
@Override
6378
public final boolean skip(MappedStatement ms, Object parameterObject, RowBounds rowBounds) {
64-
//该方法不会被调用
79+
// 该方法不会被调用
6580
return true;
6681
}
6782

@@ -72,13 +87,48 @@ public boolean beforeCount(MappedStatement ms, Object parameterObject, RowBounds
7287
}
7388

7489
@Override
75-
public String getCountSql(MappedStatement ms, BoundSql boundSql, Object parameterObject, RowBounds rowBounds, CacheKey countKey) {
90+
public String getCountSql(MappedStatement ms, BoundSql boundSql, Object parameterObject, RowBounds rowBounds,
91+
CacheKey countKey) {
92+
final long startTime = tracingOn || logger.isDebugEnabled() ? System.nanoTime() : 0;
93+
if (startTime > 0) {
94+
logger.info("getCountSql start ...");
95+
}
7696
Page<Object> page = getLocalPage();
7797
String countColumn = page.getCountColumn();
98+
final String sql = boundSql.getSql();
99+
final String countSqlKey;
100+
String cachedSql;
101+
final boolean cacheOn = cacheOnFlag && CACHE_COUNTSQL != null;
78102
if (StringUtil.isNotEmpty(countColumn)) {
79-
return countSqlParser.getSmartCountSql(boundSql.getSql(), countColumn);
103+
countSqlKey = sql + countColumn;
104+
cachedSql = cacheOn ? CACHE_COUNTSQL.get(countSqlKey) : null;
105+
if (cachedSql != null) {
106+
logCountSqlEnd(startTime);
107+
return cachedSql;
108+
}
109+
cachedSql = countSqlParser.getSmartCountSql(sql, countColumn);
110+
} else {
111+
countSqlKey = sql;
112+
cachedSql = cacheOn ? CACHE_COUNTSQL.get(countSqlKey) : null;
113+
if (cachedSql != null) {
114+
logCountSqlEnd(startTime);
115+
return cachedSql;
116+
}
117+
cachedSql = countSqlParser.getSmartCountSql(sql);
118+
}
119+
if (cacheOn) {
120+
CACHE_COUNTSQL.put(countSqlKey, cachedSql);
121+
}
122+
logCountSqlEnd(startTime);
123+
return cachedSql;
124+
}
125+
126+
private void logCountSqlEnd(final long startTime) {
127+
if (startTime > 0) {
128+
final long time = System.nanoTime() - startTime;
129+
logger.info("getCountSql(cacheOn={}) end: {}", cacheOnFlag,
130+
Double.toString(time == 0 ? 0 : time / 1000000d));
80131
}
81-
return countSqlParser.getSmartCountSql(boundSql.getSql());
82132
}
83133

84134
@Override
@@ -88,58 +138,61 @@ public boolean afterCount(long count, Object parameterObject, RowBounds rowBound
88138
if (rowBounds instanceof PageRowBounds) {
89139
((PageRowBounds) rowBounds).setTotal(count);
90140
}
91-
//pageSize < 0 的时候,不执行分页查询
92-
//pageSize = 0 的时候,还需要执行后续查询,但是不会分页
141+
// pageSize < 0 的时候,不执行分页查询
142+
// pageSize = 0 的时候,还需要执行后续查询,但是不会分页
93143
if (page.getPageSizeZero() != null) {
94-
//PageSizeZero=false&&pageSize<=0
144+
// PageSizeZero=false&&pageSize<=0
95145
if (!page.getPageSizeZero() && page.getPageSize() <= 0) {
96146
return false;
97147
}
98-
//PageSizeZero=true&&pageSize<0 返回 false,只有>=0才需要执行后续的
148+
// PageSizeZero=true&&pageSize<0 返回 false,只有>=0才需要执行后续的
99149
else if (page.getPageSizeZero() && page.getPageSize() < 0) {
100150
return false;
101151
}
102152
}
103-
//页码>0 && 开始行数<总行数即可,不需要考虑 pageSize(上面的 if 已经处理不符合要求的值了)
153+
// 页码>0 && 开始行数<总行数即可,不需要考虑 pageSize(上面的 if 已经处理不符合要求的值了)
104154
return page.getPageNum() > 0 && count > page.getStartRow();
105155
}
106156

107157
@Override
108-
public Object processParameterObject(MappedStatement ms, Object parameterObject, BoundSql boundSql, CacheKey pageKey) {
109-
//处理参数
158+
public Object processParameterObject(MappedStatement ms, Object parameterObject, BoundSql boundSql,
159+
CacheKey pageKey) {
160+
// 处理参数
110161
Page page = getLocalPage();
111-
//如果只是 order by 就不必处理参数
162+
// 如果只是 order by 就不必处理参数
112163
if (page.isOrderByOnly()) {
113164
return parameterObject;
114165
}
115166
Map<String, Object> paramMap = null;
116167
if (parameterObject == null) {
117168
paramMap = new HashMap<String, Object>();
118169
} else if (parameterObject instanceof Map) {
119-
//解决不可变Map的情况
170+
// 解决不可变Map的情况
120171
paramMap = new HashMap<String, Object>();
121172
paramMap.putAll((Map) parameterObject);
122173
} else {
123174
paramMap = new HashMap<String, Object>();
124175
// sqlSource为ProviderSqlSource时,处理只有1个参数的情况
125176
if (ms.getSqlSource() instanceof ProviderSqlSource) {
126-
String[] providerMethodArgumentNames = ExecutorUtil.getProviderMethodArgumentNames((ProviderSqlSource) ms.getSqlSource());
177+
String[] providerMethodArgumentNames = ExecutorUtil
178+
.getProviderMethodArgumentNames((ProviderSqlSource) ms.getSqlSource());
127179
if (providerMethodArgumentNames != null && providerMethodArgumentNames.length == 1) {
128180
paramMap.put(providerMethodArgumentNames[0], parameterObject);
129181
paramMap.put("param1", parameterObject);
130182
}
131183
}
132-
//动态sql时的判断条件不会出现在ParameterMapping中,但是必须有,所以这里需要收集所有的getter属性
133-
//TypeHandlerRegistry可以直接处理的会作为一个直接使用的对象进行处理
134-
boolean hasTypeHandler = ms.getConfiguration().getTypeHandlerRegistry().hasTypeHandler(parameterObject.getClass());
184+
// 动态sql时的判断条件不会出现在ParameterMapping中,但是必须有,所以这里需要收集所有的getter属性
185+
// TypeHandlerRegistry可以直接处理的会作为一个直接使用的对象进行处理
186+
boolean hasTypeHandler = ms.getConfiguration().getTypeHandlerRegistry()
187+
.hasTypeHandler(parameterObject.getClass());
135188
MetaObject metaObject = MetaObjectUtil.forObject(parameterObject);
136-
//需要针对注解形式的MyProviderSqlSource保存原值
189+
// 需要针对注解形式的MyProviderSqlSource保存原值
137190
if (!hasTypeHandler) {
138191
for (String name : metaObject.getGetterNames()) {
139192
paramMap.put(name, metaObject.getValue(name));
140193
}
141194
}
142-
//下面这段方法,主要解决一个常见类型的参数时的问题
195+
// 下面这段方法,主要解决一个常见类型的参数时的问题
143196
if (boundSql.getParameterMappings() != null && boundSql.getParameterMappings().size() > 0) {
144197
for (ParameterMapping parameterMapping : boundSql.getParameterMappings()) {
145198
String name = parameterMapping.getProperty();
@@ -168,7 +221,8 @@ public Object processParameterObject(MappedStatement ms, Object parameterObject,
168221
* @param pageKey
169222
* @return
170223
*/
171-
public abstract Object processPageParameter(MappedStatement ms, Map<String, Object> paramMap, Page page, BoundSql boundSql, CacheKey pageKey);
224+
public abstract Object processPageParameter(MappedStatement ms, Map<String, Object> paramMap, Page page,
225+
BoundSql boundSql, CacheKey pageKey);
172226

173227
@Override
174228
public boolean beforePage(MappedStatement ms, Object parameterObject, RowBounds rowBounds) {
@@ -180,19 +234,51 @@ public boolean beforePage(MappedStatement ms, Object parameterObject, RowBounds
180234
}
181235

182236
@Override
183-
public String getPageSql(MappedStatement ms, BoundSql boundSql, Object parameterObject, RowBounds rowBounds, CacheKey pageKey) {
237+
public String getPageSql(MappedStatement ms, BoundSql boundSql, Object parameterObject, RowBounds rowBounds,
238+
CacheKey pageKey) {
184239
String sql = boundSql.getSql();
185240
Page page = getLocalPage();
186-
//支持 order by
241+
// 支持 order by
187242
String orderBy = page.getOrderBy();
243+
String cacheSqlKey = getPageCacheSqlKey(page, sql);
244+
final boolean cacheOn = cacheOnFlag && CACHE_PAGESQL != null;
245+
final boolean orderByOnly = page.isOrderByOnly();
188246
if (StringUtil.isNotEmpty(orderBy)) {
247+
if (cacheOn) {
248+
cacheSqlKey += orderBy;
249+
if (orderByOnly) {
250+
cacheSqlKey += "-orderByOnly";
251+
}
252+
}
189253
pageKey.update(orderBy);
190-
sql = orderBySqlParser.converToOrderBySql(sql, orderBy);
254+
255+
String cachedSql = cacheOn ? CACHE_PAGESQL.get(cacheSqlKey) : null;
256+
if (cachedSql == null) {
257+
cachedSql = orderBySqlParser.converToOrderBySql(sql, orderBy);
258+
if (cacheOn && orderByOnly) {
259+
CACHE_PAGESQL.put(cacheSqlKey, cachedSql);
260+
}
261+
}
262+
sql = cachedSql;
191263
}
192-
if (page.isOrderByOnly()) {
264+
if (orderByOnly) {
193265
return sql;
194266
}
195-
return getPageSql(sql, page, pageKey);
267+
String pageSql = cacheOn ? CACHE_PAGESQL.get(cacheSqlKey) : null;
268+
if (pageSql == null) {
269+
pageSql = getPageSql(sql, page, pageKey);
270+
if (cacheOn) {
271+
CACHE_PAGESQL.put(cacheSqlKey, pageSql);
272+
}
273+
}
274+
return pageSql;
275+
}
276+
277+
protected String getPageCacheSqlKey(final Page page, final String sql) {
278+
if (page.getStartRow() == 0) {
279+
return sql;
280+
}
281+
return sql + "-1";
196282
}
197283

198284
/**
@@ -212,7 +298,7 @@ public Object afterPage(List pageList, Object parameterObject, RowBounds rowBoun
212298
return pageList;
213299
}
214300
page.addAll(pageList);
215-
//调整判断顺序,如果查全部,total就是size,如果只排序,也是全部,其他情况下如果不查询count就是-1
301+
// 调整判断顺序,如果查全部,total就是size,如果只排序,也是全部,其他情况下如果不查询count就是-1
216302
if ((page.getPageSizeZero() != null && page.getPageSizeZero()) && page.getPageSize() == 0) {
217303
page.setTotal(pageList.size());
218304
} else if (page.isOrderByOnly()) {
@@ -231,12 +317,21 @@ public void afterAll() {
231317
@Override
232318
public void setProperties(Properties properties) {
233319
super.setProperties(properties);
320+
final String sqlCacheClass = properties.getProperty("sqlCacheClass");
321+
if (StringUtil.isNotEmpty(sqlCacheClass) && !sqlCacheClass.equalsIgnoreCase("false")) {
322+
CACHE_COUNTSQL = CacheFactory.createCache(sqlCacheClass, "count", properties);
323+
CACHE_PAGESQL = CacheFactory.createCache(sqlCacheClass, "page", properties);
324+
} else if (!"false".equalsIgnoreCase(sqlCacheClass)) {
325+
CACHE_COUNTSQL = CacheFactory.createCache(null, "count", properties);
326+
CACHE_PAGESQL = CacheFactory.createCache(null, "page", properties);
327+
}
234328
}
235329

236330
/**
237331
* @param boundSql
238332
* @param ms
239-
* @deprecated use {@code handleParameter(BoundSql boundSql, MappedStatement ms, Class<?> firstClass, Class<?> secondClass)}
333+
* @deprecated use
334+
* {@code handleParameter(BoundSql boundSql, MappedStatement ms, Class<?> firstClass, Class<?> secondClass)}
240335
*/
241336
@Deprecated
242337
protected void handleParameter(BoundSql boundSql, MappedStatement ms) {
@@ -247,9 +342,12 @@ protected void handleParameter(BoundSql boundSql, MappedStatement ms) {
247342

248343
protected void handleParameter(BoundSql boundSql, MappedStatement ms, Class<?> firstClass, Class<?> secondClass) {
249344
if (boundSql.getParameterMappings() != null) {
250-
List<ParameterMapping> newParameterMappings = new ArrayList<ParameterMapping>(boundSql.getParameterMappings());
251-
newParameterMappings.add(new ParameterMapping.Builder(ms.getConfiguration(), PAGEPARAMETER_FIRST, firstClass).build());
252-
newParameterMappings.add(new ParameterMapping.Builder(ms.getConfiguration(), PAGEPARAMETER_SECOND, secondClass).build());
345+
List<ParameterMapping> newParameterMappings = new ArrayList<ParameterMapping>(
346+
boundSql.getParameterMappings());
347+
newParameterMappings
348+
.add(new ParameterMapping.Builder(ms.getConfiguration(), PAGEPARAMETER_FIRST, firstClass).build());
349+
newParameterMappings.add(
350+
new ParameterMapping.Builder(ms.getConfiguration(), PAGEPARAMETER_SECOND, secondClass).build());
253351
MetaObject metaObject = MetaObjectUtil.forObject(boundSql);
254352
metaObject.setValue("parameterMappings", newParameterMappings);
255353
}

src/main/java/com/github/pagehelper/dialect/helper/AS400Dialect.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,4 +53,9 @@ public Object processPageParameter(MappedStatement ms, Map<String, Object> param
5353
public String getPageSql(String sql, Page page, CacheKey pageKey) {
5454
return sql + " OFFSET ? ROWS FETCH FIRST ? ROWS ONLY";
5555
}
56+
57+
@Override
58+
protected String getPageCacheSqlKey(final Page page, final String sql) {
59+
return sql;
60+
}
5661
}

src/main/java/com/github/pagehelper/dialect/helper/CirroDataDialect.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,4 +56,8 @@ public String getPageSql(String sql, Page page, CacheKey pageKey) {
5656
return sqlBuilder.toString();
5757
}
5858

59+
@Override
60+
protected String getPageCacheSqlKey(final Page page, final String sql) {
61+
return sql;
62+
}
5963
}

src/main/java/com/github/pagehelper/dialect/helper/Db2Dialect.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,4 +58,8 @@ public String getPageSql(String sql, Page page, CacheKey pageKey) {
5858
return sqlBuilder.toString();
5959
}
6060

61+
@Override
62+
protected String getPageCacheSqlKey(final Page page, final String sql) {
63+
return sql;
64+
}
6165
}

src/main/java/com/github/pagehelper/dialect/helper/FirebirdDialect.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,4 +64,8 @@ public String getPageSql(String sql, Page page, CacheKey pageKey) {
6464
return sqlBuilder.toString();
6565
}
6666

67+
@Override
68+
protected String getPageCacheSqlKey(final Page page, final String sql) {
69+
return sql;
70+
}
6771
}

src/main/java/com/github/pagehelper/dialect/helper/HsqldbDialect.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,4 +76,16 @@ public String getPageSql(String sql, Page page, CacheKey pageKey) {
7676
}
7777
return sqlBuilder.toString();
7878
}
79+
80+
@Override
81+
protected String getPageCacheSqlKey(final Page page, final String sql) {
82+
String cacheKey = sql;
83+
if (page.getPageSize() > 0) {
84+
cacheKey += "-p";
85+
}
86+
if (page.getStartRow() > 0) {
87+
cacheKey += "-s";
88+
}
89+
return cacheKey;
90+
}
7991
}

src/main/java/com/github/pagehelper/dialect/helper/Oracle9iDialect.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,4 +65,8 @@ public String getPageSql(String sql, Page page, CacheKey pageKey) {
6565
return sqlBuilder.toString();
6666
}
6767

68+
@Override
69+
protected String getPageCacheSqlKey(final Page page, final String sql) {
70+
return sql;
71+
}
6872
}

src/main/java/com/github/pagehelper/dialect/helper/OracleDialect.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,4 +60,8 @@ public String getPageSql(String sql, Page page, CacheKey pageKey) {
6060
return sqlBuilder.toString();
6161
}
6262

63+
@Override
64+
protected String getPageCacheSqlKey(final Page page, final String sql) {
65+
return sql;
66+
}
6367
}

src/main/java/com/github/pagehelper/dialect/helper/SqlServer2012Dialect.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,4 +57,8 @@ public String getPageSql(String sql, Page page, CacheKey pageKey) {
5757
return sqlBuilder.toString();
5858
}
5959

60+
@Override
61+
protected String getPageCacheSqlKey(final Page page, final String sql) {
62+
return sql;
63+
}
6064
}

0 commit comments

Comments
 (0)