ホームページ  >  記事  >  システムチュートリアル  >  SQL クエリを最適化して「未実行」ランタイムを短縮する

SQL クエリを最適化して「未実行」ランタイムを短縮する

PHPz
PHPz転載
2024-01-13 20:12:051049ブラウズ
###導入### DBA によって最適化されたデータベース環境では、パフォーマンスの問題の大部分は、実際には不適切な SQL 記述によって引き起こされます。 SQL の世界は不思議に満ちていますが、今日は血を吐きたくなるようなキラー SQL を紹介します。

保険クライアントの場合、ETL に数時間かかりました。SQL レポートを作成したところ、主に SQL の 1 つに負荷がかかっていることがわかりました。

耗时数小时,‘Not in’ SQL 优化

1 回の実行時間: 5788 (秒)

単一論理読み取り: 10億 (ブロック)

一度に返される行数: 210,000 (行)

まず SQL ステートメントを見てみましょう。比較的長いため、一部のみを抜粋します

耗时数小时,‘Not in’ SQL 优化

実行計画を表示:

耗时数小时,‘Not in’ SQL 优化

主に行 7 ~ 16 に注目します。テーブル全体のスキャンが 2 回あることがわかりました。真ん中にフィルターを施しました。

長年の経験から、2 つのテーブル全体のスキャンで構成されるフィルターには、データを 1 つずつ処理する必要があるため、重大な問題があることがわかりました。この実行プランでは、駆動テーブル全体が引き続きスキャンされます。

Not In/In 操作ではフィルター操作が生成されることがあります。11g より前のバージョンでは、not in ステートメントはアンチ結合に変換する必要があります。not in 条件の列には Not null 属性が必要です。そうでない場合は、not が含まれます。ステートメント内で。null 制限を使用しない場合は、Filter を使用して 1 つずつフィルタリングすることしかできません。

例を挙げてみましょう:

SQL1:CREATE TABLE T_OBJ AS SELECT OBJECT_ID,OWNER,OBJECT_NAME,OBJECT_TYPE FROM DBA_OBJECTS WHERE OWNER != 'SEROL';SQL2:CREATE TABLET_TABLE AS SELECT OWNER,TABLE_NAME FROM DBA_TABLES WHERE OWNER!='SEROL';

T_OBJ の属性を表示します:

耗时数小时,‘Not in’ SQL 优化

3 つの列には null でないという制限がないことがわかりました。

現時点では、10G オプティマイザーであるふりをしています。

SQL> セッションの変更 set optimizer_features_enable=”10.2.0.5″;

次の SQL を実行します:

SQL>set autotracetrace exp

SQL> SELECT * FROM T_TABLE WHERE TABLE_NAME NOT IN(SELECT OBJECT_NAME FROM T_OBJ);

この時点での実行計画を確認すると、フィルターが使用されていることがわかりました:

耗时数小时,‘Not in’ SQL 优化

しかし、11g バージョンでは、オプティマイザは、高価なフィルターから Not in Operation を Null-Aware-Anti-Join に自動的に変換できます。

Not null 条件を追加するか、フィールド属性を not null に設定する場合

SQL> テーブル T_OBJ の変更変更(OBJECT_NAME NOT NULL);

同じステートメントを再度実行します:

SQL> SELECT * FROM T_TABLE WHERE TABLE_NAME

入っていません(T_OBJからオブジェクト名を選択してください

WHEREOBJECT_NAME が NULL ではありません);

実行計画をもう一度表示します:

耗时数小时,‘Not in’ SQL 优化

現時点では、実行計画で hash join anti.

が確認されました。

また、11g では、not null 制限なしで列内の not が許可され、アンチ結合も変換できます。

SQL> セッションの変更 set optimizer_features_enable=”11.2.0.4″;

SQL> テーブル T_OBJ 変更変更(OBJECT_NAME NULL);

SQ> SELECT * FROM T_TABLE WHERE TABLE_NAME

入っていません (T_OBJ からの SELECTOBJECT_NAME);

実行計画の表示:

耗时数小时,‘Not in’ SQL 优化

現時点では、hash join anti.

も空以外の制限なしで使用されていることがわかります。

この機能は、オプティマイザー パラメーターを通じて制御できます。

SQL>セッション セット「_optimizer_null_aware_antijoin」を変更します=FALSE;

上記のステートメントを再度実行し、実行計画を表示します:

SQL> SELECT * FROM T_TABLE WHERE TABLE_NAME

入っていません (T_OBJ からの SELECTOBJECT_NAME);

耗时数小时,‘Not in’ SQL 优化

ハッシュ結合 anti.

がまだ使用されていることがわかりました。

検証の結果、このパラメータ設定で問題ありません

Not in のロジックは結果セット間の相互排他です。実際、これを書き換える方法は次のとおりです。 ###-存在しない### #—— 外部結合が null です

###-マイナス###

not in と上記の 3 つの書き方の違いは、not in では null 値が除外されることです。

書き換えてみます。

次に、奇跡が起こると思ったとき、ステートメントでエラーが報告されました。

耗时数小时,‘Not in’ SQL 优化

エラーが報告されるのはなぜですか?

このステートメントを not in に変換すると:

耗时数小时,‘Not in’ SQL 优化

not inのロジックに従い、このときfee_codeの前に'A.'を追加することになりますが、もちろん問題ありませんが、この文をもう一度見てみると、

となります。

耗时数小时,‘Not in’ SQL 优化

TMP_APP_xxx_PREM A には FEE_CODE フィールドがないため、Not in を Null Aware ANTI JOIN に自動的に変更することはできません。

それでは、答えが明らかになった今、それは間違いだったということになるのでしょうか? !始まりは推測できましたが、結末は推測できませんでした。

ただし、この場合、ステートメントが SQL ステートメントに明示的に記述されていないため、このエラーは初期の分析プロセスでは発見されませんでした。

あなたも言葉を失いましたか?実際、私がもっと聞きたいのは、キラー SQL をよく書くのですか?でも、それは問題ではありません。もし病気なら、私は薬を持っています。 (無邪気な顔、殴らないでね)

DBA によって最適化されたデータベース環境では、パフォーマンスの問題の大部分が実際には不適切な SQL 記述によって引き起こされていることは誰もが知っています。

オンラインではないシステムの場合、初期の SQL 監査と制御を通じて、SQL の問題の 80% が初期段階で排除されます。オンラインで実行されているシステムの場合は、潜在的なパフォーマンスの問題を発見して解決し、問題が発生する前に防止できます。 。

SQL 監査により、DBA はシステムの救急医からシステムの医療医に変身できます

1. DBA はアプリケーション コードの開発とテストのプロセスに参加します: 開発者に専門的なデータベース開発と最適化の提案を提供します

2. 事前最適化: アプリケーション コードをオンラインにする前に、ビジネス ニーズに応じて効率的な SQL とインデックスを設計します

3. 変更リスクの制御: アプリケーション開発中のテーブル構造の変更と SQL の変更が実行中のアプリケーションに与える影響を事前評価し、適切な変更期間と変更計画を決定します。

以上がSQL クエリを最適化して「未実行」ランタイムを短縮するの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はlinuxprobe.comで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。