Доброго времени суток!
У меня есть миллион разных слов, которые я хотел бы запросить в таблице с 15 миллионами строк. Результат синонимов вместе со словом обрабатывается после каждого запроса.
таблица выглядит так:
synonym word
---------------------
ancient old
anile old
centenarian old
darkened old
distant far
remote far
calm gentle
quite gentle
Вот как это сейчас делается в Java:
....
PreparedStatement stmt;
ResultSet wordList;
ResultSet syns;
...
stmt = conn.prepareStatement("select distinct word from table");
wordList = stmt.executeQuery();
while (wordList.next()) {
stmt = conn.prepareStatement("select synonym from table where word=?");
stmt.setString(1, wordList.getString(1));
syns = stmt.executeQuery();
process(syns, wordList.getString(1));
}
...
Это невероятно медленно. Какой самый быстрый способ делать подобные вещи?
Ваше здоровье, Крис
Да, в столбце слов есть указатель.




Две идеи:
а) Как насчет того, чтобы сделать это одним запросом:
select synonym from table where word in (select distinct word from table)
б) Или, если ваш метод process должен обрабатывать их как набор синонимов одного слова, почему бы не отсортировать их по word и не запускать process заново каждый раз, когда word отличается? Этот запрос будет:
select word, synonym
from table
order by word
Я уточнил свой вопрос. Обработка должна происходить после каждого слова.
Это вернет все синонимы в том порядке, в котором они появляются в исходной таблице. Он также не вернет сами слова. «In (выбрать отдельное слово из таблицы)» будет действовать только как замедление.
У меня есть два варианта. Я добавил запрос для варианта b
Второй момент именно так! Иногда я просто не могу найти простейшего решения. конфигуратор также упомянул об этом, но вы предоставили код. Это может быть проще для других, поэтому: принято и проголосовать за обоих;) Ура
Просто хотел отметить, что выполнение сортировки по 15 миллионам строк займет некоторое время. Лучше кофе готов =)
в зависимости от индексации, на самом деле сортировка может занять мало времени или вообще не потребоваться.
Убедитесь, что в столбце "слово" есть указатель.
Переместите второй prepareStatement за пределы цикла слов. Каждый раз, когда вы создаете новый оператор, база данных компилирует и оптимизирует запрос, но в этом случае запрос тот же, поэтому в этом нет необходимости.
Объедините утверждения, как это сделал бледный выше.
Почему вы запрашиваете синонимы внутри цикла, если вы все равно запрашиваете их все? Вы должны использовать один select word, synonym from table order by word, а затем разбить его по словам в коде Java.
PreparedStatement stmt;
ResultSet syns;
...
stmt = conn.prepareStatement("select distinct " +
" sy.synonm " +
"from " +
" table sy " +
" table wd " +
"where sy.word = wd.word");
syns = stmt.executeQuery();
process(syns);
Проблема решена. Важным моментом является то, что таблицу можно сортировать по словам. Поэтому я могу легко перебирать всю таблицу. Нравится:
....
Statement stmt;
ResultSet rs;
String currentWord;
HashSet<String> syns = new HashSet<String>();
...
stmt = conn.createStatement();
rs = stmt.executeQuery(select word, synonym from table order by word);
rs.next();
currentWord = rs.getString(1);
syns.add(rs.getString(2));
while (rs.next()) {
if (rs.getString(1) != currentWord) {
process(syns, currentWord);
syns.clear();
currentWord = rs.getString(1);
}
syns.add(rs.getString(2));
}
...
связанные, но не связанные:
while (wordList.next()) {
stmt = conn.prepareStatement("select synonym from table where word=?");
stmt.setString(1, wordList.getString(1));
syns = stmt.executeQuery();
process(syns, wordList.getString(1));
}
Вы должны переместить этот вызов подготовительного оператора за пределы цикла:
stmt = conn.prepareStatement("select synonym from table where word=?");
while (wordList.next()) {
stmt.setString(1, wordList.getString(1));
syns = stmt.executeQuery();
process(syns, wordList.getString(1));
}
Весь смысл подготовки оператора заключается в том, чтобы база данных скомпилировала / кешировала / и т. д., Потому что вы собираетесь использовать оператор неоднократно. Вам также может потребоваться явная очистка наборов результатов, если вы собираетесь выполнять такое количество запросов, чтобы гарантировать, что у вас не закончатся курсоры.
Вам также следует рассмотреть возможность использования метода setFetchSize объекта инструкции, чтобы уменьшить переключение контекста между вашим приложением и базой данных. Если вы знаете, что собираетесь обработать миллион записей, вам следует использовать setFetchSize (someRelativelyHighNumberLike1000). Это говорит java, что нужно захватывать до 1000 записей каждый раз, когда ей требуется больше от Oracle [вместо того, чтобы захватывать их по одной, что является наихудшим сценарием для такого типа операции пакетной обработки]. Это повысит скорость вашей программы. Вам также следует подумать о рефакторинге и пакетной обработке ваших слов / синонимов, так как
медленнее, чем
просто удерживайте 50/100/1000 [или столько, сколько вы получите сразу] в некоторой структуре массива, пока вы их не обработаете.
Полагаю, у вас есть указатель на столбец слов?