提升数据服务API性能:解析SQL时间占比优化与缓存机制的应用
1、问题分析
数据服务api之前做过压测,从火焰图分析 解析SQL时间占比比较大,为了提高性能,我们需要专注于优化解析SQL的部分。
| 验签 | 获取apiinfo | 解析SQL | 执行动态SQL |
| 11.18% | 2.55% | 28.03% | 6.35% |
2、优化前代码分析
本文提供优化前的代码示例,其中包括了解析MyBatis SQL的方法。该方法涉及使用XPathParser来解析SQL,创建SqlSource,并最终得到带有参数值的完整SQL。然后,该SQL用于获取分页数据。
/**
* mybatis sql解析
*
* @param databaseType 数据源类型 mysql,oracle,clickhouse
* @param sql mybatis模板sql
* @param params 参数
* @param pageDTO 分页参数
* @return
*/
private static String parseMybatisSql(String databaseType, String sql, Map<String, Object> params, ApiPageDTO pageDTO) { XPathParser xPathParser = new XPathParser(sql); XNode node = xPathParser.evalNode("select|insert|update|delete"); Configuration configuration = new Configuration(); LanguageDriver langDriver = configuration.getLanguageDriver(null); SqlSource sqlSource = langDriver.createSqlSource(configuration, node, null); BoundSql boundSql = sqlSource.getBoundSql(params); String sqlWithVal = getFullSql(configuration, boundSql); return DataBaseTypeEnum.getDataBaseTypeEnumByName(databaseType).getPageExpression(pageDTO, sqlWithVal); }
- 每次API请求,SQL语句作为参数,然后从缓存中获取对应的SqlSource对象
- 单例模式获取Configuration实例
3、优化方案
提出了一种优化方案,以减少解析SQL的性能开销。新的代码示例使用了SqlSourceCache和ConfigurationSingleton两个关键组件。下面,我们对这两个组件进行详细说明。
SqlSourceCache
SqlSourceCache 是一个缓存机制,它用于存储已解析的SQL语句。这有助于避免重复解析相同的SQL,从而提高性能。Cache最大容量设置为100,采用LRU策略,确保缓存不会无限增长。每当需要解析SQL时,该组件会检查缓存中是否已存在解析过的SQL,如果存在,则直接返回,否则执行解析并将其缓存。
ConfigurationSingleton
ConfigurationSingleton 是一个单例模式的类,用于获取MyBatis的Configuration实例。这确保了只有一个Configuration实例存在,减少了不必要的资源开销。
优化后代码为
private static String parseMybatisSql(String databaseType, String sql, Map<String, Object> params, ApiPageDTO pageDTO) { SqlSource sqlSource = SqlSourceCache.getSqlSource(sql); BoundSql boundSql = sqlSource.getBoundSql(params); String sqlWithVal = getFullSql(ConfigurationSingleton.getInstance(), boundSql); return DataBaseTypeEnum.getDataBaseTypeEnumByName(databaseType).getPageExpression(pageDTO, sqlWithVal); }
public class SqlSourceCache {
private static final int CACHE_MAX = 100; private static final Map<String, SqlSource> cache = new LinkedHashMap<String, SqlSource>(CACHE_MAX, 0.75f, true) { // 重写removeEldestEntry方法来控制缓存的大小,使用LRU策略 @Override protected boolean removeEldestEntry(Map.Entry<String, SqlSource> eldest) { return size() > CACHE_MAX; } }; private SqlSourceCache() { // 私有构造函数,防止其他类实例化该类 } public static SqlSource getSqlSource(String encryptedSQL) { return cache.computeIfAbsent(encryptedSQL, SqlSourceCache::initSqlSource); } private static SqlSource initSqlSource(String encryptedSQL) { String sql = AesUtil.decryptAes(encryptedSQL, BaseConstant.SQL_ENCODE32_KEY); XPathParser xPathParser = new XPathParser(sql); XNode node = xPathParser.evalNode("select|insert|update|delete"); Configuration configuration = ConfigurationSingleton.getInstance(); LanguageDriver langDriver = configuration.getLanguageDriver(null); SqlSource sqlSource = langDriver.createSqlSource(configuration, node, null); return sqlSource; } }
public class ConfigurationSingleton { private static volatile Configuration instance; public static Configuration getInstance() { if (instance == null) { synchronized (ConfigurationSingleton.class) { if (instance == null) { instance = new Configuration(); } } } return instance; } }
4、优化效果
这些优化措施的主要目的是减少解析SQL的时间,从而提高数据服务API的性能。通过将已解析的SQL缓存起来,我们避免了重复解析的开销,而通过单例模式的Configuration,我们减少了对象创建的开销。这两个优化措施相结合,可以显著提高数据服务API的性能,减少解析SQL所占用的时间,从而加速API的响应时间。
这些优化措施对于处理大量API请求尤其重要,可以显著减少解析SQL的开销,提高API的响应速度。通过实施这些优化,可以提高数据服务API的性能,提供更快的响应时间。

浙公网安备 33010602011771号