ネットワーク
まず第一に、 rowidを使用してから およびrownum とにかくベンダーロックインであるため、データベースに保存されたルーチンの使用を検討する必要があります。これにより、データベースからアプリケーションサーバーにデータを送信するオーバーヘッドを大幅に削減できます(特に、それらが異なるマシン上にあり、ネットワークを介して接続されている場合)。
送信するレコードが8000万件あることを考えると、スレッドの作業の種類にもよりますが、これがパフォーマンスの向上につながる可能性があります。
明らかに、帯域幅を増やすことは、ネットワークの問題を解決するのにも役立ちます。
ディスクパフォーマンス
コードを変更する前に、タスクの実行中にハードドライブの負荷を確認してください。おそらく、それほど多くのI / Oを処理できない可能性があります(10スレッドが同時に読み取ります)。
SSD / RAIDまたはクラスタリングデータベースに移行すると、問題が解決する場合があります。データベースへのアクセス方法を変更している間は、その場合は変更されません。
マルチスレッドはCPUの問題を解決できますが、データベースは主にディスクシステムに依存しています。
Rownum
rowidとrownumを使用して実装する場合、直面する可能性のある問題がいくつかあります。
1) rownum クエリの結果ごとにオンザフライで生成されます。したがって、クエリに明示的な並べ替えがなく、クエリを実行するたびに一部のレコードの行番号が異なる可能性がある場合。
たとえば、初めて実行すると、次のような結果が得られます。
some_column | rownum
____________|________
A | 1
B | 2
C | 3
次に、2回目に実行します。明示的な並べ替えがないため、dbms(何らかの理由でそれ自体が認識されている)は次のような結果を返すことにします。
some_column | rownum
____________|________
C | 1
A | 2
B | 3
2)ポイント1は、 rownumで結果をフィルタリングする場合も意味します。 ALLの一時テーブルが生成されます 結果をフィルタリングしてから
つまりrownum 結果を分割するのに適した選択ではありません。 rowid 良さそうですが、いくつかの問題もあります。
Rowid
ROWIDの説明 を見ると 「rowid値はデータベースの行を一意に識別します。 "。
そのため、行を削除するとROWIDシーケンスに「穴」ができ、ROWIDがテーブルレコード間で均等に分散されない場合があります。
したがって、たとえば、3つのスレッドがあり、それぞれが1'000'000のROWIDをフェッチしている場合、1つは1'000'000レコードを取得し、他の2つはそれぞれ1レコードを取得する可能性があります。したがって、1つは圧倒され、他の2つは飢えている 。
あなたの場合は大したことではないかもしれませんが、主キーパターンで現在直面している問題である可能性は十分にあります。
または、最初にディスパッチャですべてのROWIDをフェッチしてから、それらを均等に分割すると(peter.petrovが提案したように)、8000万のIDをフェッチすることはまだ多くのように聞こえますが、1つで分割する方が良いと思います。チャンクの境界を返すsql-query。
または、タスクごとに少量のROWIDを指定し、Java 7で導入されたFork-Joinフレームワークを使用することで、この問題を解決することもできますが、あるべき 使用済み 慎重に 。
また、明らかなポイント:rownumとrowidの両方がデータベース間で移植可能ではありません。
したがって、独自の「シャーディング」列を用意する方がはるかに優れていますが、レコードがほぼ等しいチャンクに分割されることを確認する必要があります。
また、複数のスレッドで実行する場合は、ロックモードデータベースが使用するものを確認することが重要であることにも注意してください。 、おそらくそれはすべてのアクセスに対してテーブルをロックするだけであり、マルチスレッドは無意味です。
他の人が示唆しているように、パフォーマンスが低下する主な理由を最初に見つけたほうがよいでしょう(ネットワーク、ディスク、データベースのロック、スレッドの枯渇、またはクエリが最適ではない場合は、クエリプランを確認してください)。