Проблема производительности при использовании переменной связывания для большого списка в предложении IN - PullRequest
0 голосов
/ 21 октября 2019

Я использую 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 секунд.

Я удивлен, делая это способом переменных связыванияэто совсем другое, не говоря уже о , что резко отличается. Может кто-нибудь объяснить, что здесь происходит? Эта переменная связывания делает что-то другое под капотом, в отличие от отправки отформатированной строки через JDBC? Есть ли другой способ обезопасить мой код без резкого снижения производительности?

1 Ответ

0 голосов
/ 30 октября 2019

Вы должны проверить, что на самом деле происходит в конце базы данных, с помощью плана showplan / плана запроса, но использование предложения «in» в лучшем случае обычно выполняет поиск по одному индексу для каждого значения в предложении «in», поэтому 10 значений - десятьпоиски, 80 тысяч запросов делает 80 тысяч из них и, следовательно, значительно медленнее. На самом деле Oracle запрещает помещать более 1000 значений в предложении «in», а Sybase не настолько ограничен, что не означает, что это хорошая идея. Вы рискуете стеком и другими проблемами в своей базе данных, помещая огромное количество значений таким образом. Я видел, как такой запрос извлекает экземпляр производственной базы данных с ошибкой стека.

Гораздо лучше создать временную таблицузагрузите туда значения 80k и выполните внутреннее соединение между временной таблицей и основной таблицей, используя столбец, который вы ранее искали с помощью предложения in.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...