15

Oracle 12c で欠落しているデータに関する問題が発生しました。

コードを調べたところ、mysql、mssql、oracle 11g では動作するが、oracle 12c では動作が異なるクエリが見つかりました。

テーブル構造とクエリをある程度一般化し、問題を再現しました。

create table thing (thing_id number, display_name varchar2(500));
create table thing_related (related_id number, thing_id number, thing_type varchar2(500));
create table type_a_status (related_id number, status varchar2(500));
create table type_b_status (related_id number, status varchar2(500));

insert into thing values (1, 'first');
insert into thing values (2, 'second');
insert into thing values (3, 'third');
insert into thing values (4, 'fourth');
insert into thing values (5, 'fifth');
insert into thing_related values (101, 1, 'TypeA');
insert into thing_related values (102, 2, 'TypeB');
insert into thing_related values (103, 3, 'TypeB');
insert into thing_related (related_id, thing_id) values (104, 4);

insert into type_a_status values (101, 'OK');
insert into type_b_status values (102, 'OK');
insert into type_b_status values (103, 'NOT OK');

クエリの実行:

SELECT t.thing_id AS id, t.display_name as name,
       tas.status as type_a_status,
       tbs.status as type_b_status
FROM thing t LEFT JOIN thing_related tr 
  ON t.thing_id = tr.thing_id
LEFT JOIN type_a_status tas 
  ON (tr.related_id IS NOT NULL 
      AND tr.thing_type = 'TypeA' 
      AND tr.related_id = tas.related_id)
LEFT JOIN type_b_status tbs 
  ON (tr.related_id IS NOT NULL 
      AND tr.thing_type = 'TypeB' 
      AND tr.related_id = tbs.related_id)

Oracle 11g では次のようになります (これはSQL Fiddleです):

ID | NAME   | TYPE_A_STATUS | TYPE_B_STATUS
 1 | first  |            OK | (null)
 2 | second |        (null) | OK
 3 | third  |        (null) | NOT OK
 4 | fourth |        (null) | (null)
 5 | fifth  |        (null) | (null)

Oracle 12c での同じスキーマ、データ、およびクエリ:

ID | NAME   | TYPE_A_STATUS | TYPE_B_STATUS
 1 | first  |            OK | (null)
 2 | second |        (null) | OK
 3 | third  |        (null) | NOT OK
 4 | fourth |        (null) | (null)

'thing_related' に結合する行がないため、2 番目の 2 つの外部結合では何も返されていないようです。ただし、この場合、Oracle 11g、Mysqlなどのように、外部結合がnullを返さない理由がわかりません.

私は調査を行っており、Oracle 12c には外部結合の多くの機能強化があったドキュメントを見つけましたが、これに影響を与える変更を強調するものはありませんでした。

これがOracle 12cでのみ発生する理由を知っている人はいますか?12cで動作し、11g、mysqlなどとの互換性を維持するには、これをどのように書き直すのが最善でしょうか?

編集:添付の計画。

オラクル 11g:

ここに画像の説明を入力

オラクル 12c:

ここに画像の説明を入力

4

3 に答える 3

12

更新:これは 12.1.0.2 で修正されています。


これは明らかに 12.1.0.1 のバグのようです。Oracle サポートを通じてサービス リクエストを作成することをお勧めします。彼らは修正またはより良い回避策を見つけることができるかもしれません. そして、うまくいけば、オラクルが将来のバージョンですべての人のために修正できることを願っています. 通常、サポートとの連携で最悪の部分は、問題を再現することです。しかし、すでに非常に優れたテスト ケースがあるため、この問題は簡単に解決できる可能性があります。

このバグを回避するには、おそらく多くの方法があります。しかし、どの方法が常に機能するかを判断するのは困難です。クエリの再書き込みは現在機能している可能性がありますが、オプティマイザーの統計が変更された場合、将来的に計画が変更される可能性があります。

12.1.0.1.0 で機能する別のオプションは次のとおりです。

ALTER SESSION SET optimizer_features_enable='11.2.0.3';

ただし、クエリを実行する前に常にこの設定を変更し、後で「12.1.0.1」に戻すことを忘れないでください。などのクエリ ヒント内に埋め込む方法があります/*+ OPT_PARAM('optimizer_features_enable' '11.2.0.3') */。しかし、何らかの理由で、ここでは機能しません。または、システム全体に対して一時的に設定し、修正またはより良い回避策が利用可能になった後に元に戻すことができます。

どのソリューションを使用する場合でも、それを文書化することを忘れないでください。クエリが奇妙に見える場合、次の開発者がそれを「修正」しようとして、同じ問題に遭遇する可能性があります。

于 2013-10-31T06:12:49.800 に答える
4

参照する:

12.1.0.1 へのアップグレード後に ANSI 外部結合クエリが間違った結果を返す (Doc ID 1957943.1)

未公開のバグ 16726638

12.1.0.2 で修正済み (テスト済み)

回避策 (12.1.0.1 でテストしました):

alter session set "_optimizer_ansi_rearchitecture"=false;          

注 1957943.1 では、代替として次のことを推奨しています。

optimizer_features_enable = '11.2.0.4';

しかし、それは機能しませ

于 2015-02-14T20:16:44.030 に答える