Лучший способ выбрать из миллионов строк в базе данных Oracle

Доброго времени суток!

У меня есть миллион разных слов, которые я хотел бы запросить в таблице с 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));
}
...

Это невероятно медленно. Какой самый быстрый способ делать подобные вещи?

Ваше здоровье, Крис

Полагаю, у вас есть указатель на столбец слов?

JeeBee 12.11.2008 18:58

Да, в столбце слов есть указатель.

chris 12.11.2008 19:01
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
3
2
5 930
7
Перейти к ответу Данный вопрос помечен как решенный

Ответы 7

Ответ принят как подходящий

Две идеи:

а) Как насчет того, чтобы сделать это одним запросом:

select synonym from table where word in (select distinct word from table)

б) Или, если ваш метод process должен обрабатывать их как набор синонимов одного слова, почему бы не отсортировать их по word и не запускать process заново каждый раз, когда word отличается? Этот запрос будет:

select word, synonym 
from table 
order by word

Я уточнил свой вопрос. Обработка должна происходить после каждого слова.

chris 12.11.2008 19:05

Это вернет все синонимы в том порядке, в котором они появляются в исходной таблице. Он также не вернет сами слова. «In (выбрать отдельное слово из таблицы)» будет действовать только как замедление.

configurator 12.11.2008 19:06

У меня есть два варианта. Я добавил запрос для варианта b

sblundy 12.11.2008 19:10

Второй момент именно так! Иногда я просто не могу найти простейшего решения. конфигуратор также упомянул об этом, но вы предоставили код. Это может быть проще для других, поэтому: принято и проголосовать за обоих;) Ура

chris 12.11.2008 19:20

Просто хотел отметить, что выполнение сортировки по 15 миллионам строк займет некоторое время. Лучше кофе готов =)

Maxam 12.11.2008 19:46

в зависимости от индексации, на самом деле сортировка может занять мало времени или вообще не потребоваться.

John Gardner 12.11.2008 22:48
  1. Убедитесь, что в столбце "слово" есть указатель.

  2. Переместите второй prepareStatement за пределы цикла слов. Каждый раз, когда вы создаете новый оператор, база данных компилирует и оптимизирует запрос, но в этом случае запрос тот же, поэтому в этом нет необходимости.

  3. Объедините утверждения, как это сделал бледный выше.

Почему вы запрашиваете синонимы внутри цикла, если вы все равно запрашиваете их все? Вы должны использовать один 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 [вместо того, чтобы захватывать их по одной, что является наихудшим сценарием для такого типа операции пакетной обработки]. Это повысит скорость вашей программы. Вам также следует подумать о рефакторинге и пакетной обработке ваших слов / синонимов, так как

  1. получить 1
  2. процесс 1
  3. повторить

медленнее, чем

  1. получить 50/100/1000
  2. процесс 50/100/1000
  3. повторить

просто удерживайте 50/100/1000 [или столько, сколько вы получите сразу] в некоторой структуре массива, пока вы их не обработаете.

Другие вопросы по теме