3

天!

我有一百万个不同的单词,我想在一个有 1500 万行的表中查询它们。同义词的结果与单词一起在每次查询后得到处理。

表如下所示:

    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. 将第二个 prepareStatement 移到单词循环之外。每次创建新语句时,数据库都会编译并优化查询——但在这种情况下,查询是相同的,因此没有必要这样做。

  3. 结合上面的sblundy所做的陈述。

于 2008-11-12T16:02:49.090 回答
4

两个想法:

a)如何使它成为一个查询:

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
于 2008-11-12T15:59:22.437 回答
3

如果您要查询所有同义词,为什么还要查询循环内的同义词?您应该使用单个select word, synonym from table order by word,然后在 Java 代码中按单词拆分。

于 2008-11-12T16:05:02.520 回答
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 回答
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));
}

准备语句的全部目的是让数据库编译/缓存/等,因为您将重复使用该语句。如果要执行这么多查询,您可能还需要显式清理结果集,以确保不会用完游标。

于 2008-11-12T19:46:30.823 回答
1

您还应该考虑利用语句对象的 setFetchSize 方法来减少应用程序和数据库之间的上下文切换。如果您知道要处理一百万条记录,则应使用 setFetchSize(someRelativelyHighNumberLike1000)。这告诉 java 每次需要从 Oracle 获取更多记录时最多抓取 1000 条记录[而不是一次抓取一条记录,这是这种批处理操作的最坏情况]。这将提高您的程序的速度。您还应该考虑对单词/同义词进行重构和批处理,如

  1. 取 1
  2. 过程1
  3. 重复

  1. 获取 50/100/1000
  2. 处理 50/100/1000
  3. 重复

只需将 50/100/1000 [或您一次检索的多个] 保存在某个数组结构中,直到您处理它们。

于 2009-04-30T13:47:35.857 回答
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 回答