1

Oracle Database 11g Release 11.2.0.2.0 - 64bit Production/ を実行しています。

user、user_learning、および user_group テーブル間の結合である次のクエリがあります。

select u.user_id, u.first_name, u.surname, u.client_company_id, u.username,   
       ul.completion_status 
from user u, user_learning ul 
where 
      u.user_id = ul.user_id (+) 
  and (ul.enrolment_status = 'E'   or ul.enrolment_status is null) 
  and upper(u.surname) like 'CART%'
  and ((u.user_id is not null  and (u.client_company_id in ('ABCDEF') )  
       and exists (select 1 
                   from user_group g
                   where g.user_id = u.user_id 
                     and g.group_id in  
                         (215479,215480,221934,39901,45709,45710,45712,
                         45713,45714,45715,45716,45717,45718)
                   ) 
       ) 
       or (u.user_id = 1209289 or u.manager_id = 1209289)
      )
  order by u.client_company_id, u.surname, u.first_name, u.user_id;

このクエリは、交互に実行されるたびに 0 の結果と 198 を返し、時には 0 などを返します。

テーブルとこれまでに試したことに関する背景情報

-- Gives 1184415 records
select count(1) from user; 

-- Gives 7789332 records
select count(1) from user_learning; 

-- Gives 3278032
select count(1) from user_group; 

次のように、user テーブルの列 surname にインデックスがあります。

私たちが気づいたことは、IDX_USER_UPPER インデックスを削除してクエリを実行すると、結果が常に一貫していることです。しかし、インデックスを持つということは、しばらくすると結果が同じではないことを意味します。インデックスに疑いがあり、それを削除してクエリを実行すると一貫した結果が得られたように見えましたが、それはしばらくするとクエリが一貫した結果を返さなくなりました。'CART%' のようなアッパー (u.surname) を 'CAR%' や 'CARTE%' などに変更します...その後、0 以上のレコードなどを与える奇妙な動作をゆっくりと開始します.

説明計画は、インデックスが使用される場合と使用されない場合があることを示しています..おそらく、このインデックスは問題ではありません...??

インデックスの統計を収集し、インデックスを再構築しようとしました

CREATE INDEX IDX_USER_UPPER ON USER (UPPER("SURNAME")) 
alter index IDX_USER_UPPER compute statistics
alter index IDX_USER_UPPER rebuild 

以下も実行しましたが、インデックスが削除された場合を除いて同じ効果があり、しばらくは機能しているようです。

exec DBMS_STATS.gather_table_stats('SCHEMA', 'USER');
exec DBMS_STATS.gather_table_stats('SCHEMA', 'USER_LEARNING');
exec DBMS_STATS.gather_table_stats('SCHEMA', 'USER_GROUP');

exec DBMS_STATS.GATHER_INDEX_STATS ( 'SCHEMA', 'IDX_USER_UPPER');
-- note SCHEMA is our schema name

-- indicates Last_analysed is updated ...
select table_name, owner, to_char(last_analyzed, 'dd-mon-yyyy hh24:mi:ss') 
from   dba_tables 
where table_name IN ('USER', 'USER_LEARNING', 'USER_GROUP')

私が試した別のオプションは、次のように「_no_or_expansion」フラグを設定することです。

alter session set "_no_or_expansion"=true;
-- no impact to the query though

(インデックスが削除されたときに、「CAR%」、「CART%」、「CARTE%」、「CARTER%」がクエリされたときに、クエリが一貫したデータを返し続けるように見えることがあります-奇妙な)

それでも奇妙な動作が存在します。考え、質問、または解決策があります。これに似たものに遭遇した人は、どうぞ。


select * from dba_autotask_client を実行すると、
自動オプティマイザの統計収集 が有効になっていることが表示されます

4

4 に答える 4

1

バグのある動作のように聞こえますが、非決定論的な動作を伴うビュー/関数を使用しないように十分注意してください (つまり、何らかの方法でステートフルであるため、常に同じ入力で同じ回答を返すとは限りません)。

あなたのクエリが使用している実行計画を見てみましょう。異なる実行計画が使用されている可能性があり、計画によって異なる結果が得られる可能性があります。あなたが混乱してクエリが非決定的でない限り、彼らはそうすべきではありませんが、もしそうなら、これを突き止めてOracleに文句を言うことができます.

1つの方法は、クエリを実行してから実行することです

select * from table(dbms_xplan.display_cursor(format=>'advanced'));

これは、セッションで最後に実行されたものの実行計画を表示するはずですが、残念ながら、PL/SQL 開発者や、DBMS_OUTPUT などを取得するためにクエリをサイレントに実行するその他のツールでは機能しません (「最後の」クエリ実行あなたのセッションでは、あなたが与えたものではありません)

それ以外の場合は次のようにします

select * from v$sql where lower(sql_fulltext) like '%client_company_id%';

... クエリ テキストと非常に差別的なものを like 句に入れます。例として client_company_id を選択しましたが、それがクエリでどれほど一般的かはわかりません。いずれにせよ、少し努力すれば、クエリに対応する v$sql の行を確認し、sql_id を見つけることができるはずです。これは sql テキストのハッシュであるため、同じクエリ テキスト (空白などまで同じ) は常に同じ sql_id を生成します。

次に、 select * from table(dbms_xplan.display_cursor(, 0, format=>'advanced'); を実行できます。

v$sql に同じ sql_id を持つ複数の行がある場合、それはクエリに対して複数の実行計画が生成されたことを示す強力な指標です。カーソルの sql_id は同じですが、'child_number' は異なります。

select * from table(dbms_xplan.display_cursor(<sql id>, <child number>, format=>'advanced');

異なる実行計画が使用されているかどうかを確認します。特に、「メモ」セクションの「このステートメントに使用されるカーディナリティ フィードバック」または「このステートメントに使用される統計フィードバック」に注意してください。

カーディナリティ フィードバックは、オプティマイザーが実行計画の生成時に疑わしい見積もりを行っていることを認識し、実行時の動作を観察して修正係数を生成し、これをそのクエリの次の実行にプラグインして全体を生成する場合です。新しい計画。

機能するときは非常に賢いですが、頭痛の種もかなりあります。

いずれにせよ、異なる実行計画が異なる結果を生成するというバグに遭遇した場合、これは実行計画 (および結果) が実行ごとに変化する可能性がある 1 つの方法です。

UPPER(...) でインデックスを使用する「悪い」計画が含まれている場合、そのインデックスを削除すると、それらの計画が生成されなくなり、動作が再び変更されます。

于 2016-08-24T16:01:29.330 に答える
0

列パラメーターを文字列として持つ関数ベースのインデックスを見たことがありません。

CREATE INDEX IDX_USER_UPPER ON USER (UPPER("SURNAME"))

代わりにこれを試してください:

CREATE INDEX IDX_USER_UPPER ON USER (UPPER(SURNAME))
于 2015-03-11T16:48:55.157 に答える