0

テーブルのような大きなエンティティ属性値があります。サブクエリを使用してこのテーブルからいくつかの行を選択し、行でフィルタリングしようとしました。この状況でサブクエリとメインクエリをマージしないようにするにはどうすればよいですか?

例えば:

EMP:
EMPNO | ENAME  | SAL
---------------------
1000  | KING   | 10000
1001  | BLAKE  | 7500

CREATE VIEW EAV(ID,ATTR,VALUE) AS
select empno, 'name'||ename, ename from emp -- subquery 1
union
select empno, 'sal'||ename, ename from emp -- subquery 2
union
select empno, 'mgr'||ename, ename from emp -- subquery 3

注:||enameサブクエリ 1 と 3 にフィルタ "(null is not null)" を追加して、Oracle が次のクエリを最適化するのを防ぐために追加されました。

サブクエリでは、属性「sal%」を持つすべての行を選択し、メイン クエリでフィルタリングします。

select *
FROM (select id,value from EAV where attr like 'sal%')
WHERE to_number(value) > 5000;

このクエリ フォールにより、オプティマイザはサブクエリを外部クエリとマージします。DB をマージした後、列「値」のすべての値に to_number を適用しようとしましたが、その一部に文字列値が含まれています。魔女のヒントは、この最適化を妨げますか?

psと同じ結果を得たい

WITH t as (
   select /*+ materialize */ id,value
   from eav
   where attr like 'sal%') 
select * from t where to_number(value) > 5000;

ただし、CTEなし。

4

2 に答える 2

1

ROWNUMオプティマイザの変換を防ぎ、型の安全性を確保する最も安全な方法です。を使用ROWNUMすると、オラクルは行の順序が重要であると考え、述語のプッシュやビューのマージなどを防ぎます。

select *
from
(
   select id, value, rownum --Add ROWNUM for type safety.
   from eav
   where attr like 'sal%' 
)
where to_number(value) > 5000;

これを行う方法は他にもありますが、どれも信頼できません。CASE単純なインライン ビュー、一般的なテーブル式、述語の順序付け、またはヒントを気にしないでください。これらの一般的な方法は信頼性が低く、すべて失敗するのを見てきました。


最良の長期的な解決策は、この回答で説明するように、EAV テーブルを変更して、タイプごとに異なる列を持つことです。今すぐこれを修正しないと、将来の開発者が型エラーを避けるために複雑なクエリを書かなければならないときにあなたの名前を呪うでしょう.

于 2016-05-24T23:04:03.480 に答える
0

あなたの問題が本当にオプティマイザと関係があるとは思えません。少なくともあなたの例では、3 つの属性すべてで VALUE が ENAME に設定されています。「name」属性については問題ありませんが、「sal」についてはおそらく SAL にする必要があります。「mgr」については、あなたの例では十分な情報が得られないため、手がかりがありません。

オプティマイザが問題ではないという前提で、「||ename」の部分を削除することもお勧めします。

最後に、EMPNO が EMP の主キーである場合は、UNION を UNION ALL に変更します。UNION は、結果を一意の行に削減しようとしますが、ID、ATTR で既に一意である場合、これは不要な処理です。

ビューを作り直してから、「select * from EAV where ATTR = 'sal'」を選択し、表示されているものが実際に給与であることを確認します。これにより、問題なく sal に対して to_number(ATTR) を実行できるようになります。

于 2016-05-24T22:18:47.927 に答える