1対多の関係を持つ2つのテーブルを作成しています。
そこで、 に行を挿入し、その行outer
の (自動インクリメント主キー)id
を取得してから、 に 100 行を挿入しますinner
(すべて外部キーが を指していますouter.id
)。
次に、50回繰り返します。のすべてのエントリに対してouter
、挿入し、読み取りid
、次に内部に挿入する必要があります。
これは遅いです。ほとんどの時間は、100 行を にロードするのに費やされinner
ます。50*100 行すべてを 1 回のバッチ操作で挿入できれば、はるかに高速になると思います。inner
しかし、それを行う方法がわかりません。どうすれば外部キーを機能させることができますか?
他の人はどのようにこれを効率的にしていますか?
Java/Spring を使用しています。100 行は . で挿入されJdbcTemplate.batchUpdate()
ます。
public final void insert(final JdbcTemplate db,
final Iterable<DataBlock> data) {
String insertSql = getInsertSql();
String idQuery = getIdQuery();
ItemRowMapper.IdRowMapper mapper = new ItemRowMapper.IdRowMapper();
for (DataBlock block: data) {
Object[] outer = block.getOuter();
LOG.trace("Loading outer");
db.update(insertSql, outer);
LOG.trace("Getting index");
// currently retrieve index based on natural key, but could use last index
int id = db.query(idQuery, mapper, uniqueData(outer)).get(0);
LOG.trace("Getting inner");
List<Object[]> inner = block.getInner(id);
// most time spent here
LOG.trace(format("Loading inner (%d)", inner.size()));
innerTable.insert(db, inner);
}
}
および疑似 SQL:
create table outer (
integer id primary key autoincrement,
...
);
create table inner (
integer outer references outer(id),
...
);
更新- 以下は、Spring 3.1.1 および Postgres 9.2-1003.jdbc4 で動作するようです。
/**
* An alternative implementation that should be faster, since it inserts
* in just two batches (one for inner and one fo router).
*
* @param db A connection to the database.
* @param data The data to insert.
*/
public final void insertBatchier(final JdbcTemplate db,
final AllDataBlocks data) {
final List<Object[]> outers = data.getOuter();
List<Integer> ids = db.execute(
new PreparedStatementCreator() {
@Override
public PreparedStatement createPreparedStatement(
final Connection con) throws SQLException {
return con.prepareStatement(getInsertSql(),
Statement.RETURN_GENERATED_KEYS);
}
},
new PreparedStatementCallback<List<Integer>>() {
@Override
public List<Integer> doInPreparedStatement(final PreparedStatement ps)
throws SQLException {
for (Object[] outer: outers) {
for (int i = 0; i < outer.length; ++i) {
setParameterValue(ps, i + 1,
SqlTypeValue.TYPE_UNKNOWN, outer[i]);
}
ps.addBatch();
}
ps.executeBatch();
RowMapperResultSetExtractor<Integer> ids =
new RowMapperResultSetExtractor<Integer>(
new ItemRowMapper.IdRowMapper());
try (ResultSet keys = ps.getGeneratedKeys()) {
return ids.extractData(keys);
}
}
});
innerTable.insert(db, data.getInner(ids));
}