在Oracle DB中选择数百万行的最佳方法

时间:2008-11-12 15:55:34

标签: java sql oracle select

天儿真好!

我有一百万个不同的单词,我想在一个有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));
}
...

这令人难以置信的缓慢。做这样的事情的最快方法是什么?

干杯, 克里斯

7 个答案:

答案 0 :(得分:5)

  1. 确保'word'列上有索引。

  2. 将第二个prepareStatement移到word循环之外。每次创建新语句时,数据库都会编译并优化查询 - 但在这种情况下查询是相同的,所以这是不必要的。

  3. 将上述sblundy的陈述合并完成。

答案 1 :(得分:4)

两个想法:

a)如何制作一个查询:

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

b)或者,如果您process方法需要将它们作为一个单词的一组同义词来处理,为什么不按word对它们进行排序并每次重新开始process { {1}}有什么不同?该查询将是:

word

答案 2 :(得分:3)

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

答案 3 :(得分: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);

答案 4 :(得分: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));
}

你应该在循环之外移动预先初始化调用:

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,因为你将重复使用该语句。如果要进行那么多查询,也可能需要明确地清理结果集,以确保不会耗尽游标。

答案 5 :(得分:1)

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

  1. fetch 1
  2. 流程1
  3. 重复
  4. 慢于

    1. 获取50/100/1000
    2. 流程50/100/1000
    3. 重复
    4. 在某个数组结构中按住50/100/1000 [或者一次检索多少],直到你处理它们为止。

答案 6 :(得分: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));
}
...