4

別のマテリアライズド・ビューに一致するレコードがあるレコードとして定義された、テーブルのサブセット(マテリアライズド・ビューとして)を作成しようとしています。

たとえば、user_id列とname列を持つUsersテーブルと、entry_id、user_id、activity、timestamp列を持つLogテーブルがあるとします。

まず、ログテーブルのマテリアライズドビューを作成し、タイムスタンプ>some_dateの行のみを選択します。ここで、ログテーブルのスナップショットで参照されているユーザーのマテリアルビューが必要です。私はそれを次のように作成することができます

select * from Users where user_id in (select user_id from Log_mview)

または私はすることができます

select distinct u.* from Users u inner join Log_mview l on u.user_id = l.user_id

(複数のログエントリを持つユーザーからの複数のヒットを回避するために、明確にする必要があります)。

前者はよりクリーンでエレガントに見えますが、はるかに時間がかかります。私は何かが足りないのですか?これを行うためのより良い方法はありますか?

編集:where exists条件が。を使用する場合を除いて、句は大いに役立ちましたOR。たとえば、上記のログテーブルにもuser_name列があり、ログエントリをUsersレコードに一致させる正しい方法は、列(ユーザーIDまたはユーザー名)のいずれかが一致する場合です。私はそれを見つけています

select distinct u.* from Users u
    inner join Log_mview l
        on u.user_id = l.user_id or u.name = l.user_name

よりもはるかに高速です

select * from Users u where exists
    (select id from Log_mview l 
        where l.user_id = u.user_id or l.user_name = u.name)

何か助けはありますか?

(説明計画に関しては...レムはそれを消毒することに取り組んでいます、あるいはそれらはむしろ...私はそれらをしばらく投稿します。)

編集:計画の説明:内部結合を使用したクエリの場合:

計画ハッシュ値:436698422

-------------------------------------------------- -------------------------------------------------- -----------
| Id | 操作| 名前| 行| バイト|TempSpc| コスト(%CPU)| 時間|
-------------------------------------------------- -------------------------------------------------- -----------
| 0 | ステートメントの選択| | 4539K | 606M | | 637K(3)| 02:07:25 |
| 1 | ハッシュユニーク| | 4539K | 606M | 3201M | 637K(3)| 02:07:25 |
| 2 | 連結| | | | | | |
| * 3 | ハッシュ結合| | 4206K | 561M | 33M | 181K(4)| 00:36:14 |
| 4 | ROWIDへのビットマップ変換| | 926K | 22M | | 2279(1)| 00:00:28 |
| 5 | BITMAP INDEX FAST FULL SCAN | I_M_LOG_MVIEW_4 | | | | | |
| * 6 | テーブルアクセスフル| ユーザー| 15M | 1630M | | 86638(6)| 00:17:20 |
| * 7 | ハッシュ結合| | 7646K | 1020M | 33M | 231K(4)| 00:46:13 |
| 8 | ROWIDへのビットマップ変換| | 926K | 22M | | 2279(1)| 00:00:28 |
| 9 | BITMAP INDEX FAST FULL SCAN | I_M_LOG_MVIEW_4 | | | | | |
| 10 | テーブルアクセスフル| ユーザー| 23M | 2515M | | 87546(7)| 00:17:31 |
-------------------------------------------------- -------------------------------------------------- -----------

述語情報(操作IDで識別):
-------------------------------------------------- -

   3-access("U"。"NAME" ="L"。"USER_NAME")
   6-filter("U"。"NAME" IS NOT NULL)
   7-access("U"。"USER_ID" = TO_NUMBER("L"。"USER_ID"))
       filter(LNNVL("U"。"NAME" ="L"。"USER_NAME")またはLNNVL("U"。"NAME" IS NOT NULL))

ノート
-----
   -このステートメントに使用される動的サンプリング

使用しているものの場合where exists

計画ハッシュ値:2786958565

-------------------------------------------------- -------------------------------------------------- -
| Id | 操作| 名前| 行| バイト| コスト(%CPU)| 時間|
-------------------------------------------------- -------------------------------------------------- -
| 0 | ステートメントの選択| | 1 | 114 | 21M(1)| 70:12:13 |
| * 1 | フィルター| | | | | |
| 2 | テーブルアクセスフル| ユーザー| 23M | 2515M | 87681(7)| 00:17:33 |
| 3 | ROWIDへのビットマップ変換| | 7062 | 179K | 1(0)| 00:00:01 |
| * 4 | BITMAP INDEX FAST FULL SCAN | I_M_LOG_MVIEW_4 | | | | |
-------------------------------------------------- -------------------------------------------------- -

述語情報(操作IDで識別):
-------------------------------------------------- -

   1-filter(EXISTS(SELECT / * + * / 0FROM"MYSCHEMA"。"LOG_MVIEW"
              "LOG_MVIEW" WHERE( "USER_NAME" =:B1 OR TO_NUMBER( "USER_ID")=:B2)AND
              ("USER_NAME" =:B3 OR TO_NUMBER( "USER_ID")=:B4)AND( "USER_NAME" =:B5 OR
              TO_NUMBER( "USER_ID")=:B6)))
   4-filter( "USER_NAME" =:B1 OR TO_NUMBER( "USER_ID")=:B2)

ノート
-----
   -このステートメントに使用される動的サンプリング

無実を保護するためにDBオブジェクト名が変更されました。:p

4

3 に答える 3

1

これを試して

select * from Users u
where exists 
   ( select user_id 
     from Log_mview l
     where l.user_id = u.user_id )
/

サブクエリが多数の行を返す場合は、WHERE EXISTSよりも大幅に高速になる可能性がありますWHERE ... IN

于 2010-04-14T16:36:47.480 に答える
1

2番目のクエリは、おそらく最初のクエリ(join + distinc)よりもハードドライブで機能しています。

最初のクエリは、おそらく次のように変換されます。

テーブルログの各行について、テーブルUser(メモリ内)で対応する行を検索します。

データベースはおそらく、ログテーブルよりもはるかに小さいテーブルUserのメモリ構造を作成するのに十分スマートです。

クエリ1(join + distinct)は、テーブルLogのパスを1つだけ必要とすると思います。

個別はおそらくメモリ内で実行されます。

2番目のクエリは、おそらくデータベースにテーブルLogで複数のフル読み取りを実行するように強制します。

したがって、2番目のクエリでは、おそらく次のようになります。

テーブルユーザーの各行について、条件を一致させるためにテーブルログ(ディスクから)のすべての行を読み取ります。

また、メモリの可用性、負荷、およびテーブルの増加の変化により、一部のクエリで速度が劇的に異なる場合があることも考慮する必要があります。

于 2010-04-14T18:32:24.663 に答える
1

これは持っているデータによって異なりますがDistinct、結合内で使用するとパフォーマンスが向上する可能性があります。

Select u.*
From Users u
Join ( Select Distinct user_id
       From log_mview ) l On u.user_id = l.user_id
于 2010-04-14T16:21:33.490 に答える