Лучший способ выбрать из миллионов строк в базе данных Oracle - PullRequest
3 голосов
/ 12 ноября 2008

G'day!

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

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

Cheers, Chris

Ответы [ 7 ]

5 голосов
/ 12 ноября 2008
  1. Убедитесь, что в столбце «слово» есть индекс.

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

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

4 голосов
/ 12 ноября 2008

Две идеи:

а) Как насчет одного запроса:

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

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

select word, synonym 
from table 
order by word
3 голосов
/ 12 ноября 2008

Почему вы запрашиваете синонимы внутри цикла, если все равно запрашиваете их все? Вы должны использовать один select word, synonym from table order by word, а затем разделить по словам в коде Java.

1 голос
/ 30 апреля 2009

Вам также следует рассмотреть возможность использования метода setFetchSize объекта оператора, чтобы уменьшить переключение контекста между вашим приложением и базой данных. Если вы знаете, что собираетесь обработать миллион записей, вам следует использовать setFetchSize (someRelativelyHighNumberLike1000). Это говорит java собирать до 1000 записей каждый раз, когда ей нужно больше от Oracle [вместо того, чтобы получать их по одной за раз, что является наихудшим сценарием для такой операции пакетной обработки]. Это улучшит скорость вашей программы. Вы также должны рассмотреть возможность рефакторинга и выполнения пакетной обработки ваших слов / синонимов, как

  1. выборка 1
  2. процесс 1
  3. повтор

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

  1. выборка 50/100/1000
  2. процесс 50/100/1000
  3. повтор

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

1 голос
/ 12 ноября 2008

связанных, но не связанных:

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));
}

Весь смысл подготовки оператора состоит в том, что БД должна скомпилировать / кэшировать / и т. Д., Поскольку вы собираетесь использовать этот оператор несколько раз. Вам также может понадобиться явно очистить наборы результатов, если вы собираетесь выполнять такое количество запросов, чтобы гарантировать, что у вас не закончатся курсоры.

1 голос
/ 12 ноября 2008
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);
0 голосов
/ 12 ноября 2008

Проблема решена. Важным моментом является то, что таблица может быть отсортирована по слову. Поэтому я могу легко перебрать всю таблицу. Как это:

....
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));
}
...
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...