2 つの ODT をくらべてみる (SQL 文生成編)

検証環境 自作マシン(Core2QuadQ9400 2.66GHz/4GB)

Windows7 Ultimate(6.1.7600) – x86
VisualStudio2008Pro(VB) 9.0.30729.1SP/.NET Framework 3.5SP1
Oracle Database 11g 11.1.0.6.0
Oracle Developer Tools for Visual Studio 11.1.0.7.20

Windows XP Professional SP3
VisualStudio2008Pro(VB) 9.0.21022.8/.NET Framework 3.5SP1
Oracle Developer Tools for Visual Studio.NET 11.1.0.6.20

ということで Oracle Developer Tools for Visual Studio (以下 ODT) の 11.1.0.6.21 (旧版)と 11.1.0.7.20 (新版)を比較するシリーズはまだ続くわけですが。
ネタはいろいろたまってきているんですが、なかなか検証と文章起こしの時間を作ることができませんとほほ。

ので申し訳ありませんが、しばらくポイントだけ押さえて手早くまとめていきたいと思います。

今回は、新版・旧版で、デザイナから作成される SQL 文に違いはあるか?という観点からひとつ。


 手順はともかく、11.1.0.6.21 (旧版)で 2 つのテーブルを単純に結合すると、こんな感じになります。

 

SELECT TBL_PARENT.ID, TBL_PARENT.STR_HAN, TBL_PARENT.STR_ZEN,
       TBL_PARENT.ADD_FIELD, TBL_PARENT.IDX_C1, TBL_PARENT.IDX_C2,
       TBL_PARENT.NUM_P, TBL_CHILD1.STR_HAN AS EXPR1
FROM   TBL_PARENT LEFT OUTER JOIN
       TBL_CHILD1 ON TBL_PARENT.IDX_C1 = TBL_CHILD1.IDX

同じことを 11.1.0.7.20 (新版)でやると、

SELECT TBL_PARENT.ID, TBL_PARENT.STR_HAN, TBL_PARENT.STR_ZEN,
       TBL_PARENT.ADD_FIELD,
       TBL_PARENT.IDX_C1, TBL_PARENT.IDX_C2, TBL_PARENT.NUM_P,
       TBL_CHILD1.STR_HAN AS EXPR1
FROM   TBL_PARENT, TBL_CHILD1
WHERE  TBL_PARENT.IDX_C1 = TBL_CHILD1.IDX (+)

…あらまあ。11.1.0.6.21 が JOIN で結合しているのに対して、11.1.0.7.20 は WHERE で結合しています。
古い世代の私としては WHERE でなんでもかんでも書いちゃった方がピンと来はしますが、メタ的な文法解析としてはちょっとキビシいんではないでしょうか。

ということで、もうちょい解析しにくそうな例でも一度試してみます。

SELECT TBL_PARENT.ID, TBL_PARENT.STR_HAN, TBL_PARENT.STR_ZEN,
       TBL_PARENT.ADD_FIELD, TBL_PARENT.IDX_C1, TBL_PARENT.IDX_C2,
       TBL_PARENT.NUM_P, TBL_CHILD2.STR_ZEN AS EXPR1
FROM   TBL_PARENT LEFT OUTER JOIN
       TBL_CHILD2 ON TBL_PARENT.IDX_C1 = TBL_CHILD2.IDX_C1 AND
       TBL_PARENT.IDX_C2 = TBL_CHILD2.IDX_C2

といっても、結合に使う項目を 2 つに増やしただけなんですが。

同じことを 11.1.0.7.20 でやると、

SELECT TBL_PARENT.ID, TBL_PARENT.STR_HAN, TBL_PARENT.STR_ZEN,
       TBL_PARENT.ADD_FIELD,
       TBL_PARENT.IDX_C1, TBL_PARENT.IDX_C2, TBL_PARENT.NUM_P,
       TBL_CHILD2.STR_ZEN AS EXPR1
FROM   TBL_PARENT, TBL_CHILD2
WHERE  TBL_PARENT.IDX_C1 = TBL_CHILD2.IDX_C1 (+)
  AND  TBL_PARENT.IDX_C2 = TBL_CHILD2.IDX_C2 (+)

… SQL 文を生成するところまではよかったんですが、その後ウィザードを進めていくと、「生成するメソッドの選択」画面で超長考、数十分考え込んでから 落ちました。

これはひどい。

同じ手順を何度繰り返しても、やはり長考の末落ちます。
では、ということで、「SQL ステートメントの入力」画面で[次へ]ではなく[完了]を押してみると、今度はほどなく終了しました。

しかしその後、完了したテーブルアダプタを再度クエリビルダで開いてみると、

ダイアグラムペインが「2 つの項目で結合」ではなく、「1 つめの項目だけで結合し、もうひと項目はフィルタリング(抽出条件)」という状態になってしまっていました。
SQL ペインの WHERE 句も、2 つめの結合条件が無意味に「( )」で括られてしまっています。
これ、もう少し複雑な結合条件を記述した場合に変な括りでカッコ入れられて、判断の優先順位が変わってしまいそうで大変不安です。


条件を変えながら何度もやってみると、おぼろげながら落ちる条件がわかってきました。

  1. サーバーエクスプローラからメインとなるテーブルをデータセットデザイナウィンドウにドラッグ & ドロップして、テーブルアダプタを生成する。
  2. 1. で生成したテーブルアダプタを右クリック → [構成]で TableAdapter 構成ウィザードを開き、クエリビルダを呼び出す。
  3. クエリビルダ上でサブテーブルを追加し、複数の外部結合条件を設定する。
  4. クエリビルダを[OK]で完了し、[次へ] → [次へ]で最終画面まで進む。

私の環境では、この手順で必ず落ちました。

この手順で進むと、「生成するメソッドの選択」画面で「更新を直接データベースに送信するためのメソッドを作成する」にチェックが入った状態になるんですが、どうもこのチェックが入っているとダメなようです。

実際、外部結合が含まれている SQL 文で更新なんかできるわけがありません。
(内部結合に限った SQL 文でも、通常は更新なんかかけません。トラブった時の原因の切り分けが非常にしにくいので、トランザクションで囲って単テーブル単位で更新をかけるのがセオリーです。)
ので、落ちずに最後まで完了できた場合には更新系(Insert / Update /Delete)の SQL 文は生成されないようになっているんですが、このチェックが入っていると、スルーするロジックがうまく働かないようです。

サーバーエクスプローラからのドラッグ & ドロップではなく、デザイナウィンドウ右クリック → [追加] → [TableAdapter]で TableAdapter 構成ウィザードを起動して一気に外部結合 SQL 文を生成する(ただしサブテーブル側から 1 項目以上を選択している場合に限る)、内部結合 SQL 文を生成する 等をした場合は、クエリビルダから戻って TableAdapter 構成ウィザードを進めた時に、「更新を直接~」チェックボックスは使用不可になっており、そもそもチェックをつけることができないようになっています。

また、TableAdapter 構成ウィザードで直接新規生成する場合でも、サブテーブルを外部結合させて、しかもサブテーブル側の項目をひとつも指定しない(何のために結合かけているのかわかりませんが)という構成だと、「更新を直接~」チェックボックスはチェック付いたまま有効な状態になっています。
この状態で無理無理先に進めると、時間はかかるものの正常に更新系がスルーされて完了してみたり、Insert 文や Delete 文の生成に失敗したというアラーム付きで完了してみたり、ほんとに不安定で思うような再現もできないような結果がぼこぼこ出てきたり。


とりあえずあまりにも動作が不安定なので、上記不具合はあるいは私の環境だけなのかもしれません。
また、通常複数テーブルを結合かけた状態で更新系の SQL 文を発行させる方が通常の仕様の範疇には入っていないのかもしれません。

がまあ、11.1.0.7.20 は操作を間違っちゃうとなかなかおっかない動作になってしまうという不安定さを持っていると思っておいた方がいいように思います。

ちなみに 11.1.0.6.21 もけっこう長考しますが、最終的には更新系の SQL 文をスルーした結果で完了しますので、こちらの方が安定感はいい感じです。

つことで複数テーブルを結合した SQL 文を生成する場合は、

「SQL ステートメントの入力」画面から[詳細オプション] →「詳細設定」ダイアログで「INSERT、UPDATE、および DETETE ステートメントの生成」チェックを絶対に事前に外しておく ことを心がけましょう、と。

なんだか嫌なところに地雷があるような気がするんですがねえ。

コメントを投稿