4

複数のテーブルで目的を達成する方法は 2 つあります。結果セットの列が更新され、速度が必要になる場合があります。結果セットは、次のいずれかによって取得されます。

ケース 1:

select ert.* 
from eval_rep_track ert
inner join 
(
        select erp.evaluation_fk, erp.report_type, LTRIM(erp.assign_group_id, '/site/') course_name
        from eval_report_dup@prod erp
        inner join eval_report er
        on er.id = erp.id
        where erp.status='queue'
        and er.status='done'
) cat

on ert.eval_id || '.' || ert.report_type || '.' || ert.course_name = cat.evaluation_fk || '.' || cat.report_type || '.' || cat.course_name;

また

ケース 2:

select ert.* 
from eval_rep_track ert
inner join 
(
        select erp.evaluation_fk, erp.report_type, LTRIM(erp.assign_group_id, '/site/') course_name
        from eval_report_dup@prod erp
        inner join eval_report er
        on er.id = erp.id
        where erp.status='queue'
        and er.status='done'
) cat
on ert.eval_id = cat.evaluation_fk  
and ert.report_type = cat.report_type  
and ert.course_name = cat.course_name;

結合条件のみが異なり、両方とも同じ結果が得られます。どちらがより速く実行/実行されますか?

eval_id はNUMBER、report_type および course_name はVARCHAR2です。

使用した開発者によると、ケース 1 の統計は次のとおりです。 [SELECT - 3077 行、0.048 秒] フェッチされた結果セット ... 1 ステートメントが実行され、3077 行が影響を受け、実行/フェッチ時間: 0.048 /0.236 秒 [1 成功、0 警告、0 エラー]

while ケース 2: [SELECT - 3077 行、0.019 秒] 結果セットがフェッチされました ... 1 ステートメントが実行され、3077 行が影響を受け、実行/フェッチ時間: 0.019/0.194 秒 [1 成功、0警告、0 エラー]

結果は、ケース 2 の方が高速であることを示しています。これはどのプラットフォーム (ide、開発者) とデータベースでも共通ですか? これはデータ型に依存していますか、それとも連結は常に高価ですか? 連結の結果は実際には必要ありません。ありがとう。

4

3 に答える 3

7

連結を使用したバージョンは、実質的に常に遅くなると思います。

個別に比較している列のいずれかにインデックスがある場合、データベースは通常、インデックスを使用して結合を最適化できます。連結を比較する場合、計算の結果がインデックスに含まれないため、完全なテーブル スキャンを実行する必要があります。

また、列が索引付けされていない場合でも、データベースは比較をより効率的に実行できます。一度に 1 つの列のペアを比較し、それらの比較のいずれかが失敗するとすぐに停止できます。連結を使用する場合、最初に両方の行のすべての列を結合してから、文字列の比較を行う必要があります。

最後に、列のいずれかが数値である場合、連結には数値を文字列に変換する追加の手順が必要になります。

于 2015-04-29T19:46:04.480 に答える
4

簡単に言えば、個々の列で結合するのが正しいです。連結値への結合は正しくありません。パフォーマンスの議論とは別に、正しいコードを書く必要があります。

特定のクエリについては、おそらく連結を使用してほぼ正しいクエリを作成できます。しかし、ほとんどの場合、予期しないデータを取得したときに噛み付く微妙なバグが発生します。この場合、列にピリオドが含まれるとすぐに、データが正しく一致しない可能性があります ( 'a.b' || '.' || null = 'a' || '.' || 'b.')。それ以外の場合は、その他の微妙な問題が発生します。日付と数値は、異なる結果を生成する可能性のある異なるセッション レベルの設定を使用して暗黙的に文字列に変換される可能性があります (NLS_DATE_FORMAT時間コンポーネントが含まれている場合と含まれていない場合があるため、連結された値に時間の比較が含まれる場合と含まれない場合があります)。列を一般的に連結すると、テーブル内のデータとコードを実行するユーザーに基づいて、非常に微妙なバグを持つ多くのクエリが発生することになります。メンテナンスとサポートの観点からすると、これはひどいことです。パフォーマンスは、せいぜい二次的な関心事である必要があります。

パフォーマンスの観点からは、適切な結合はほぼ確実に連結アプローチよりも優れています。オプティマイザーは、正しく結合している場合、クエリ プランを生成するときに、結合の一部であるさまざまな列の通常のインデックスを考慮することができます。値を連結している場合、せいぜい Oracle は通常のインデックスのフル スキャンを実行して、連結する必要があるすべてのデータを取得できる可能性があります。ただし、これは効率が大幅に低下する可能性があります (特に、数千行を超える場合)。

理論的には、連結アプローチがどこかのクエリに対してより効率的である可能性はありますか? もちろん。サディスティックな開発者は、連結された結果に関数ベースのインデックスを作成し、個々の列にインデックスを作成することを避け、連結アプローチがより効率的なテスト ケースを生成する可能性があります。ただし、これは、基本列に適切な対応するインデックス (または複数のインデックス) を作成することで簡単に修正できます。オプティマイザーが他の方法で使用したいインデックスを使用できなくなるため、連結が一部のクエリでより効率的になる可能性はありますか? もちろん。しかし、これはほぼ間違いなく、オプティマイザーの設定または統計に問題があることを示しており、問題に応急処置を施すのではなく、対処する必要があります。

于 2015-04-29T20:08:45.087 に答える
1

テーブルのインデックスに依存します。通常、インデックスは列リストで定義されますが、列の連結 (式として) では定義されないため、経験則として、2 番目のバージョンは通常どおりインデックスを作成する方が高速です。

そうは言っても、データベース管理者は (何らかの理由で、おそらく中毒や狂気で) 列の連結にインデックスを作成することを決定する可能性があります。その場合、ステートメントの最初のバージョンはインデックスを使用でき、2 番目のバージョンは使用できません。

于 2015-04-29T19:44:46.813 に答える