DBD::Oracle に激遅のコードが混在している件について
えーっと、ここ数日やっている DBIx::Class 関連なんですが、DBIx::Class::Schema::Loader::Oracle を作ってみたものの、Oracle の場合、なぜか _load_relationships が異常に遅いんですよ。でかなり深追いしてみました。
DBIx::Class::Schema::Loader::Base->_load_relationships あたりが遅いのでメソッドコールを深追い
↓
DBIx::Class::Storage::DBI->columns_info_for の $dbh->column_info そのものが遅いことを突き止める。
my $sth = $dbh->column_info( undef, undef, $table, '%' );
$sth->execute();
while ( my $info = $sth->fetchrow_hashref() ){
・・・
$dbh->column_info つまりは、DBD::Oracle->column_info が原因って事で、まさかの DBD::Oracle を除いてみることに。
DBD::Oracle の解析
DBD::Oracle にデバッグ情報をいれつつ、生成された SQL をみてみた。。。 LIKE 文がすごーく非効率的につかわれてます。まずは結論。修正した Oracle.pm との差分は下記の通り。
diff Oracle.pm Oracle.pm.org
371,372c371,372
< if ( defined $SchVal && $SchVal ne '%' ) {
< push @Where, ($SchVal =~ /%/) ? "TABLE_SCHEM LIKE '$SchVal' ESCAPE '\\'" : "TABLE_SCHEM = '$SchVal'";
---
> if ( defined $SchVal ) {
> push @Where, "TABLE_SCHEM LIKE '$SchVal' ESCAPE '\\'";
374,375c374,375
< if ( defined $TblVal && $TblVal ne '%' ) {
< push @Where, ($TblVal =~ /%/) ? "TABLE_NAME LIKE '$TblVal' ESCAPE '\\'" : "TABLE_NAME = '$TblVal'";
---
> if ( defined $TblVal ) {
> push @Where, "TABLE_NAME LIKE '$TblVal' ESCAPE '\\'";
621,622c621,622
< if( $v && $v ne '%' ) {
< $Sql .= ($v =~ /%/) ? " AND $k LIKE ? ESCAPE '\\'\n" : " AND $k = ?\n";
---
> if ( $v ) {
> $Sql .= " AND $k LIKE ? ESCAPE '\\'\n";
627d626
< warn "DBD::Oracle->@BindVals\n$Sql\n";
で、説明。まずオリジナルのコードは条件文をすべて LIKE 文で生成しようとします。たとえば、
他の例もあげますと、
まぁ要するに、インデックスを使わない SQL を生成する作りになっていたので激遅だったわけです。もっとも普段は column_info メソッドなんて使わないから効率を考えて無かったんだろうなぁ〜と思ったり。改造版はかなり高速になります。
それともう一つ猛烈に気になるのが
ってところ。近頃の Oracle はコストベースがデフォルトになってるにも関わらずルールベースで SQL を解析しろと Hint 句を使ってます。うーんうーん・・・微妙だなぁ・・・この Hint 句とっちゃう??
一応、改造した Oracle.pm を公開しておきます。何かのお役に立てればと。。。
ダウンロードはこちら → DBD::Oracle-1.17a.pm


コメントやシェアをお願いします!