将绑定变量用于IN子句中的大型列表时的性能问题

问题描述 投票:0回答:1

我使用的是Sybase,并且有一些看起来像这样的代码:

String[] ids = ... an array containing 80-90k strings, which is retrieved from another table and varies.
for (String id : ids) {
    // wrap every id with single-quotes 
}
String idsAsString = String.join(",", ids); 
String query = String.format("select * from someTable where idName in (%s)", idsAsString);
getNamedParameterJDBCTemplate().query(query, resultSetExtractor ->{
    // do stuff with results
});

我已经定时到达resultSetExtractor的内部要花多长时间,并且从未花费超过4秒的时间。

但是为了保护代码,我尝试使用绑定变量路由。因此,该代码如下所示:

String[] ids = ... an array containing 80-90k strings, which is retrieved from another table and varies.
String query = "select * from someTable where idName in (:ids)";
Map<String, Object> params = new HashMap<>();
params.put("ids", Arrays.asList(ids));
getNamedParameterJDBCTemplate().query(query, params, resultSetExtractor ->{
    // do stuff with results 
});

但是以这种方式进行此操作最多需要4-5分钟的时间才能产生以下异常:

21-10-2019 14:04:01 DEBUG DefaultConnectionTester:126 - Testing a Connection in response to an Exception:
com.sybase.jdbc4.jdbc.SybSQLException: The token datastream length was not correct. This is an internal protocol error.

[我还有其他一些代码,在其中我将大小为1-10的数组作为绑定变量进行传递,并注意到这些查询从瞬时变为耗时长达10秒。

令我惊讶的是,绑定变量的方式完全不同,更不用说that]了。有人可以解释这里发生了什么吗?与通过JDBC发送格式化的字符串相反,绑定变量在幕后做了什么不同的事情吗?还有另一种方法可以保护我的代码而又不会大大降低性能吗?

我正在使用Sybase,并具有一些类似于以下代码的代码:String [] ids = ...一个包含80-90k字符串的数组,该数组是从另一个表中检索的并且有所不同。 for(String id:ids){//包装...

sql sybase spring-jdbc jdbctemplate
1个回答
0
投票

您应该通过showplan / query计划验证数据库端实际发生的情况,但是使用'in'子句通常最多只能对'in'子句中的每个值进行一个索引搜索,因此10个值可以进行十次搜索,其中80k次搜索会完成80k次搜索,因此速度大大降低。 Oracle实际上禁止在'in子句中放置超过1000个值,而Sybase的限制并不那么严格,这并不意味着它是一个好主意。通过以这种方式放置大量值,您可能会冒着栈和数据库中其他问题的风险,我已经看到这种查询会导致栈失败的生产数据库实例。

© www.soinside.com 2019 - 2024. All rights reserved.