3

こんにちは!

1,500 万行のテーブルでクエリしたい 100 万の異なる単語があります。単語と同義語の結果は、各クエリの後に処理されます。

テーブルは次のようになります。

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

これは信じられないほど遅いです。このようなことを行うための最速の方法は何ですか?

乾杯、クリス

4

7 に答える 7

5
  1. 「単語」列に索引があることを確認してください。

  2. 2 番目の prepareStatement を単語ループの外に移動します。新しいステートメントを作成するたびに、データベースはクエリをコンパイルして最適化しますが、この場合、クエリは同じであるため、これは不要です。

  3. 上記のsblundyが行ったように、ステートメントを結合します。

于 2008-11-12T16:02:49.090 に答える
4

2 つのアイデア:

a)1つのクエリにするのはどうですか:

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

b) または、processメソッドがそれらを 1 つの単語の同義語のセットとして処理する必要がある場合は、それらを並べ替えて、異なるたびに新たwordに開始してみませんか? そのクエリは次のようになります。processword

select word, synonym 
from table 
order by word
于 2008-11-12T15:59:22.437 に答える
3

とにかくすべてのシノニムを照会しているのに、ループ内でシノニムを照会するのはなぜですか? 単一select word, synonym from table order by wordの を使用してから、Java コードで単語ごとに分割する必要があります。

于 2008-11-12T16:05:02.520 に答える
1

また、ステートメントオブジェクトのsetFetchSizeメソッドを利用して、アプリケーションとデータベース間のコンテキストスイッチを減らすことも検討する必要があります。100万件のレコードを処理することがわかっている場合は、setFetchSize(someRelativelyHighNumberLike1000)を使用する必要があります。これにより、Javaは、Oracleからさらに必要になるたびに最大1000レコードを取得するように指示されます(この種のバッチ処理操作の最悪のシナリオである、一度に1つずつ取得するのではなく)。これにより、プログラムの速度が向上します。また、単語/類義語のリファクタリングとバッチ処理の実行も検討する必要があります。

  1. フェッチ1
  2. プロセス1
  3. 繰り返す

より遅い

  1. 50/100/1000をフェッチ
  2. プロセス50/100/1000
  3. 繰り返す

処理するまで、50/100/1000[または一度に取得する数]を配列構造に保持するだけです。

于 2009-04-30T13:47:35.857 に答える
1

関連するが無関係:

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

その preparestatement 呼び出しをループの外に移動する必要があります。

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

ステートメントを準備することの全体的なポイントは、ステートメントを繰り返し使用するため、db がコンパイル/キャッシュ/etc することです。また、カーソルが不足しないように、多数のクエリを実行する場合は、結果セットを明示的にクリーンアップする必要がある場合もあります。

于 2008-11-12T19:46:30.823 に答える
1
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);
于 2008-11-12T16:07:04.713 に答える
0

問題は解決された。重要な点は、表が単語でソートできることです。したがって、テーブル全体を簡単に反復処理できます。このような:

....
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));
}
...
于 2008-11-12T16:33:49.823 に答える