Oracle® Database

SQLチューニング・ガイド

12cリリース1(12.1)

B71277-09(原本部品番号:E49106-14)

2017年7月

Oracle Database SQLチューニング・ガイド, 12cリリース1(12.1)

B71277-09

Copyright © 2013, 2017, Oracle and/or its affiliates.  All rights reserved.

原本著者: Lance Ashdown

原本協力著者: Nigel Bayliss, Maria Colgan, Tom Kyte

原本協力者: Pete Belknap、Ali Cakmak、Sunil Chakkappen、Immanuel Chan、Deba Chatterjee、Chris Chiappa、Dinesh Das、Leonidas Galanis、William Endress、Bruce Golbus、Katsumi Inoue、Kevin Jernigan、Shantanu Joshi、Adam Kociubes、Allison Lee、Sue Lee、David McDermid、Colin McGregor、Ted Persky、Ekrem Soylemez、Hong Su、Murali Thiyagarajah、Randy Urbano、Bharath Venkatakrishnan、Hailing Yu

このソフトウェアおよび関連ドキュメントの使用と開示は、ライセンス契約の制約条件に従うものとし、知的財産に関する法律により保護されています。ライセンス契約で明示的に許諾されている場合もしくは法律によって認められている場合を除き、形式、手段に関係なく、いかなる部分も使用、複写、複製、翻訳、放送、修正、ライセンス供与、送信、配布、発表、実行、公開または表示することはできません。このソフトウェアのリバース・エンジニアリング、逆アセンブル、逆コンパイルは互換性のために法律によって規定されている場合を除き、禁止されています。

ここに記載された情報は予告なしに変更される場合があります。また、誤りが無いことの保証はいたしかねます。誤りを見つけた場合は、オラクル社までご連絡ください。

このソフトウェアまたは関連ドキュメントを、米国政府機関もしくは米国政府機関に代わってこのソフトウェアまたは関連ドキュメントをライセンスされた者に提供する場合は、次の通知が適用されます。

U.S. GOVERNMENT END USERS: Oracle programs, including any operating system, integrated software, any programs installed on the hardware, and/or documentation, delivered to U.S. Government end users are "commercial computer software" pursuant to the applicable Federal Acquisition Regulation and agency-specific supplemental regulations.As such, use, duplication, disclosure, modification, and adaptation of the programs, including any operating system, integrated software, any programs installed on the hardware, and/or documentation, shall be subject to license terms and license restrictions applicable to the programs.No other rights are granted to the U.S. Government.

このソフトウェアまたはハードウェアは様々な情報管理アプリケーションでの一般的な使用のために開発されたものです。このソフトウェアまたはハードウェアは、危険が伴うアプリケーション(人的傷害を発生させる可能性があるアプリケーションを含む)への用途を目的として開発されていません。このソフトウェアまたはハードウェアを危険が伴うアプリケーションで使用する際、このソフトウェアまたはハードウェアを安全に使用するために、適切な安全装置、バックアップ、冗長性(redundancy)、その他の対策を講じることは使用者の責任となります。このソフトウェアまたはハードウェアを危険が伴うアプリケーションで使用したことに起因して損害が発生しても、オラクル社およびその関連会社は一切の責任を負いかねます。

OracleおよびJavaはOracle およびその関連企業の登録商標です。その他の名称は、それぞれの所有者の商標または登録商標です。

Intel、Intel Xeonは、Intel Corporationの商標または登録商標です。すべてのSPARCの商標はライセンスをもとに使用し、SPARC International, Inc.の商標または登録商標です。AMD、Opteron、AMDロゴ、AMD Opteronロゴは、Advanced Micro Devices, Inc.の商標または登録商標です。UNIXはThe Open Groupの登録商標です。

このソフトウェアまたはハードウェア、そしてドキュメントは、第三者のコンテンツ、製品、サービスへのアクセス、あるいはそれらに関する情報を提供することがあります。適用されるお客様とOracle Corporationとの間の契約に別段の定めがある場合を除いて、Oracle Corporationおよびその関連会社は、第三者のコンテンツ、製品、サービスに関して一切の責任を負わず、いかなる保証もいたしません。適用されるお客様とOracle Corporationとの間の契約に定めがある場合を除いて、Oracle Corporationおよびその関連会社は、第三者のコンテンツ、製品、サービスへのアクセスまたは使用によって損失、費用、あるいは損害が発生しても一切の責任を負いかねます。

目次

タイトルおよび著作権情報

はじめに

- 対象読者

- ドキュメントのアクセシビリティについて

- 関連ドキュメント

- 表記規則

Oracle Database SQLチューニング・ガイドのこのリリースでの変更

- Oracle Database 12cリリース1(12.1.0.2)での変更点

- 新機能

- Oracle Database 12cリリース1 (12.1.0.1)での変更点

- 新機能

- 非推奨となった機能

- サポート対象外機能

- その他の変更

第I部 SQLパフォーマンスの基本

1 SQLチューニングの概要

- SQLチューニングについて

- SQLチューニングの目的

- SQLチューニングの前提条件

- SQLチューニングのタスクとツール

- SQLチューニング・タスク

- SQLチューニング・ツール

- 自動SQLチューニング・ツール

- 自動データベース診断モニター(ADDM)

- SQLチューニング・アドバイザ

- SQLアクセス・アドバイザ

- SQL計画管理

- SQLパフォーマンス・アナライザ

- 手動SQLチューニング・ツール

- 実行計画

- リアルタイムなSQL監視およびリアルタイムなデータベース操作

- アプリケーションのトレース

- オプティマイザ・ヒント

- SQLチューニング・ツールへのユーザー・インタフェース

2 SQLパフォーマンスの方法

- アプリケーションの設計のガイドライン

- データのモデル化のガイドライン

- 効率的なアプリケーションの作成のガイドライン

- アプリケーションのデプロイのガイドライン

- テスト環境でのデプロイのガイドライン

- アプリケーションのロールアウトのガイドライン

第II部 問合せオプティマイザの基礎

3 SQLの処理

- SQL処理について

- SQLの解析

- 構文チェック

- セマンティクス・チェック

- 共有プール・チェック

- SQLの最適化

- SQLの行ソース生成

- SQLの実行

- Oracle DatabaseによるDML処理方法

- 行セットのフェッチ方法

- 読取り一貫性

- データ変更

- Oracle DatabaseによるDDLの処理方法

4 問合せオプティマイザの概念

- 問合せオプティマイザの概要

- 問合せオプティマイザの目的

- コストベースの最適化

- 実行計画

- 問合せブロック

- 問合せサブプラン

- オプティマイザの例え

- オプティマイザのコンポーネントについて

- 問合せトランスフォーマ

- エスティメータ

- 選択性

- カーディナリティ

- コスト

- プラン・ジェネレータ

- 自動チューニング・オプティマイザについて

- 適応問合せ最適化について

- 適応問合せ計画

- 適応問合せ計画の目的

- 適応問合せ計画の仕組み

- 適応問合せ計画: 結合方法の例

- 適応問合せ計画: パラレル配分方法

- 適応問合せ計画: ビットマップ索引プルーニング

- 適応統計

- 動的統計

- 自動再最適化

- 再最適化: 統計フィードバック

- 再最適化: パフォーマンス・フィードバック

- SQL計画ディレクティブ

- SQL計画ベースラインのオプティマイザ管理について

5 問合せ変換

- OR拡張

- ビューのマージ

- ビューのマージにおける問合せブロック

- 単純ビューのマージ

- 複合ビューのマージ

- 述語のプッシュ

- 副問合せのネスト解除

- マテリアライズド・ビューを使用したクエリー・リライト

- スター型変換

- スター・スキーマについて

- スター型変換の目的

- スター型変換の仕組み

- スター型変換の制御

- スター型変換: シナリオ

- 一時表の変換: シナリオ

- インメモリー集計

- インメモリー集計の目的

- インメモリー集計の仕組み

- キー・ベクター

- インメモリー集計の2つのフェーズ

- インメモリー集計の制御

- インメモリー集計: シナリオ

- スター・スキーマのサンプル分析問合せ

- 手順1: geographyディメンションのキー・ベクターと一時表の作成

- 手順2: productsディメンションのキー・ベクターと一時表の作成

- 手順3: キー・ベクター問合せ変換

- 手順4: ファクト表からの行フィルタ

- 手順5: 配列を使用した集計

- 手順6: 一時表への再結合

- インメモリー集計: 例

- 表拡張

- 表拡張の目的

- 表拡張の仕組み

- 表拡張: シナリオ

- 表拡張とスター型変換: シナリオ

- 結合の因数分解

- 結合の因数分解の目的

- 結合の因数分解の仕組み

- 因数分解と結合順序: シナリオ

- 外部結合の因数分解: シナリオ

第III部 問合せの実行計画

6 実行計画の生成と表示

- 実行計画の概要

- 計画の生成と表示について

- 計画の説明について

- 実行計画の変化理由

- スキーマの相違

- コストの相違

- 排除行数の最少化のガイドライン

- 実行計画の評価のガイドライン

- V$SQL_PLANビューを使用した計画の評価のガイドライン

- EXPLAIN PLANの制限事項

- PLAN_TABLEの作成のガイドライン

- 実行計画の生成

- 1つの文に対するEXPLAIN PLANの実行

- 文IDを使用したEXPLAIN PLANの実行

- デフォルト以外の表へのEXPLAIN PLAN出力の指示

- PLAN_TABLE出力の表示

- 実行計画の表示: 例

- PLAN_TABLE出力のカスタマイズ

7 実行計画の読取り

- 実行計画の読取り: 基本

- 実行計画の読取り: 拡張

- 適応問合せ計画の読取り

- EXPLAIN PLANによるパラレル実行の表示

- EXPLAIN PLANおよびパラレル問合せについて

- EXPLAIN PLANによるパラレル問合せの表示: 例

- EXPLAIN PLANによるビットマップ索引の表示

- EXPLAIN PLANによる結果キャッシュの表示

- EXPLAIN PLANによるパーティション・オブジェクトの表示

- EXPLAIN PLANによるレンジ・パーティション化およびハッシュ・パーティション化の表示: 例

- コンポジット・パーティション・オブジェクトでのプルーニング情報: 例

- パーシャル・パーティション・ワイズ結合の例

- フル・パーティション・ワイズ結合の例

- INLIST ITERATORおよびEXPLAIN PLANの例

- INリスト列が索引列である場合: 例

- INリスト列が索引でありパーティション列である場合: 例

- INリスト列がパーティション列である場合: 例

- ドメイン索引およびEXPLAIN PLANの例

- PLAN_TABLE列

- 実行計画のリファレンス

- 実行計画のビュー

- PLAN_TABLE列

- DBMS_XPLANプログラム・ユニット

第IV部 SQL演算子: アクセス・パスおよび結合

8 オプティマイザのアクセス・パス

- 「アクセス・パスの概要」

- 表アクセス・パス

- ヒープ構成表アクセスについて

- データ・ブロックとセグメントでの行の格納: 入門編

- 行アクセスにおけるROWIDの重要性

- ダイレクト・パス読取り

- 全表スキャン

- オプティマイザが全表スキャンを考慮する場合

- 全表スキャンの仕組み

- 全表スキャン: 例

- ROWIDによる表アクセス

- オプティマイザがROWIDによる表アクセスを選択する場合

- ROWIDによる表アクセスの仕組み

- ROWIDによる表アクセス: 例

- サンプル表スキャン

- オプティマイザがサンプル表スキャンを選択する場合

- サンプル表スキャン: 例

- インメモリー表スキャン

- オプティマイザがインメモリー表スキャンを選択する場合

- インメモリー問合せの制御

- インメモリー表スキャン: 例

- Bツリー索引アクセス・パス

- Bツリー索引アクセスについて

- Bツリー索引構造

- 索引記憶が索引スキャンに与える影響

- 一意索引と非一意索引

- Bツリー索引およびNULL

- 索引一意スキャン

- オプティマイザが索引一意スキャンを考慮する場合

- 索引一意スキャンの仕組み

- 索引一意スキャン: 例

- 索引レンジ・スキャン

- オプティマイザが索引レンジ・スキャンを考慮する場合

- 索引レンジ・スキャンの仕組み

- 索引レンジ・スキャン: 例

- 索引レンジ・スキャン降順: 例

- 全索引スキャン

- オプティマイザが全索引スキャンを考慮する場合

- 全索引スキャンの仕組み

- 全索引スキャン: 例

- 高速全索引スキャン

- オプティマイザが高速全索引スキャンを考慮する場合

- 高速全索引スキャンの仕組み

- 高速全索引スキャン: 例

- 索引スキップ・スキャン

- オプティマイザが索引スキップ・スキャンを考慮する場合

- 索引スキップ・スキャンの仕組み

- 索引スキップ・スキャン: 例

- 索引結合スキャン

- オプティマイザが索引結合スキャンを考慮する場合

- 索引結合スキャンの仕組み

- 索引結合スキャン: 例

- ビットマップ索引アクセス・パス

- ビットマップ索引アクセスについて

- ビットマップ索引とBツリー索引の違い

- ビットマップ索引の目的

- ビットマップおよびROWID

- ビットマップ結合索引

- ビットマップ・ストレージ

- ビットマップのROWIDへの変換

- オプティマイザがビットマップのROWIDへの変換を選択する場合

- ビットマップのROWIDへの変換の仕組み

- ビットマップのROWIDへの変換: 例

- ビットマップ索引単一値

- オプティマイザがビットマップ索引単一値を考慮する場合

- ビットマップ索引単一値の仕組み

- ビットマップ索引単一値: 例

- ビットマップ索引レンジ・スキャン

- オプティマイザがビットマップ索引レンジ・スキャンを考慮する場合

- ビットマップ索引レンジ・スキャンの仕組み

- ビットマップ索引レンジ・スキャン: 例

- ビットマップ・マージ

- オプティマイザがビットマップ・マージを考慮する場合

- ビットマップ・マージの仕組み

- ビットマップ・マージ: 例

- 表クラスタ・アクセス・パス

- クラスタ・スキャン

- オプティマイザがクラスタ・スキャンを考慮する場合

- クラスタ・スキャンの仕組み

- クラスタ・スキャン: 例

- ハッシュ・スキャン

- オプティマイザがハッシュ・スキャンを考慮する場合

- ハッシュ・スキャンの仕組み

- ハッシュ・スキャン: 例

9 結合

- 結合について

- 結合ツリー

- オプティマイザによる結合文の実行方法

- オプティマイザによる結合の実行計画の選択方法

- 結合方法

- ネステッド・ループ結合

- オプティマイザがネステッド・ループ結合を考慮する場合

- ネステッド・ループ結合の仕組み

- ネステッド・ループのネスト

- ネステッド・ループ結合の現在の実装

- ネステッド・ループ結合の従来の実装

- ネステッド・ループの制御

- ハッシュ結合

- オプティマイザがハッシュ結合を考慮する場合

- ハッシュ結合の仕組み

- ハッシュ表

- ハッシュ結合: 基本手順

- ハッシュ表がPGAに収まらない場合のハッシュ結合の仕組み

- ハッシュ結合の制御

- ソート/マージ結合

- オプティマイザがソート/マージ結合を考慮する場合

- ソート/マージ結合の仕組み

- ソート/マージ結合の制御

- デカルト結合

- オプティマイザがデカルト結合を考慮する場合

- デカルト結合の仕組み

- デカルト結合の制御

- 結合タイプ

- 内部結合

- 等価結合

- 非等価結合

- 外部結合

- ネステッド・ループ外部結合

- ハッシュ結合外部結合

- ソート/マージ外部結合

- 完全外部結合

- 左側に複数の表がある外部結合

- セミ結合

- オプティマイザによってセミ結合が考慮される場合

- セミ結合の仕組み

- アンチ結合

- オプティマイザによってアンチ結合が考慮される場合

- アンチ結合の仕組み

- アンチ結合でNULLが処理される仕組み

- 結合の最適化

- ブルーム・フィルタ

- ブルーム・フィルタの目的

- ブルーム・フィルタの仕組み

- ブルーム・フィルタの制御

- ブルーム・フィルタのメタデータ

- ブルーム・フィルタ: シナリオ

- パーティション・ワイズ結合

- パーティション・ワイズ結合の目的

- パーティション・ワイズ結合の仕組み

- フル・パーティション・ワイズ結合の仕組み

- パーシャル・パーティション・ワイズ結合の仕組み

第V部 オプティマイザ統計

10 オプティマイザ統計の概念

- オプティマイザ統計の概要

- オプティマイザ統計のタイプについて

- 表統計

- 列統計

- 索引統計

- 索引統計のタイプ

- 索引クラスタ化係数

- 索引クラスタ化係数がコストに与える影響: 例

- グローバル一時表のセッション固有統計

- グローバル一時表の共有統計およびセッション固有統計

- トランザクション固有一時表へのDBMS_STATSの影響

- システム統計

- ユーザー定義のオプティマイザ統計

- データベースがオプティマイザ統計を収集する方法

- DBMS_STATSパッケージ

- 補足的な動的統計

- バルク・ロードのためのオンライン統計収集

- バルク・ロードのためのオンライン統計収集の目的

- 空のパーティション化された表への挿入時のグローバル統計

- バルク・ロード時の索引統計およびヒストグラム

- バルク・ロードのためのオンライン統計収集の制限

- バルク・ロードのためのオンライン統計収集のヒント

- データベースがオプティマイザ統計を収集する場合

- オプティマイザ統計のソース

- SQL計画ディレクティブ

- SQL計画ディレクティブについて

- オプティマイザがSQL計画ディレクティブを使用する際の仕組み: 例

- オプティマイザが拡張およびSQL計画ディレクティブを使用する際の仕組み: 例

- データベースがデータをサンプリングする場合

- データベースがデータをサンプリングする方法

11 ヒストグラム

- ヒストグラムの目的

- ヒストグラムが作成される場合

- Oracle Databaseによるヒストグラム・タイプの選択方法

- ヒストグラム使用時のカーディナリティ・アルゴリズム

- エンドポイント番号とエンドポイント値

- ポピュラー値と非ポピュラー値

- バケットの圧縮

- 頻度ヒストグラム

- 頻度ヒストグラムの基準

- 頻度ヒストグラムの生成

- 上位頻度ヒストグラム

- 上位頻度ヒストグラムの基準

- 上位頻度ヒストグラムの生成

- 高さ調整済ヒストグラム(レガシー)

- 高さ調整済ヒストグラムの基準

- 高さ調整済ヒストグラムの生成

- ハイブリッド・ヒストグラム

- エンドポイント繰返しカウントの仕組み

- ハイブリッド・ヒストグラムの基準

- ハイブリッド・ヒストグラムの生成

12 オプティマイザ統計の管理: 基本的なトピック

- オプティマイザ統計収集について

- オプティマイザ統計収集の目的

- オプティマイザ統計管理のユーザー・インタフェース

- オプティマイザ統計管理のグラフィカル・インタフェース

- Cloud Controlのデータベース・ホーム・ページへのアクセス

- 「オプティマイザ統計コンソール」へのアクセス

- オプティマイザ統計管理のコマンドライン・インタフェース

- 自動オプティマイザ統計収集の構成

- 自動オプティマイザ統計収集について

- Cloud Controlを使用した自動オプティマイザ統計収集の構成

- コマンドラインからの自動オプティマイザ統計収集の構成

- オプティマイザ統計プリファレンスの設定

- オプティマイザ統計プリファレンスについて

- 統計プリファレンスを設定するDBMS_STATSプロシージャ

- 統計プリファレンスの設定: 例

- Cloud Controlを使用したグローバル・オプティマイザ統計プリファレンスの設定

- Cloud Controlを使用したオブジェクト・レベルのオプティマイザ統計プリファレンスの設定

- コマンドラインからのオプティマイザ統計プリファレンスの設定

- オプティマイザ統計の手動収集

- DBMS_STATSを使用した手動統計収集について

- オプティマイザ統計の手動収集のガイドライン

- サンプル・サイズの設定のガイドライン

- パラレル統計収集のガイドライン

- パーティション・オブジェクトのガイドライン

- 変更頻度の高いオブジェクトのガイドライン

- 外部表のガイドライン

- オプティマイザ統計が失効するタイミングの判別

- スキーマ統計および表統計の収集

- 固定オブジェクトの統計情報の収集

- 動的統計を使用した変化しやすい表の統計の収集

- オプティマイザ統計の同時収集

- 同時統計収集について

- DBMS_STATSによる統計の同時収集の方法

- 同時統計収集とリソースの管理

- 同時統計収集の有効化

- パラレル実行および同時統計収集のためのシステムの構成

- 統計収集操作の監視

- パーティション・オブジェクトの増分統計の収集

- 増分統計の目的

- DBMS_STATSによるパーティション表のグローバル統計の導出方法

- 増分統計メンテナンスの考慮事項

- パーティション・メンテナンス操作の増分統計の維持

- 失効したまたはロックされたパーティション統計のある表の増分統計の維持

- システム統計の手動収集

- DBMS_STATSを使用したシステム統計の収集について

- システム統計収集のガイドライン

- 作業負荷統計の収集

- 作業負荷統計について

- システム統計収集の開始および停止

- 指定された間隔でのシステム統計の収集

- 非作業負荷統計の収集

- システム統計の削除

13 オプティマイザ統計の管理: 高度なトピック

- 動的統計の制御

- 動的統計レベルについて

- 動的統計レベルの手動設定

- 動的統計の無効化

- 保留中のオプティマイザ統計の公開

- 保留中のオプティマイザ統計について

- オプティマイザ統計の公開のためのユーザー・インタフェース

- 公開された統計と保留中の統計の管理

- 拡張統計の管理

- 列グループの統計の管理

- 列グループの統計について

- 列グループの統計が必要な理由: 例

- 列グループの統計のユーザー・インタフェース

- 特定のワークロードに対して有用な列グループの検出

- ワークロードの監視中に検出された列グループの作成

- 手動による列グループの作成および統計の収集

- 列グループ情報の表示

- 列グループの削除

- 式の統計の管理

- 式の統計について

- 式の統計が有用なタイミング: 例

- 式の統計の作成

- 式の統計の表示

- 式の統計の削除

- オプティマイザ統計のロックおよびロック解除

- 統計のロック

- 統計のロック解除

- オプティマイザ統計のリストア

- オプティマイザ統計のリストア操作について

- オプティマイザ統計のリストアのガイドライン

- オプティマイザ統計のリストアの制限

- DBMS_STATSを使用したオプティマイザ統計のリストア

- オプティマイザ統計の保存の管理

- オプティマイザ統計の履歴の取得

- オプティマイザ統計の保存期間の変更

- オプティマイザ統計の消去

- オプティマイザ統計のインポートとエクスポート

- オプティマイザ統計の転送について

- テスト・データベースへのオプティマイザ統計の転送

- レポート作成モードでの統計収集関数の実行

- 過去の統計収集操作のレポート作成

- SQL計画ディレクティブの管理

第VI部 オプティマイザの制御

14 オプティマイザへの影響

- オプティマイザに影響を与える手法

- 初期化パラメータによるオプティマイザへの影響

- オプティマイザの初期化パラメータについて

- オプティマイザ機能の有効化

- オプティマイザの目標の選択

- 適応最適化の制御

- ヒントによるオプティマイザへの影響

- オプティマイザ・ヒントについて

- ヒントの型

- ヒントの有効範囲

- ヒントの考慮事項

- 結合順序のヒントのガイドライン

15 カーソル共有によるReal-World Performanceの改善

- カーソル共有の概要

- カーソルについて

- プライベートSQL領域と共有SQL領域

- 親カーソルと子カーソル

- 親カーソルおよびV$SQLAREA

- 子カーソルおよびV$SQL

- カーソルの不一致およびV$SQL_SHARED_CURSOR

- カーソルおよび解析について

- リテラルおよびバインド変数について

- リテラルおよびカーソル

- バインド変数およびカーソル

- バインド変数の照合

- CURSOR_SHARINGおよびバインド変数置換

- CURSOR_SHARING初期化パラメータ

- CURSOR_SHARING = FORCEの場合の動作の解析

- 適応カーソル共有

- 適応カーソル共有の目的

- 適応カーソル共有の仕組み: 例

- バインド依存カーソル

- バインド対応カーソル

- カーソルのマージ

- 適応カーソル共有のビュー

- カーソル共有のためのReal-World Performanceのガイドライン

- セキュリティおよびパフォーマンスのためのバインド変数を使用したアプリケーションの開発

- CURSOR_SHARING = FORCEを永続的な修正として使用しない

- カーソル再利用を増やすためのコーディング規則の確立

- オプティマイザ環境へのセッション・レベルの変更の最小化

第VII部 SQLの監視および追跡

16 データベース操作の監視

- データベース操作の監視について

- データベース操作の監視の目的

- 単純なデータベース操作のユースケース

- 複合データベース操作のユースケース

- データベース操作監視の概念

- データベース操作のアーキテクチャについて

- 複合データベース操作

- データベース操作の属性

- データベース操作監視のユーザー・インタフェース

- Cloud Controlの「監視されたSQL実行」ページ

- 「監視されたSQL実行」ページへのアクセス

- DBMS_SQL_MONITORパッケージ

- データベース操作監視のビュー

- データベース操作監視の基本的なタスク

- データベース操作監視の有効化および無効化

- システム・レベルでのデータベース操作監視の有効化

- 文レベルでのデータベース操作監視の有効化および無効化

- データベース操作の作成

- Cloud Controlを使用したSQL実行の監視

17 SQLテスト・ケース・ビルダーを使用した診断データの収集

- SQLテスト・ケース・ビルダーの目的

- SQLテスト・ケース・ビルダーの概念

- SQLインシデント

- SQLテスト・ケース・ビルダーで取得される情報

- SQLテスト・ケース・ビルダーの出力

- SQLテスト・ケース・ビルダーのユーザー・インタフェース

- SQLテスト・ケース・ビルダーのグラフィカル・インタフェース

- インシデント・マネージャへのアクセス

- サポート・ワークベンチへのアクセス

- SQLテスト・ケース・ビルダーのコマンドライン・インタフェース

- SQLテスト・ケース・ビルダーの実行

18 アプリケーション・トレースの実行

- エンドツーエンド・アプリケーションのトレースの概要

- エンドツーエンド・アプリケーションのトレースの目的

- エンドツーエンド・アプリケーションのトレースのツール

- SQLトレース機能の概要

- TKPROFの概要

- エンドツーエンド・トレースにおける統計収集の有効化

- クライアント識別子に対する統計収集の有効化

- サービス、モジュールおよびアクションに対する統計収集の有効化

- エンドツーエンド・アプリケーションのトレースの有効化

- クライアント識別子に対するトレースの有効化

- サービス、モジュールおよびアクションに対するトレースの有効化

- セッションに対するトレースの有効化

- インスタンスまたはデータベースに対するトレースの有効化

- SQLトレースおよびTKPROFを使用した出力ファイルの生成

- 手順1: トレース・ファイル管理用の初期化パラメータの設定

- 手順2: SQLトレース機能を使用可能にする方法

- 手順3: TKPROFでの出力ファイルの生成

- 手順4: SQLトレース機能統計の格納

- TKPROFによる出力SQLスクリプトの生成

- TKPROFによる出力SQLスクリプトの編集

- 出力表の問合せ

- TKPROF出力の解釈のガイドライン

- 統計の精度を解釈するためのガイドライン

- 再帰的SQL文に関するガイドライン

- チューニングする文の決定に関するガイドライン

- TKPROFの解釈におけるトラップを回避するためのガイドライン

- 引数トラップを回避するためのガイドライン

- 読取り一貫性トラップを回避するためのガイドライン

- スキーマ・トラップを回避するためのガイドライン

- タイム・トラップを回避するためのガイドライン

- アプリケーション・トレース・ユーティリティ

- TRCSESS

- 目的

- ガイドライン

- 構文

- オプション

- 例

- TKPROF

- 目的

- ガイドライン

- 構文

- オプション

- 出力

- TKPROFでのSQL文を発行するユーザーの識別

- TKPROFの表形式の統計

- TKPROFのライブラリ・キャッシュ・ミス

- TKPROFの行ソースの操作

- TKPROF内の待機イベント情報

- 例

- アプリケーションのトレースのビュー

- トレース統計の公開に関連するビュー

- トレースの有効化に関連するビュー

第VIII部 自動SQLチューニング

19 SQLチューニング・セットの管理

- SQLチューニング・セットについて

- SQLチューニング・セットの目的

- SQLチューニング・セットの概念

- SQLチューニング・セットのユーザー・インタフェース

- Cloud Controlでの「SQLチューニング・セット」ページへのアクセス

- SQLチューニング・セットへのコマンドライン・インタフェース

- SQLチューニング・セットの基本タスク

- SQLチューニング・セットの作成

- SQLチューニング・セットのロード

- SQLチューニング・セットの内容の表示

- SQLチューニング・セットの変更

- SQLチューニング・セットの転送

- SQLチューニング・セットの転送について

- SQLチューニング・セットを転送するための基本手順

- CON_DBID値が異なる場合のSQLチューニング・セットを転送するための基本手順

- DBMS_SQLTUNEを使用したSQLチューニング・セットの転送

- SQLチューニング・セットの削除

20 SQLチューニング・アドバイザを使用したSQLの分析

- SQLチューニング・アドバイザについて

- SQLチューニング・アドバイザの目的

- SQLチューニング・アドバイザのアーキテクチャ

- 自動およびオンデマンドSQLチューニング

- SQLチューニング・アドバイザへの入力

- SQLチューニング・アドバイザの出力

- 自動チューニング・オプティマイザの分析

- 統計分析

- SQLプロファイリング

- SQLプロファイリングの動作

- SQLプロファイルの実装

- アクセス・パス分析

- SQL構造分析

- 代替計画分析

- 自動SQLチューニング・タスクの管理

- 自動SQLチューニング・タスクについて

- 自動SQLチューニングの目的

- 自動SQLチューニングの概要

- SQLチューニング・アドバイザへのコマンドライン・ユーザー・インタフェース

- 自動SQLチューニングの基本タスク

- 自動SQLチューニング・タスクの有効化と無効化

- Cloud Controlを使用した自動SQLチューニング・タスクの有効化と無効化

- コマンドラインを使用した自動SQLチューニング・タスクの有効化と無効化

- 自動SQLチューニング・タスクの構成

- Cloud Controlを使用した自動SQLチューニング・タスクの構成

- コマンドラインを使用した自動SQLチューニング・タスクの構成

- 自動SQLチューニング・レポートの表示

- コマンドラインを使用した自動SQLチューニング・レポートの表示

- オンデマンドでのSQLチューニング・アドバイザの実行

- オンデマンドSQLチューニングについて

- オンデマンドSQLチューニングの目的

- オンデマンドSQLチューニングのユーザー・インタフェース

- Cloud Controlを使用したSQLチューニング・アドバイザへのアクセス

- オンデマンドSQLチューニングへのコマンドライン・インタフェース

- オンデマンドSQLチューニングの基本タスク

- SQLチューニング・タスクの作成

- SQLチューニング・タスクの構成

- SQLチューニング・タスクの実行

- SQLチューニング・タスクの監視

- SQLチューニング・タスクの結果の表示

21 SQLアクセス・アドバイザを使用したアクセス・パスの最適化

- SQLアクセス・アドバイザについて

- SQLアクセス・アドバイザの目的

- SQLアクセス・アドバイザのアーキテクチャ

- SQLアクセス・アドバイザへの入力

- SQLアクセス・アドバイザのフィルタ・オプション

- SQLアクセス・アドバイザ推奨事項

- SQLアクセス・アドバイザ・アクション

- アクションのタイプ

- パーティション化の推奨事項の解釈のガイドライン

- SQLアクセス・アドバイザ・リポジトリ

- SQLアクセス・アドバイザのユーザー・インタフェース

- Cloud Controlを使用した「SQLアクセス・アドバイザ: 初期オプション」ページへのアクセス

- SQLチューニング・セットへのコマンドライン・インタフェース

- SQLアクセス・アドバイザの使用: 基本タスク

- SQLアクセス・アドバイザの入力としてのSQLチューニング・セットの作成

- ユーザー定義のワークロードのSQLチューニング・セットへの移入

- SQLアクセス・アドバイザ・タスクの作成および構成

- SQLアクセス・アドバイザ・タスクの実行

- SQLアクセス・アドバイザ・タスクの結果の表示

- タスク・スクリプトの生成および実行

- SQLアクセス・アドバイザ・クイック・チューニングの実行

- SQLアクセス・アドバイザの使用: 詳細タスク

- 既存のアクセス構造の評価

- SQLアクセス・アドバイザのタスク属性の更新

- SQLアクセス・アドバイザのタスク・テンプレートの作成および使用

- SQLアクセス・アドバイザ・タスクの実行終了

- SQLアクセス・アドバイザ・タスクへの割込み

- SQLアクセス・アドバイザ・タスクの取消し

- SQLアクセス・アドバイザ・タスクの削除

- SQLアクセス・アドバイザ推奨事項のマーク

- SQLアクセス・アドバイザ推奨事項の変更

- SQLアクセス・アドバイザの例

- SQLアクセス・アドバイザ・リファレンス

- DBA_ADVISOR_ACTIONSビューのアクション属性

- SQLアクセス・アドバイザのタスク・パラメータのカテゴリ

- SQLアクセス・アドバイザの定数

第IX部 SQLの管理

22 SQLプロファイルの管理

- SQLプロファイルについて

- SQLプロファイルの目的

- SQLプロファイルの概念

- SQLプロファイルの推奨事項

- SQLプロファイルおよびSQL計画ベースライン

- SQLプロファイルのユーザー・インタフェース

- SQLプロファイルの基本タスク

- SQLプロファイルの実装

- SQLプロファイルの実装について

- SQLプロファイルの実装

- SQLプロファイルのリスト

- SQLプロファイルの変更

- SQLプロファイルの削除

- SQLプロファイルの転送

23 SQL計画ベースラインの管理

- SQL計画管理について

- SQL計画管理の目的

- SQL計画管理の利点

- SQL計画ベースラインとSQLプロファイルの違い

- 計画の取得

- 初期計画の自動取得

- 計画の手動取得

- 計画の選択

- 計画の展開

- 計画の展開の目的

- 計画の展開用のPL/SQLサブプログラム

- SQL計画管理の記憶域アーキテクチャ

- SQL管理ベース

- SQL文のログ

- SQL計画履歴

- 有効化された計画

- 承認済の計画

- 固定計画

- SQL計画管理のユーザー・インタフェース

- Cloud Controlでの「SQL計画ベースライン」ページへのアクセス

- DBMS_SPMパッケージ

- SQL計画管理の基本タスク

- SQL計画管理の構成

- SQL計画ベースラインの取得と使用の構成

- SQL計画管理での初期計画自動取得の有効化

- すべてのSQL計画ベースラインの無効化

- SPM展開アドバイザのタスクの管理

- SPM展開アドバイザのタスクの有効化と無効化

- SPM展開アドバイザの自動タスクの構成

- SQL計画ベースラインでの計画の表示

- SQL計画ベースラインのロード

- SQLチューニング・セットからの計画のロード

- 共有SQL領域からの計画のロード

- ステージング表からの計画のロード

- SQL計画ベースラインの手動での展開

- DBMS_SPM展開ファンクションについて

- 展開タスクの管理

- SQL計画ベースラインの削除

- SQL管理ベースの管理

- SMBのディスク領域制限の変更

- SMBでの計画保存ポリシーの変更

24 ストアド・アウトラインのSQL計画ベースラインへの移行

- ストアド・アウトラインの移行について

- ストアド・アウトラインの移行の目的

- ストアド・アウトラインの移行方法

- ストアド・アウトラインの移行ステージ

- アウトラインのカテゴリとベースライン・モジュール

- ストアド・アウトラインの移行のためのユーザー・インタフェース

- ストアド・アウトラインの移行の基本ステップ

- ストアド・アウトラインの移行の準備

- アウトラインの移行によるSQL計画管理機能の使用

- アウトラインの移行でのストアド・アウトライン動作の保存

- ストアド・アウトラインの移行後のフォーローアップ・タスクの実行

A 索引および表クラスタに関するガイドライン

- 索引パフォーマンスのチューニングに関するガイドライン

- 論理構造のチューニングに関するガイドライン

- SQLアクセス・アドバイザの使用方法に関するガイドライン

- 索引を付ける列と式の選択に関するガイドライン

- コンポジット索引の選択に関するガイドライン

- コンポジット索引のキーの選択に関するガイドライン

- コンポジット索引のキーの順序付けに関するガイドライン

- 索引を使用するSQL文の記述に関するガイドライン

- 索引を使用しないSQL文の記述に関するガイドライン

- 索引の再作成に関するガイドライン

- 索引の縮小に関するガイドライン

- 一意でない索引による一意性の規定の使用方法に関するガイドライン

- ENABLE NOVALIDATE制約の使用方法に関するガイドライン

- パフォーマンスを考慮したファンクション索引の使用方法に関するガイドライン

- パフォーマンスを考慮したパーティション索引の使用方法に関するガイドライン

- パフォーマンスを考慮した索引構成表の使用方法に関するガイドライン

- パフォーマンスを考慮したビットマップ索引の使用方法に関するガイドライン

- パフォーマンスを考慮したビットマップ結合索引の使用方法に関するガイドライン

- パフォーマンスを考慮したドメイン索引の使用方法に関するガイドライン

- 表クラスタの使用に関するガイドライン

- パフォーマンスを考慮したハッシュ・クラスタの使用方法に関するガイドライン

用語集

索引

はじめに

このマニュアルでは、Oracle SQLのチューニング方法について説明します。

対象読者

このドキュメントは、次のタスクを実行するデータベース管理者およびアプリケーション開発者を対象としています。

- SQL実行計画を生成および解釈する

- オプティマイザ統計を管理する

- 初期化パラメータまたはSQLヒントを使用してオプティマイザに影響を与える

- SQL文のカーソル共有を制御する

- SQLの実行を監視する

- アプリケーション・トレースを実行する

- SQLチューニング・セットを管理する

- SQLチューニング・アドバイザまたはSQLアクセス・アドバイザを使用する

- SQLプロファイルを管理する

- SQL計画ベースラインを管理する

ドキュメントのアクセシビリティについて

オラクル社のアクセシビリティへの取組みの詳細は、Oracle Accessibility ProgramのWebサイトhttp://www.oracle.com/pls/topic/lookup?ctx=acc&id=docaccを参照してください。

Oracleサポートへのアクセス

サポートをご購入のOracleのお客様は、My Oracle Supportにアクセスして電子サポートを受けることができます。詳細は、http://www.oracle.com/pls/topic/lookup?ctx=acc&id=infoまたはhttp://www.oracle.com/pls/topic/lookup?ctx=acc&id=trs (聴覚障害者向け)を参照してください。

関連ドキュメント

このマニュアルは、『Oracle Database概要』を十分に理解していることを前提としています。次のガイドを頻繁に参照します。

- Oracle Databaseデータウェアハウス・ガイド

- 『Oracle Database VLDBおよびパーティショニング・ガイド』

- 『Oracle Database SQL言語リファレンス』

- 『Oracle Databaseリファレンス』

このマニュアルに記載されている多数の例は、Oracle Databaseで「基本インストール」オプションを選択した場合にデフォルトでインストールされるサンプル・スキーマを使用しています。それらのスキーマの作成方法および使用方法の詳細は、『Oracle Databaseサンプル・スキーマ』を参照してください。

表記規則

このマニュアルでは次の表記規則を使用します。

規則

意味

太字

太字は、操作に関連するGraphical User Interface要素、または本文中で定義されている用語および用語集に記載されている用語を示します。

イタリック体

イタリックは、ユーザーが特定の値を指定するプレースホルダ変数を示します。

固定幅フォント

固定幅フォントは、段落内のコマンド、URL、サンプル内のコード、画面に表示されるテキスト、または入力するテキストを示します。

Oracle Database SQLチューニング・ガイドのこのリリースでの変更

この章の内容は次のとおりです。

- Oracle Database 12cリリース1(12.1.0.2)での変更点

- Oracle Database 12cリリース1(12.1.0.1)での変更点

Oracle Database 12cリリース1 (12.1.0.2)での変更点

Oracle Database 12cリリース1(12.1.0.2)の『Oracle Database SQLチューニング・ガイド』には、次の変更があります。

新機能

このリリースの新機能は次のとおりです。

- インメモリー集計
この最適化により、スター・スキーマなどで、単一の大きな表を複数の小さな表に結合する際に各行に必要な結合およびGROUP BY処理が最小限に抑えられます。VECTOR GROUP BY集計では、パラレル問合せ(PQ)処理に関連するインフラストラクチャを使用し、それをCPU効率のよいアルゴリズムと組み合せて、ファクト・データの再分散前に実行される初期集計のパフォーマンスと効果を最大化します。

「インメモリー集計」を参照してください。

- 適応問合せ計画のSQL監視サポート
SQL監視では適応問合せ計画を次のようにサポートします。

- 問合せ計画が適応かどうかを示し、その現在のステータス(解決中または解決済)を表示します。

- 現在の問合せ計画、完全問合せ計画または最終問合せ計画を選択できるリストを提供します。
適応問合せ計画の詳細は「適応問合せ計画」を、SQL監視の詳細は「Cloud Controlを使用したSQL実行の監視」を参照してください。

Oracle Database 12cリリース1 (12.1.0.1)での変更点

Oracle Database 12cリリース1(12.1)の『Oracle Database SQLチューニング・ガイド』には、次の変更があります。

新機能

このリリースの新機能は次のとおりです。

- 適応SQL計画管理(SPM)
SPM展開アドバイザは、展開タスクのスケジュール、展開タスクの再実行および持続的なレポートの生成を可能にするタスク・インフラストラクチャです。新しい自動展開タスクSYS_AUTO_SPM_EVOLVE_TASKが、デフォルトのメンテナンス・ウィンドウに実行されます。このタスクは、承認されていないすべての計画をランク付けし、それらの展開プロセスを実行します。新しい計画のほうが既存の計画よりもパフォーマンスが高いとわかった場合、タスクは自動的にその計画を承認します。DBMS_SPMパッケージを使用して、手動で展開タスクを実行することもできます。

「SPM展開アドバイザのタスクの管理」を参照してください。

- 適応問合せ最適化
適応問合せ最適化は、オプティマイザが、実行計画に対する実行時の調整を行い、より優れた統計を導くための追加情報を検出できるようにするための一連の機能です。それには、次のような機能が含まれます。

- 適応問合せ計画
適応問合せ計画に用意されている組込みオプションを使用すると、文に対してデフォルトの計画とは異なる最終計画を使用できます。最初の実行時、特定のサブプランがアクティブになる前に、オプティマイザは、どのオプションを使用するかについて最終的な決定を行います。オプティマイザの選択は、この時点までの実行中に行われた監視に基づいています。オプティマイザが計画を適応することにより、問合せのパフォーマンスを向上させることができます。

「適応問合せ計画」を参照してください。

- 自動再最適化
自動再最適化を使用すると、オプティマイザは、問合せの初期実行を監視します。実際の実行統計が元の計画統計と大きく異なる場合、オプティマイザは、実行統計を記録し、次回その文が実行されるときにその実行統計を使用してより最適な計画を選択します。データベースでは、自動再最適化で取得された情報を使用して、自動的にSQL計画ディレクティブが生成されます。

「自動再最適化」を参照してください。

- SQL計画ディレクティブ
Oracle Database 12cより前のリリースの場合、データベースでは、コンパイルおよび実行に関する統計は、非永続の共有SQL領域に格納されていました。このリリースから、データベースでは、SQL計画ディレクティブを使用できるようになりました。SQL計画ディレクティブは、オプティマイザがより最適な計画の生成に使用できる追加の情報および命令です。データベースでは、SQL計画ディレクティブがSYSAUX表領域に永続的に格納されます。実行計画を生成する際、オプティマイザは、SQL計画ディレクティブを使用して、計画でアクセスするオブジェクトに関する詳細情報を取得できます。

「SQL計画ディレクティブ」を参照してください。

- 動的統計の拡張
Oracle Database 12cより前のリリースでは、動的統計(以前は動的サンプリングと呼ばれていました)は、問合せ内の1つ以上の表にオプティマイザ統計が存在しない場合にのみ使用されました。このリリースから、オプティマイザは、動的統計が有用であるかどうか、およびすべてのSQL文に対して使用する動的統計レベルを自動的に決定するようになりました。動的統計で収集された情報は、永続的であり、他の問合せで使用できます。

「補足的な動的統計」を参照してください。

- 新しいタイプのヒストグラム
このリリースでは、上位頻度ヒストグラムおよびハイブリッド・ヒストグラムが導入されています。列に254を超える個別値があり、かつ上位254の最頻出値の占める割合がデータの99%を超える場合は、上位254の最頻出値を使用して上位頻度ヒストグラムが作成されます。統計的には重要でない非ポピュラー値を無視することによって、データベースでは、頻繁に出現する値に関するより高品質なヒストグラムを作成できます。ハイブリッド・ヒストグラムは、拡張された高さ調整済ヒストグラムです。このヒストグラムでは、各エンドポイントの正確な頻度がサンプルに格納され、値が複数のバケットに格納されることはありません。

また、通常の頻度ヒストグラムも拡張されています。オプティマイザは、NDVの計算時に、小規模なサンプルではなくデータの全体スキャンに基づいて頻度ヒストグラムを計算します(AUTO_SAMPLING使用時)。拡張された頻度ヒストグラムでは、非常に頻度の低い値でも正確なバケット・カウントによってヒストグラム内で適切に表されます。

「ヒストグラム」を参照してください。

- データベース操作の監視
リアルタイムなデータベース操作の監視によって、長時間実行されるデータベース・タスク(バッチ・ジョブ、スケジューラ・ジョブ、データ抽出、変換およびロード(ETL)ジョブなど)の監視が可能になります。この機能は、監視対象のビジネス・オペレーションに関連付けられたSQLおよびPL/SQLの問合せの進行状況を追跡します。DBAまたは開発者は、オペレーションの開始と終了を明確に指定するか、またはオペレーションを識別するタグで暗黙的に指定することにより、監視用のビジネス・オペレーションを定義できます。

「データベース操作の監視」を参照してください。

- 同時統計収集
複数の表、表パーティションまたは表サブパーティションでオプティマイザ統計を同時に収集できます。マルチプロセッサ環境をフルに活用することで、データベースでは、統計の収集に必要な全体時間を短縮できます。Oracle SchedulerおよびAdvanced Queuingにより、統計を同時に収集するためのジョブが作成および管理されます。スケジューラは、使用可能なシステム・リソースとJOB_QUEUE_PROCESSES初期化パラメータの値に基づいて、同時に実行するジョブの数およびキューに入れるジョブの数を決定します。

「オプティマイザ統計の同時収集」を参照してください。

- DBMS_STATS統計収集関数のレポート作成モード
DBMS_STATS関数をレポート作成モードで実行できます。このモードでは、オプティマイザは、実際には統計を収集せずに、指定された統計収集関数を使用した場合に処理されるオブジェクトをレポートします。

「レポート作成モードでの統計収集関数の実行」を参照してください。

- 過去の統計収集操作に関するレポート
DBMS_STATS関数を使用して、特定の統計収集操作または特定の日時の間に発生した操作のレポートを作成できます。

「過去の統計収集操作のレポート作成」を参照してください。

- 列グループの自動作成
列グループの統計を使用すると、データベースでは、列のグループ(1つの単位として扱われます)に関するオプティマイザ統計が収集されます。Oracle Database 12cから、データベースは自動的に、指定のワークロードまたはSQLチューニング・セットで必要な列グループを判断し、それらの列グループを作成するようになりました。そのため、指定のどのワークロードについても、各表のどの列をグループ化する必要があるのかを知る必要はありません。

「特定のワークロードに対して有用な列グループの検出」を参照してください。

- グローバル一時表のセッション固有統計
このリリースから、グローバル一時表に、各セッションの異なるオプティマイザ統計セットが含まれるようになりました。セッション固有の統計により、ユーザーは、各セッションでグローバル一時表の統計を設定したり、動的統計を使用したりする必要がなくなるため、一時表のパフォーマンスと管理性が向上します。グローバル一時表に対するカーディナリティ見積りのエラーの可能性は低くなり、最適な実行計画の決定に必要な情報がオプティマイザに確実に存在するようになります。

「グローバル一時表のセッション固有統計」を参照してください。

- SQLテスト・ケース・ビルダーの拡張
SQLテスト・ケース・ビルダーにより、特定の動的および変動要因に依存するインシデントの診断を可能にするアクションおよびイベントを捕捉して再現できます。この機能は特に、パラレル問合せおよび自動メモリー管理に役に立ちます。

「SQLテスト・ケース・ビルダーを使用した診断データの収集」を参照してください。

- バルク・ロードのためのオンライン統計収集
バルク・ロードとは、CREATE TABLE AS SELECTまたはINSERT INTO ... SELECT操作です。Oracle Database 12cより前のリリースでは、失効した統計によって実行計画が最適なものとならない可能性を避けるため、バルク・ロードの後に手動で統計を収集する必要がありました。このリリースから、Oracle Databaseでは、オプティマイザ統計が自動的に収集されるようになりました。それにより、パフォーマンスと管理性の両方が向上します。

「バルク・ロードのためのオンライン統計収集」を参照してください。

- パーティション・メンテナンス操作後にシノプシスを再利用します。
ALTER TABLE EXCHANGEは共通のパーティション・メンテナンス操作です。パーティションの交換時に、パーティションおよび表の統計も交換されます。シノプシスとは、INCREMENTAL値がtrueに設定されている場合に、パーティション表で収集される一連の補助統計です。Oracle Database 12cより前のリリースでは、表にある表レベルのシノプシスは収集できませんでした。これにより、表にある表レベルのシノプシスの収集、表とパーティションの交換およびパーティションのシノプシスによる終了ができませんでした。増分モードでオプティマイザ統計を明示的に収集して、欠落しているシノプシスを作成する必要がありました。このリリースからは、表にある表レベルのシノプシスを収集できます。この表を、増分モードの表内のパーティションと交換する場合は、シノプシスも交換されます。

「パーティション・メンテナンス操作の増分統計の維持」を参照してください。

- 失効したまたはロックされたパーティション統計のある表に対するグローバル統計の自動更新
増分統計では、パーティションまたはサブパーティション統計が失効したりロックされている場合でも、パーティション表のグローバル統計を自動的に計算できます。

「失効したまたはロックされたパーティション統計のある表の増分統計の維持」を参照してください。

- キューブ問合せのパフォーマンスの向上
この向上により、CPUおよびメモリーの消費が最小化され、キューブに対する問合せのI/Oが削減されます。

CUBE JOIN操作の詳細は、表7-7を参照してください。

非推奨となった機能

次の機能は、今回のリリースで非推奨となっており、将来のリリースではサポートされなくなります。

- ストアド・アウトライン
代替機能については、「SQL計画ベースラインの管理」を参照してください。

- CURSOR_SHARING初期化パラメータのSIMILAR値
この値は非推奨です。かわりに、FORCEを使用してください。

「CURSOR_SHARINGをFORCEに設定するタイミング」を参照してください。

サポート対象外機能

このドキュメントで以前説明されていたいくつかの機能は、Oracle Database 12cではサポートされていません。サポート対象外機能のリストについては、『Oracle Databaseアップグレード・ガイド』を参照してください。

その他の変更

このリリースでのその他の変更は次のとおりです。

- 新しいチューニング・ガイド
Oracle Database 11gの『Oracle Databaseパフォーマンス・チューニング・ガイド』は、Oracle Database 12cでは次の2つのガイドに分けられました。

- Oracle Databaseパフォーマンス・チューニング・ガイド(データベースのチューニングに関連するトピックのみが含まれています)

- Oracle Database SQLチューニング・ガイド(SQLのチューニングに関連するトピックのみが含まれています)

第I部 SQLパフォーマンスの基本

この部には次の章が含まれます:

- SQLチューニングの概要

- 「SQLパフォーマンスの方法」

1 SQLチューニングの概要

SQLチューニングは、パフォーマンス基準を満たさないSQL文を診断および修復する試みです。

この章の内容は次のとおりです。

- SQLチューニングについて

- SQLチューニングの目的

- SQLチューニングの前提条件

- SQLチューニングのタスクとツール

SQLチューニングについて

SQLチューニングは、SQL文のパフォーマンスを、特定の測定可能かつ達成可能な目標に合うように向上させる反復プロセスです。

SQLチューニングには、デプロイ済アプリケーションの問題の解決も暗黙的に含まれます。対照的に、アプリケーション設計では、アプリケーションをデプロイする前にセキュリティおよびパフォーマンスの目標を設定します。

関連項目:

- 「SQLパフォーマンスの方法」

- SQLパフォーマンスを考慮した設計方法の詳細は、「アプリケーションの設計のガイドライン」を参照してください

SQLチューニングの目的

事前定義された測定可能な基準に沿ってSQL文を実行できない場合、そのSQL文は問題になります。

問題を特定した後、一般的なチューニング・セッションの目標は次のいずれかになります。

- ユーザー・レスポンス時間の短縮。これは、ユーザーが文を発行してからレスポンスを受け取るまでの時間を短縮することを意味します。

- スループットの向上。これは、文がアクセスするすべての行を処理するために必要なリソースの使用量を最小限に抑えることを意味します。

レスポンス・タイムの問題については、顧客がショッピング・カートを更新すると、3分間ハングしてしまうオンライン書店のアプリケーションを考えてみましょう。データベース・ホストのCPUをすべて消費する、データ・ウェアハウスにおける3分間のパラレル問合せ(他の問合せの実行は阻止されます)と対比してみてください。いずれのケースでも、ユーザー・レスポンス・タイムは3分間ですが、問題の原因は異なっており、したがってチューニングの目標も異なります。

SQLチューニングの前提条件

SQLチューニングには、データベース知識の基礎が必要です。

SQLをチューニングする場合、このマニュアルでは、読者に次の知識とスキルがあることを前提としています。

- データベース・アーキテクチャに精通している
データベース・アーキテクチャは、管理者のみが関係する領域ではありません。開発者としてOracle Databaseを使用するアプリケーションの開発にかかる時間を最小限に抑えるには、データベースのアーキテクチャおよび機能を利用する必要があります。たとえば、Oracle Databaseの並行性制御およびマルチバージョン読取りの一貫性について理解していないと、アプリケーションでデータの整合性を損なったり、アプリケーションの実行が遅くなったり、スケーラビリティが低下するおそれがあります。

『Oracle Database概要』で、Oracle Databaseの基本的なリレーショナル・データ構造、トランザクション管理、記憶域構造およびインスタンス・アーキテクチャについて説明しています。

- SQLおよびPL/SQLの知識
GUIベースのツールがあるため、SQLに関する知識がなくても、アプリケーションを作成し、データベースを管理することは可能です。ただし、SQLに関する知識なしにアプリケーションまたはデータベースをチューニングすることはできません。

『Oracle Database概要』には、Oracle SQLおよびPL/SQLの概要が含まれています。『Oracle Database SQL言語リファレンス』、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』および『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』の実用的な知識も必要です。

- データベースが提供するSQLチューニング・ツールに精通していること
データベースにより、パフォーマンス統計が生成され、それらの統計を解釈するためのSQLチューニング・ツールが提供されます。

主要なSQLチューニング・ツールの概要は、『Oracle Database 2日でパフォーマンス・チューニング・ガイド』を参照してください。

SQLチューニングのタスクとツール

チューニング・セッションの目標(たとえば、ユーザー・レスポンス・タイムを3分から1秒未満に短縮するなど)を設定したら、問題は、どうやってその目標を達成するかです。

Oracle推奨のチューニング方法の詳細は、「SQLパフォーマンスの方法」を参照してください。

SQLチューニング・タスク

チューニング・セッションの仕様は、事前チューニングを行うか、事後チューニングを行うかなど、多数の要因によって異なります。

事前のSQLチューニングでは通常、SQLチューニング・アドバイザを使用して、SQL文のパフォーマンスを向上させることができるかどうかを判断します。事後のSQLチューニングでは、ユーザーが経験したSQL関連の問題を解決します。

事前のチューニングを行うか、事後のチューニングを行うかに関係なく、一般的なSQLチューニング・セッションには、次のタスクのすべてまたはほとんどが含まれています。

1. 高負荷のSQL文の識別
過去の実行履歴を検討し、アプリケーションのワークロードおよびシステム・リソースの大部分に関係している文を識別します。

2. パフォーマンス関連のデータの収集
オプティマイザ統計は、SQLチューニングにとって非常に重要です。これらの統計が存在しないか、正確でない場合、オプティマイザは、最適な計画を生成することができません。SQLパフォーマンスに関連する他のデータには、文がアクセスした表やビューの構造、および文で使用可能な索引の定義などがあります。

3. 問題の原因の特定
通常、SQLパフォーマンスの問題の原因には、次のようなものがあります。

- SQL文の設計が非効率的である
SQL文が不要な作業を実行するように記述されている場合、パフォーマンスの改善のためにオプティマイザができることはあまりありません。非効率的な設計パターンの例を次に示します。

- 結合条件が追加されていないため、デカルト結合が発生する。

- ヒントによって大きな表を結合内の駆動表として指定する。

- UNION ALLではなくUNIONを指定する。

- 外部問合せの各行に対して副問合せを実行する。

- 最適ではない実行計画
問合せオプティマイザ(オプティマイザとも呼ばれます)は、どの実行計画が最も効率的かを判断する内部ソフトウェアです。オプティマイザは、データベースからデータを取り出すための手段として、アクセス・パスが最適ではない計画を選択することもあります。たとえば、選択性が低い問合せ述語に対する計画では、索引ではなく大きな表の全表スキャンを使用することが考えられます。

SQL文を最適に実行する実行計画と、最適ではないパフォーマンスの文の計画を比較できます。この比較を行うと、データ量の変化などの情報とあわせて、パフォーマンス低下の原因の識別に役立ちます。

- SQLアクセス構造がない
SQLパフォーマンスが最適なものとならない一般的な理由は、索引やマテリアライズド・ビューなど、SQLアクセス構造がないことです。アクセス構造の最適なセットにより、SQLパフォーマンスを桁違いに向上させることができます。

- 失効したオプティマイザ統計
DBMS_STATSによって収集された統計は、自動または手動の統計メンテナンス操作が、DMLによる表データの変更に対応できていない場合に失効します。失効した表の統計は、表データを正確に反映していないため、オプティマイザによって誤った情報に基づいた決定が行われ、最適ではない実行計画が生成される可能性があります。

- ハードウェアの問題
最適ではないパフォーマンスは、メモリー、I/OおよびCPUの問題に関係する場合があります。

4. 問題の範囲の定義
ソリューションの範囲は、問題の範囲と一致している必要があります。データベース・レベルと文レベルで問題を検討してください。たとえば、共有プールが小さすぎると、カーソルのエージ・アウトが速くなり、その結果、ハード解析が何度も行われます。初期化パラメータを使用して共有プールのサイズを増やすと、データベース・レベルの問題は解決され、すべてのセッションのパフォーマンスが向上します。ただし、単一のSQL文で有用な索引が使用されていない場合、データベース全体に対してオプティマイザの初期化パラメータを変更すると、全体的なパフォーマンスに悪影響を及ぼすおそれがあります。単一のSQL文に問題がある場合は、適切な範囲のソリューションでその文のその問題にのみ対処します。

5. 最適ではないパフォーマンスのSQL文に対する修正アクションの実装
これらのアクションは状況によって異なります。たとえば、SQL文をより効率的なものにリライトすることが考えられます。バインド変数を使用するように文をリライトすることで、不要なハード解析を回避します。また、等価結合を使用する、WHERE句からファンクションを削除する、複雑なSQL文を複数の単純な文に分けるといったことも考えられます。

場合によっては、文のリライトによってではなく、スキーマ・オブジェクトの再構築によってSQLパフォーマンスが向上することもあります。たとえば、新しいアクセス・パスの索引付けや、連結索引内の列の並替えなどです。また、表のパーティション化や導出値の導入に加えて、データベース設計の変更さえも考えられます。

6. SQLパフォーマンスの低下の回避
最適なSQLパフォーマンスを確保するには、実行計画が最適なパフォーマンスを実現し続けていることを確認し、より適切な計画が使用可能になったらそれらを採用します。オプティマイザ統計、SQLプロファイルおよびSQL計画ベースラインを使用して、これらの目標を達成できます。

関連項目:

「共有プール・チェック」

SQLチューニング・ツール

SQLチューニング・ツールは、自動または手動のいずれかです。

このコンテキストでは、データベース自体が分析、アドバイスまたは修正アクションを提供できるものは自動ツールになります。手動ツールでは、これらの操作すべてをユーザーが実行する必要があります。

すべてのチューニング・ツールは、データベース・インスタンスが収集する動的パフォーマンス・ビュー、統計およびメトリックの基本ツールに依存します。SQL文のチューニングに必要なデータとメタデータは、データベース自体に含まれています。

自動SQLチューニング・ツール

Oracle Databaseには、SQLチューニングに関連するいくつかのアドバイザが用意されています。

さらに、SQL計画管理は、パフォーマンスの低下を回避し、SQLパフォーマンスの向上にも役立つメカニズムです。

すべての自動SQLチューニング・ツールで、入力としてSQLチューニング・セットを使用できます。SQLチューニング・セット(STS)は、1つ以上のSQL文がその実行統計および実行コンテキストとともに含まれているデータベース・オブジェクトです。

関連項目:

「SQLチューニング・セットについて」

自動データベース診断モニター(ADDM)

ADDMは、Oracle Databaseに組み込まれている自己診断ソフトウェアです。

ADDMでは、パフォーマンスに関する問題の根本原因の特定、修正のための推奨事項の提示、および期待される利益の数値化を自動的に行うことができます。また、ADDMはアクションを必要としない領域を識別します。

ADDMおよび他のアドバイザでは、自動ワークロード・リポジトリ(AWR)が使用されます。これは、データベース・コンポーネントに統計の収集、保持および使用のためのサービスを提供するインフラストラクチャです。ADDMは、AWR内の統計を調べて分析し、高負荷SQLなど、パフォーマンスの問題となる可能性のある事柄を特定します。

たとえば、夜間実行されるようにADDMを構成できます。朝、担当者は、最新のADDMレポートを調べて、問題の原因と考えられることや推奨される解決策の有無を確認できます。レポートでは、たとえば、特定のSELECT文がCPUを大量に使用していることが示され、SQLチューニング・アドバイザの実行が推奨されています。

関連項目:

- Oracle Database 2日でパフォーマンス・チューニング・ガイド

- Oracle Databaseパフォーマンス・チューニング・ガイド

SQLチューニング・アドバイザ

SQLチューニング・アドバイザは、問題のあるSQL文を特定し、文のパフォーマンスの改善方法を提示する内部診断ソフトウェアです。

SQLチューニング・アドバイザが自動メンテナンス・タスクとしてデータベース・メンテナンス・ウィンドウに実行される場合、自動SQLチューニング・アドバイザと呼ばれます。

SQLチューニング・アドバイザは、入力として1つ以上のSQL文を取得し、自動チューニング・オプティマイザを起動して文に対するSQLチューニングを実行します。アドバイザは、次のタイプの分析を行います。

- 欠落している統計または失効している統計の有無をチェックする

- SQLプロファイルの構築
SQLプロファイルは、SQL文に固有の補足情報です。SQLプロファイルには、自動SQLチューニングの際に検出された最適ではないオプティマイザの見積りに対する修正が含まれます。この情報は、カーディナリティおよび選択性に関するオプティマイザの見積りを向上させることができます。カーディナリティとは、実行計画で操作によって戻される見積りの行数または実際の行数です。これらの精度が増した見積りにより、オプティマイザはより適切な計画を選択できるようになります。

- 別のアクセス・パスによってパフォーマンスを大幅に改善できるかどうかを調査する。

- 最適ではない計画の原因となっているSQL文を特定する。

SQLチューニング・アドバイザの実行結果は、アドバイスまたは推奨事項の形式で出力され、推奨事項ごとに論理的根拠および予想される利点が示されます。推奨事項は、オブジェクトの統計、新しい索引の作成、SQL文の再構成またはSQLプロファイルの作成に関するものです。ユーザーは、推奨事項を受け入れるかどうかを選択してSQL文のチューニングを完了できます。

関連項目:

- SQLチューニング・アドバイザを使用したSQLの分析

- Oracle Database 2日でパフォーマンス・チューニング・ガイド

SQLアクセス・アドバイザ

SQLアクセス・アドバイザは、どのマテリアライズド・ビュー、索引およびマテリアライズド・ビュー・ログを作成、削除または保持するのが適切かを提示する内部診断ソフトウェアです。

SQLアクセス・アドバイザは、入力として実際のワークロードを使用します。または、スキーマから仮想ワークロードを導出することもできます。SQLアクセス・アドバイザでは、領域使用量と問合せパフォーマンスの兼合いが考慮され、新規および既存のマテリアライズド・ビューおよび索引の最もコスト効率の高い構成が推奨されます。アドバイザはまた、パーティション化に関する推奨事項も提示します。

関連項目:

- 「SQLアクセス・アドバイザについて」

- Oracle Database 2日でパフォーマンス・チューニング・ガイド

SQL計画管理

SQL計画管理は、データベースで既知の計画または確認済の計画のみが使用されるようにオプティマイザで実行計画を自動的に管理する予防的なメカニズムです。

このメカニズムにより、SQL計画ベースラインを構築できます。これには、各SQL文の承認済計画が1つ以上含まれます。SQL計画管理では、ベースラインを使用することで、環境の変化による計画の不具合を回避しつつ、オプティマイザがより適切な計画を検出して使用できるようにします。

関連項目:

「SQL計画管理について」

SQLパフォーマンス・アナライザ

SQLパフォーマンス・アナライザは、SQL文ごとのパフォーマンスの相違を識別することで、SQLワークロードに対する変更の影響を判断します。

データベースのアップグレードや索引の追加などのシステム変更によって、実行計画が変更され、SQLパフォーマンスに影響を与えることがあります。SQLパフォーマンス・アナライザを使用することで、システム変更がSQLパフォーマンスに与える影響を正確に予測できるようになります。この情報を使用して、SQLパフォーマンスの低下時にデータベースのチューニングを行うことや、SQLパフォーマンスが向上することによって得られる利益を検証および評価することが可能です。

関連項目:

「Oracle Database Testingガイド」

手動SQLチューニング・ツール

状況によっては、自動ツールに加えて手動ツールの実行が必要になる場合もあります。または、自動ツールを使用できないことも考えられます。

実行計画

実行計画は、手動SQLチューニングの主要な診断ツールです。たとえば、計画を表示して、オプティマイザが想定どおりの計画を選択しているかどうかを確認したり、表での索引作成の効果を特定したりすることができます。

複数の方法で実行計画を表示できます。最もよく使用されるツールは次のとおりです。

- 「EXPLAIN PLAN」
このSQL文では、実際にSQL文を実行せずに、オプティマイザがSQL文の実行に使用する実行計画を表示できます。『Oracle Database SQL言語リファレンス』を参照してください。

- AUTOTRACE
SQL*PlusのAUTOTRACEコマンドは、実行計画と、問合せのパフォーマンスに関する統計を生成します。このコマンドにより、ディスク読取りやメモリー読取りなどの統計が提供されます。『SQL*Plusユーザーズ・ガイドおよびリファレンス』を参照してください。

- V$SQL_PLANおよび関連ビュー
これらのビューには、まだ共有プール内に存在する実行済SQL文に関する情報、およびそれらの実行計画が含まれています。『Oracle Databaseリファレンス』を参照してください。

DBMS_XPLANパッケージ・メソッドを使用して、EXPLAIN PLANコマンドおよびV$SQL_PLANの問合せによって生成された実行計画を表示できます。

リアルタイムなSQL監視およびリアルタイムなデータベース操作

OracleデータベースのリアルタイムSQL監視機能では、SQL文の実行中にそのパフォーマンスを監視できます。デフォルトでは、文がパラレルで実行される場合、または1回の実行で5秒以上のCPUまたはI/O時間を消費している場合に、SQL監視が自動的に開始されます。

データベース操作は、バッチ・ジョブまたはデータ抽出、変換およびロード(ETL)処理など、エンド・ユーザーまたはアプリケーション・コードで定義された一連のデータベース・タスクです。データベース操作の定義、監視およびレポート生成が可能です。リアルタイムなデータベース操作では、複合操作を自動的に監視できます。データベースは、パラレルな問合せ、DML文およびDDL文を、実行の開始と同時に自動的に監視します。

Oracle Enterprise Manager Cloud Control (Cloud Control)には、使いやすいSQL監視ページが用意されています。または、V$SQL_MONITORおよびV$SQL_PLAN_MONITORビューを使用して、SQL関連の統計を監視することができます。これらのビューを次のビューとともに使用して、監視対象の実行に関する詳細情報を取得できます。

- V$ACTIVE_SESSION_HISTORY

- V$SESSION

- V$SESSION_LONGOPS

- V$SQL

- V$SQL_PLAN

関連項目:

- 「データベース操作の監視について」

- V$ビューの詳細は、『Oracle Databaseリファレンス』を参照してください。

アプリケーションのトレース

SQLトレース・ファイルには、解析件数、物理および論理読取り、ライブラリ・キャッシュでのミスなど、個々のSQL文に関するパフォーマンス情報が記録されています。この情報を使用して、SQLパフォーマンスの問題を診断できます。

DBMS_MONITORまたはDBMS_SESSIONパッケージを使用して、特定のセッションのSQLトレースを有効または無効にできます。Oracle Databaseでは、トレース・メカニズムが有効化されたときに各サーバー・プロセスのトレース・ファイルを生成することによって、トレースを実装します。

Oracle Databaseでは、トレース・ファイルの分析のために次のコマンドライン・ツールが用意されています。

- TKPROF
このユーティリティは、SQLトレース機能によって生成されたトレース・ファイルを入力として受け入れ、フォーマットされた出力ファイルを生成します。

- trcsess
このユーティリティでは、セッションID、クライアントID、サービスIDなどの基準に基づいて、複数のトレース・ファイルからのトレース出力が統合されます。trcsessによりトレース情報が単一の出力ファイルにマージされた後、TKPROFを使用して出力ファイルをフォーマットできます。trcsessは、パフォーマンスまたはデバッグの目的で特定のセッションのトレースを統合する際に役立ちます。

エンドツーエンド・アプリケーションのトレースは、複数層環境のパフォーマンス上の問題の診断プロセスを単純化します。これらの環境では、エンド・クライアントからのリクエストは中間層により様々なデータベース・セッションにルーティングされるため、異なるデータベース・セッション間でクライアントを追跡するのは困難です。エンドツーエンド・アプリケーションのトレースでは、クライアントIDを使用して、データベースへのすべての層を通じて特定のエンドクライアントを一意にトレースします。

関連項目:

DBMS_MONITORおよびDBMS_SESSIONの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

オプティマイザ・ヒント

ヒントは、SQL文のコメントを介してオプティマイザに渡される命令です。ヒントを使用すると、通常はオプティマイザによって自動的に行われる決定をユーザーが行うことが可能になります。

テスト環境または開発環境で、ヒントを使用して特定のアクセス・パスのパフォーマンスをテストできます。たとえば、ある問合せに対しては、特定の索引を選択する方がよい場合もあります。この場合は、次の例に示すように、ヒントを使用して、オプティマイザが適切な実行計画を使用するように指示できます。

SELECT /*+ INDEX (employees emp_department_ix) */
employee_id, department_id
FROM   employees
WHERE  department_id > 50;

関連項目:

「ヒントによるオプティマイザへの影響」

SQLチューニング・ツールへのユーザー・インタフェース

Cloud Controlは、データベース環境を集中管理するためのシステム管理ツールです。Cloud Controlは、ほとんどのチューニング・ツールにアクセスできます。

グラフィカル・コンソール、Oracle Management Server、Oracle Intelligent Agent、共通サービスおよび管理ツールを組み合せることで、Cloud Controlは、包括的なシステム管理プラットフォームを提供します。

コマンドライン・インタフェースを使用して、すべてのSQLチューニング・ツールにアクセスすることもできます。たとえば、DBMS_ADVISORパッケージは、SQLチューニング・アドバイザのためのコマンドライン・インタフェースです。

データベース管理およびチューニングのための最適なインタフェースとしてCloud Controlを使用することをお薦めします。コマンドライン・インタフェースのほうが特定の概念やタスクをよりわかりやすく説明できる場合、このマニュアルではコマンドラインの例を使用しています。ただし、その場合、チューニング・タスクには、タスクに関連付けられている主要なCloud Controlページへの参照が含まれます。

2 SQLパフォーマンスの方法

この章では、お薦めするSQLチューニングの方法について説明します。

この章の内容は次のとおりです。

- アプリケーションの設計のガイドライン

- アプリケーションのデプロイのガイドライン

アプリケーションの設計のガイドライン

良好なSQLパフォーマンスを得るには、パフォーマンスを考慮してアプリケーションを設計することが重要になります。

この項の内容は次のとおりです。

- データのモデル化のガイドライン

- 効率的なアプリケーションの作成のガイドライン

データのモデル化のガイドライン

データのモデル化は、アプリケーションの適切な設計に重要です。

データのモデル化によって、ビジネス・プラクティスを表現する必要があります。正しいデータ・モデルに関して様々な議論が展開される場合があります。重要なことは、最も頻繁に行われるビジネス・トランザクションの影響を受けるエンティティをモデル化の主な対象にすることです。

モデル化フェーズでは、あまり重要でないデータ要素のモデル化に時間を取られることがあり、開発の準備期間が延長される結果になります。モデル化ツールを使用すると、スキーマ定義をすばやく生成できます。また、短期間でプロトタイプを作成する必要がある場合に便利です。

効率的なアプリケーションの作成のガイドライン

システム開発の設計およびアーキテクチャ・フェーズでは、アプリケーション開発者がSQLの実行効率を理解している必要があります。

この目標を達成するには、開発環境が次の特性をサポートしている必要があります。

- データベース接続の適切な管理
データベースへの接続は、コストが高くスケーラブルでない操作です。そのため、ベスト・プラクティスは、データベースへの同時接続数を最小限に抑えることです。アプリケーションの初期化時にユーザーが1人接続しているという単純なシステムが理想的です。しかし、Webベース・アプリケーションや多層アプリケーションでは、複数のアプリケーション・サーバーによりユーザーへのデータベース接続が多重化しているため、接続数を少なくするのは困難です。このようなタイプのアプリケーションの場合、データベース接続をプールし、ユーザー・リクエストごとに接続を再確立しないように設計します。

- カーソルの適切な使用および管理
ユーザー接続のメンテナンスも、システムでの解析アクティビティの最小化にとっては同じように重要です。解析とは、SQL文を解釈し、そのSQL文の実行計画を作成する処理です。この処理には、構文検査、セキュリティ検査、実行計画の生成、共有プールへの共有構造のロードなど、多くのフェーズがあります。解析操作には、次の2種類があります。

- ハード解析
SQL文が初めて送信され、共有プール内に一致するものがない場合です。ハード解析は、解析に関連するすべての操作を実行するため、最もリソース集中型であり、スケーラブルではありません。

- ソフト解析
SQL文が初めて送信され、共有プール内に一致が見つかった場合です。別のユーザーが以前に実行した結果が一致することがあります。SQL文は共有されるため、最適なパフォーマンスが実現します。ただし、ソフト解析では、システム・リソースを消費する構文検査やセキュリティ検査が必要であり、理想的とはいえません。

解析はできるだけ最小限にする必要があるため、アプリケーション開発者は、SQL文を1回解析し、そのSQL文を複数回実行するようにアプリケーションを設計してください。これは、カーソルを使用して行います。経験のあるSQLプログラマであれば、カーソルのオープンと再実行の概念を理解しています。

- バインド変数の効果的な使用
アプリケーション開発者は、SQL文が共有プール内で共有されるようにする必要もあります。この目標を達成するには、問合せの中で実行ごとに変化する部分をバインド変数として表します。これを行わないと、SQL文は1回解析された後、他のユーザーから再利用されない可能性があります。SQLの共有を確実にするには、SQL文ではバインド変数を使用し文字列リテラルは使用しないようにします。次に例を示します。

文字列リテラルがある文は、次のとおりです。

SELECT *
FROM   employees
WHERE  last_name LIKE 'KING';

バインド変数がある文は、次のとおりです。

SELECT *
FROM   employees
WHERE  last_name LIKE :1;

次の例は、単純なOLTPアプリケーションでのテスト結果です。

Test                         #Users Supported
No Parsing all statements           270
Soft Parsing all statements         150
Hard Parsing all statements          60
Re-Connecting for each Transaction   30

このテストは、4台のCPUを搭載したコンピュータで実行されました。システム上のCPUの数が増えると、差異も大きくなります。

アプリケーションのデプロイのガイドライン

パフォーマンスを最適化するには、設計時と同様の注意を払ってアプリケーションをデプロイする必要があります。

この項の内容は次のとおりです。

- テスト環境でのデプロイのガイドライン

- アプリケーションのロールアウトのガイドライン

テスト環境でのデプロイのガイドライン

テスト・プロセスは、主に機能テストと安定性テストで構成されます。このプロセスの途中で、パフォーマンス・テストを実行する必要があります。

アプリケーションのパフォーマンス・テストを実行するときの簡単な規則を説明したリストを次に示します。適切に文書化した場合、このリストは、アプリケーション稼働後の本番アプリケーションと容量計画プロセスにとって重要な情報を提供します。

- 自動データベース診断モニター(ADDM)とSQLチューニング・アドバイザを使用した設計の検証

- 現実的なデータ量とデータ配分によるテスト
すべてのテストは、データが完全に含まれている表を使用して行う必要があります。テスト用データベースには、データ量や表のカーディナリティという点で本番システムと同様のデータを入れておく必要があります。本番と同様の索引をすべて作成し、スキーマ統計を正しく入力します。

- 正しいオプティマイザ・モードの使用
すべてのテストは、本番で使用するオプティマイザ・モードで実行する必要があります。

- シングル・ユーザーのパフォーマンスのテスト
アイドル状態または使用率の低いデータベースで、シングル・ユーザーのパフォーマンスが許容範囲にあるかテストします。シングル・ユーザーのパフォーマンスが理想的な条件下で許容範囲に達しない場合、実際の条件下で複数のユーザーが許容可能なパフォーマンスを得ることはできません。

- 全SQL文の計画の取得と文書化
各SQL文の実行計画を取得します。このプロセスを使用して、オプティマイザの実行計画が最適かどうか、およびSQL文の相対コストがCPU時間と物理I/O数の観点から把握されているかどうかを検証します。このプロセスは、将来において多くのチューニングおよびパフォーマンスの必要な頻繁に使用されるトランザクションを識別するのに役立ちます。

- マルチ・ユーザーのテスト。
ユーザーのワークロードやプロファイルがまだ完全に定量化されていない可能性があるため、このプロセスを正確に実行するのは困難です。しかし、DML文を実行するトランザクションをテストして、ロックの競合やシリアライズの問題がないことは確認する必要があります。

- 正しいハードウェア構成でのテスト
できるだけ本番システムに近い構成でテストを行います。実際的なシステムの使用は、ネットワーク待機時間、I/Oサブシステム帯域幅およびプロセッサのタイプと速度についてテストする場合に特に重要です。このアプローチを使用しなかった場合、潜在的なパフォーマンスの問題を正しく分析できません。

- 安定した状態でのパフォーマンスの測定
ベンチマークを行うときは、安定した状態でパフォーマンスを測定することが重要です。各ベンチマークの実行には開始フェーズが必要です。このフェーズでは、ユーザーがアプリケーションに接続し、アプリケーションでの作業を徐々に開始します。このプロセスによって、安定した状態になる前に、頻繁にキャッシュされるデータをキャッシュに初期化し、解析などの1回のみ実行する操作を完了しておくことができます。同様に、ベンチマークの実行後は、システムがリソースを解放し、ユーザーが作業を終了して接続を切断できるようにするために、終了フェーズが役立ちます。

アプリケーションのロールアウトのガイドライン

新しいアプリケーションをロールアウトするときは、次の2つの方法が一般的に採用されます。ビッグ・バン・アプローチでは、すべてのユーザーが一度に新しいシステムに移行します。トリクル・アプローチでは、ユーザーは既存のシステムから新しいシステムに徐々に移行します。

いずれの方式にもメリットとデメリットがあります。ビッグ・バン・アプローチでは、必要な規模でアプリケーションを十分にテストしておく必要がありますが、旧システムは完全に使用されなくなるため、旧システムからのデータの変換と旧システムとの同期が最小限で済みます。トリクル・アプローチでは、ワークロードの増加に伴いスケーラビリティの問題をデバッグできますが、移行中に旧システムとの間でデータを相互に移行する必要性が発生することがあります。

いずれの手法も、それぞれ移行実施中にシステムの停止につながるリスクがあるため、どちらかを推奨することは困難です。トリクル・アプローチでは、実際のユーザーが新しいアプリケーションに移行するにつれてユーザー・プロファイルを作成できるので、システムを再構成しても、その影響を受けるのは移行済ユーザーのみです。この方式は、初期の段階で移行したユーザーの作業に影響を与えますが、サポート・サービスの負荷は限定されます。そのため、スケジュール外の停止が発生しても、影響を受けるユーザーの割合は小さくて済みます。

新規アプリケーションのロールアウト方法は、ビジネスごとに判断してください。採用するどのアプローチにも、それぞれ固有の長所と短所があります。テストを重ねて、そのテストから得られた知識が増えるほど、最善のロールアウト方式を判断できます。

第II部 問合せオプティマイザの基礎

この部には次の章が含まれます:

- SQLの処理

- 問合せオプティマイザの概念

- 問合せ変換

3 SQLの処理

この章では、データベースがDDL文を処理してオブジェクトを作成する方法、DMLを使用してデータを変更する方法、問合せを使用してデータを取得する方法について説明します。

この章の内容は次のとおりです。

- SQL処理について

- Oracle DatabaseによるDML処理方法

- Oracle DatabaseによるDDLの処理方法

SQL処理について

SQL処理とは、SQL文の解析、最適化、行ソース生成および実行を行うことです。文によっては、データベースがこれらの段階の一部を省略する場合があります。

次の図は、SQL処理の全体的な段階を示しています。

図3-1 SQL処理の段階

SQLの解析

SQL処理の最初の段階は、解析です。

解析段階では、SQL文の各部分を他のルーチンで処理できるデータ構造に分解する処理が行われます。Oracle Databaseは、アプリケーションから指示されたときに文を解析するため、解析回数を削減できるのはアプリケーションのみです(Oracle Database自体ではありません)。

アプリケーションがSQL文を発行すると、アプリケーションはOracle Databaseに解析コールを出して、文の実行を準備します。解析コールによって、解析済のSQL文と処理に使用するその他の情報が保持されるセッション固有のプライベートSQL領域のハンドルであるカーソルがオープンまたは作成されます。カーソルおよびプライベートSQL領域は、プログラム・グローバル領域(PGA)内にあります。

解析コール時には、データベースでは次のチェックを実行します。

- 構文チェック

- セマンティクス・チェック

- 共有プール・チェック

これらのチェックによって、文の実行前に検出できるエラーを特定します。解析では捕捉できないエラーもあります。たとえば、データベースで、文の実行時にのみ、データ変換に関するデッドロックまたはエラーが発生する場合があります。

関連項目:

デッドロックの詳細は、『Oracle Database概要』を参照してください。

構文チェック

Oracle Databaseは各SQL文の構文上の妥当性を必ずチェックします。

SQL構文の形式が整っていても、規則に違反している文はチェックが失敗します。たとえば、次の文ではキーワードFROMがFORMという誤ったスペルになっているため、失敗します。

SQL> SELECT * FORM employees;
SELECT * FORM employees
*
ERROR at line 1:
ORA-00923: FROM keyword not found where expected

セマンティクス・チェック

文のセマンティクスとは、文の意味のことです。セマンティクス・チェックでは、文内のオブジェクトおよび列が存在するかどうかなど、文の意味が有効かどうかを判断します。

次に示す存在しない表の問合せの例のように、構文的に正しい文でも、セマンティクス・チェックに失敗します。

SQL> SELECT * FROM nonexistent_table;
SELECT * FROM nonexistent_table
*
ERROR at line 1:
ORA-00942: table or view does not exist

共有プール・チェック

解析中、データベースは共有プール・チェックを実行して、文の処理のうちリソース集中型の手順を省略できるかどうかを判断します。

これを行うために、データベースはハッシング・アルゴリズムを使用してSQL文ごとにハッシュ値を生成します。文のハッシュ値は、V$SQL.SQL_IDに示されるSQL IDです。このハッシュ値は、同一バージョンのOracle Databaseにおいて一定であるため、単一インスタンスまたは別のインスタンスにおける同じ文は同じSQL IDになります。

ユーザーがSQL文を発行すると、データベースは共有SQL領域を検索して、既存の解析済の文に同じハッシュ値があるかどうかを確認します。SQL文のハッシュ値は、次の値とは異なります。

- 文のメモリー・アドレス
Oracle Databaseでは、SQL IDをキーとして使用して検索対象の表を読み取ります。これにより、Oracle Databaseは文のメモリー・アドレスを取得します。

- 文の実行計画のハッシュ値
1つのSQL文で、複数の計画を共有プールに設定できます。通常、各計画には、異なるハッシュ値を設定します。同じSQL IDに複数の計画ハッシュ値が設定されていると、Oracle Databaseでは、そのSQL IDに対して複数の計画が存在することが認識されます。

発行される文のタイプとハッシュ・チェックの結果に応じて、解析操作は次のカテゴリに分類されます。

- ハード解析
Oracle Databaseは、既存のコードを再利用できない場合、新しく実行可能なバージョンのアプリケーション・コードを作成する必要があります。この操作はハード解析またはライブラリ・キャッシュ・ミスと呼ばれます。

注意:

データベースは常にDDLのハード解析を実行します。

ハード解析時には、データベースはライブラリ・キャッシュおよびデータ・ディクショナリ・キャッシュに何度もアクセスして、データ・ディクショナリをチェックします。データベースはこれらの領域にアクセスするとき、定義が変更されないように、必要なオブジェクト上にラッチと呼ばれるシリアライズ・デバイスを使用します。ラッチの競合が発生すると、文の実行時間が長くなり、同時実行性が低下します。

- ソフト解析
ソフト解析は、ハード解析以外のすべての解析です。発行される文が共有プール内の再利用可能なSQL文と同じ場合、Oracle Databaseは既存のコードを再利用します。コードの再利用は、ライブラリ・キャッシュ・ヒットとも呼ばれます。

ソフト解析によって実行される作業の量は、解析ごとに異なる場合があります。たとえば、セッションの共有SQL領域の構成によって、ソフト解析はラッチ量が減少し、よりソフト解析らしくなる場合があります。

データベースが最適化および行ソース生成の手順を省略してそのまま実行に進むため、通常ソフト解析はハード解析よりも優れています。

次の図に、専用サーバー・アーキテクチャのUPDATE文の共有プール・チェックを簡単に示します。

図3-2 共有プール・チェック

チェックにより、共有プール内の文に同じハッシュ値があると判断された場合、データベースはセマンティクス・チェックおよび環境チェックを実行して、文の意味が同一かどうかを判断します。構文が同一であるだけでは不十分です。たとえば、データベースに異なる2人のユーザーがログインし、次のSQL文を発行したと想定します。

CREATE TABLE my_table ( some_col INTEGER );
SELECT * FROM my_table;

2人のユーザーのSELECT文は構文上同一ですが、2つの別々のスキーマ・オブジェクトがmy_tableという名前になっています。この意味の相違によって、2番目の文では最初の文のコードを再利用できません。

2つの文が意味的に同一であったとしても、環境の違いによりハード解析が強制的に行われることがあります。この場合のオプティマイザ環境とは、作業領域サイズまたはオプティマイザの設定(たとえば、オプティマイザ・モード)など、実行計画の生成に影響する可能性があるすべてのセッション設定です。単一のユーザーによって実行される次の一連のSQL文を考えてみます。

ALTER SESSION SET OPTIMIZER_MODE=ALL_ROWS;
ALTER SYSTEM FLUSH SHARED_POOL;               # optimizer environment 1
SELECT * FROM sh.sales;

ALTER SESSION SET OPTIMIZER_MODE=FIRST_ROWS;  # optimizer environment 2
SELECT * FROM sh.sales;

ALTER SESSION SET SQL_TRACE=true;             # optimizer environment 3
SELECT * FROM sh.sales;

この例では、同じSELECT文が3つの異なるオプティマイザ環境で実行されます。結果として、データベースはこれらの文に対して3つの個別の共有SQL領域を作成し、各文にハード解析を強制的に実行します。

関連項目:

- プライベートSQL領域および共有SQL領域の詳細は、『Oracle Database概要』を参照してください。

- 共有プールの構成方法の詳細は、『Oracle Databaseパフォーマンス・チューニング・ガイド』を参照してください。

- ラッチの詳細は、『Oracle Database概要』を参照してください。

SQLの最適化

最適化の段階では、Oracle Databaseは、一意のDML文ごとに必ず1回以上のハード解析を実行して、この解析中に最適化を実行します。

最適化を要求する副問合せなどのDMLコンポーネントを含まないかぎり、データベースはDDLを最適化しません。

SQLの行ソース生成

行ソース・ジェネレータは、オプティマイザから最適な実行計画を受け取り、データベースのその他の部分で使用可能な反復実行計画を作成するソフトウェアです。

反復計画は、SQLエンジンで実行される場合に、結果セットを作成するバイナリ・プログラムです。計画では、手順の組合せ形式を使用します。各手順では行セットが戻されます。次のステップでは、このセットの行を使用するか、最後のステップで、SQL文を発行しているアプリケーションに行を戻します。

行ソースは、行を反復的に処理できる制御構造に沿って、実行計画の手順から戻された行セットです。表、ビュー、または結合処理あるいはグループ化処理の結果が行ソースになる可能性があります。

行ソース・ジェネレータは、行ソースのコレクションである行ソース・ツリーを作成します。行ソース・ツリーには次の情報が表示されます。

- 文によって参照される表の順序

- 文で言及される各表へのアクセス方法

- 文の結合操作の影響を受ける表の結合方法

- フィルタ、ソートまたは集計などのデータ操作

例3-1 実行計画

この例に、AUTOTRACEが有効な場合のSELECT文の実行計画を示します。この文では、姓が文字Aで始まるすべての従業員の姓、職種、部門名を選択します。この文の実行計画は行ソース・ジェネレータから出力されます。

SELECT e.last_name, j.job_title, d.department_name
FROM   hr.employees e, hr.departments d, hr.jobs j
WHERE  e.department_id = d.department_id
AND    e.job_id = j.job_id
AND    e.last_name LIKE 'A%';

Execution Plan
----------------------------------------------------------
Plan hash value: 975837011

--------------------------------------------------------------------------------
| Id| Operation                     | Name        |Rows|Bytes|Cost(%CPU)|Time  |
--------------------------------------------------------------------------------
| 0 | SELECT STATEMENT              |             |  3 | 189 | 7(15)| 00:00:01 |
|*1 |  HASH JOIN                    |             |  3 | 189 | 7(15)| 00:00:01 |
|*2 |   HASH JOIN                   |             |  3 | 141 | 5(20)| 00:00:01 |
| 3 |    TABLE ACCESS BY INDEX ROWID| EMPLOYEES   |  3 |  60 | 2 (0)| 00:00:01 |
|*4 |     INDEX RANGE SCAN          | EMP_NAME_IX |  3 |     | 1 (0)| 00:00:01 |
| 5 |    TABLE ACCESS FULL          | JOBS        | 19 | 513 | 2 (0)| 00:00:01 |
| 6 |   TABLE ACCESS FULL           | DEPARTMENTS | 27 | 432 | 2 (0)| 00:00:01 |
--------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

1 - access("E"."DEPARTMENT_ID"="D"."DEPARTMENT_ID")
2 - access("E"."JOB_ID"="J"."JOB_ID")
4 - access("E"."LAST_NAME" LIKE 'A%')
filter("E"."LAST_NAME" LIKE 'A%')

SQLの実行

実行時には、SQLエンジンが行ソース・ジェネレータによって作成されたツリー内の各行ソースを実行します。この手順のみがDML処理の必須手順です。

図3-3は、例3-1の計画の各手順間の行ソースのフローを示す実行ツリー(解析ツリーとも呼ばれる)です。通常、実行時の手順の順序は計画時の順序とは逆になるため、計画の場合は下から上へと読み取ります。

実行計画の各手順にはID番号があります。図3-3の番号は、例3-1に示されている計画のId列に対応します。計画のOperation列の最初のスペースは階層の関係を示します。たとえば、操作の名前の前に2つのスペースがある場合、この処理は1つのスペースの後続となる子処理です。前に1つのスペースがある操作は、SELECT文自体の子です。

図3-3 行ソース・ツリー

図3-3では、ツリーの各ノードが行ソースとして機能しており、例3-1の実行計画の各手順がデータベースから行を取得するか、1つ以上の行ソースから入力として行を受け取ります。SQLエンジンは各行のソースを次のように実行します。

- 黒のボックスで示された手順は、データベース内のオブジェクトから物理的にデータを取り出します。これらの手順はアクセス・パス、つまりデータベースからデータを取得する技法です。

- 手順6は全表スキャンを使用してdepartments表のすべての行を取得します。

- 手順5は全表スキャンを使用してjobs表のすべての行を取得します。

- 手順4はemp_name_ix索引を順番にスキャンして、文字Aで始まる各キーを検索し、該当のROWIDを取得します。たとえば、Atkinsonに対応するROWIDはAAAPzRAAFAAAABSAAeです。

- 手順3はemployees表から手順4でROWIDが戻された行を取得します。たとえば、データベースはROWID AAAPzRAAFAAAABSAAeを使用して、Atkinsonの行を取得します。

- 透明のボックスで示された手順は行ソースを操作します。

- 手順2はハッシュ結合を実行して、手順3および5から行ソースを受け取り、手順5の行ソースからの各行を手順3の対応する行と結合して、手順1に結果の行を戻します。
たとえば、従業員Atkinsonの行は職種Stock Clerkに関連付けられています。

- 手順1は別のハッシュ結合を実行して、手順2および6から行ソースを受け取り、手順6のソースからの各行を手順2の対応する行と結合して、クライアントに結果を戻します。
たとえば、従業員Atkinsonの行は部門名Shippingに関連付けられています。

実行計画には、手順が反復して実行されるものと、連続して実行されるものがあります。例3-1に示されているハッシュ結合は連続して実行されます。データベースでは、結合順序に基づいて手順がすべて実行されます。データベースでは、emp_name_ixの索引レンジ・スキャンから開始されます。索引から取得されるROWIDを使用して、データベースは、employees表内の一致する行を読み取り、jobs表をスキャンします。jobs表から行を取得した後、データベースでは、ハッシュ結合が実行されます。

実行中、データがメモリー内にない場合は、データベースがディスクからメモリーへとデータを読み取ります。また、データベースはデータ整合性を保証するために必要なすべてのロックおよびラッチを取り除き、SQL実行時に行われたすべての変更を記録します。SQL文の処理の最後の段階は、カーソルのクローズです。

Oracle DatabaseによるDML処理方法

ほとんどのDML文には問合せコンポーネントがあります。問合せでは、カーソルを実行すると、問合せの結果が結果セットと呼ばれる行の集合に配置されます。

行セットのフェッチ方法

結果セットの行は、1行ごとにまたはグループ単位でフェッチできます。

フェッチ段階では、データベースで行が選択され、問合せで要求された場合には行が順序付けされます。最後の行がフェッチされるまで、毎回のフェッチで結果の行が連続して取得されます。

通常、データベースは、最後の行がフェッチされるまで問合せによって取得する確実な行数を判定できません。Oracle Databaseはフェッチ・コールに応じてデータを取得するため、データベースが読み取る行が多いほど、データベースが実行する作業が増加します。一部の問合せではデータベースが最初の行を可能なかぎり迅速に戻すのに対して、別の問合せでは最初の行を戻す前にデータベースは全結果セットを作成します。

読取り一貫性

通常、問合せはOracle Databaseの読取り一貫性メカニズムを使用してデータを取得します。このメカニズムでは、問合せによって読み取られるすべてのデータ・ブロックがある時点のものと一貫していることを保証します。

読取り一貫性では、UNDOデータを使用してデータの過去のバージョンを表示します。たとえば、1つの問合せで全表スキャンにより100個のデータ・ブロックを読み取る必要があるとします。問合せが最初の10個のブロックを処理している間に、別のセッションのDMLがブロック75を変更します。最初のセッションがブロック75に到達したとき、問合せは変更を認識し、変更前の古いバージョンのデータを取り出すためにUNDOデータを使用し、メモリー内に現時点のバージョンではないブロック75を構成します。

関連項目:

マルチバージョン読取り一貫性の詳細は、『Oracle Database概要』を参照してください。

データ変更

データを変更する必要があるDML文では、読取り一貫性を使用して、変更が開始された時点で検索基準に一致していたデータのみを取得します。

その後、これらの文は最新の状態のデータ・ブロックを取得して、必要な変更を加えます。データベースは、REDOおよびUNDOデータの生成などのデータの変更に関連するその他のアクションを実行する必要があります。

Oracle DatabaseによるDDLの処理方法

Oracle DatabaseはDMLとは異なる方法でDDLを処理します。

たとえば、表を作成するとき、データベースはCREATE TABLE文を最適化しません。かわりに、Oracle DatabaseはDDL文を解析してコマンドを実行します。

DDLはデータ・ディクショナリ内のオブジェクトを定義する手段であるため、データベースはDDLを異なる方法で処理します。通常、DDL文を実行するために、Oracle Databaseは多くの 再帰的SQL文を解析して実行する必要があります。次のような表を作成するとします。

CREATE TABLE mytable (mycolumn INTEGER);

通常、この文を実行するために、データベースは多数の再帰的な文を実行します。再帰的SQLでは、次のようなアクションが実行されます。

- CREATE TABLE文を実行する前にCOMMITを発行します。

- ユーザー権限が表の作成に十分であることを検証します。

- 表が属する表領域を決定します。

- 表領域の割当てが超過していないことを確認します。

- スキーマ内に同じ名前のオブジェクトがないことを確認します。

- データ・ディクショナリに表を定義する行を挿入します。

- DDL文が成功した場合はCOMMITを発行し、失敗した場合はROLLBACKを発行します。

関連項目:

DDLの処理、トランザクション制御およびその他のタイプの文の詳細は、『Oracle Database開発ガイド』を参照してください。

4 問合せオプティマイザの概念

SQLチューニングには、オプティマイザに対する深い理解が必要です。

この章の内容は次のとおりです。

- 問合せオプティマイザの概要

- オプティマイザのコンポーネントについて

- 自動チューニング・オプティマイザについて

- 適応問合せ最適化について

- SQL計画ベースラインのオプティマイザ管理について

問合せオプティマイザの概要

問合せオプティマイザ(単にオプティマイザと呼ばれます)は、SQL文が必要なデータにアクセスするための最も効率的な方法を判断する組込みデータベース・ソフトウェアです。

この項の内容は次のとおりです。

- 問合せオプティマイザの目的

- コストベースの最適化

- 実行計画

問合せオプティマイザの目的

オプティマイザは、SQL文に最も適した実行計画の生成を試みます。

オプティマイザは、考えられるすべての計画の候補中で最もコストの低い計画を選択します。オプティマイザは使用可能な統計を使用してコストを計算します。指定された環境における特定の問合せでは、コスト計算はI/O、CPUおよび通信など問合せ実行の要因から構成されます。

たとえば、問合せで従業員に関する情報を要求する場合があります。オプティマイザ統計で従業員の80%がマネージャであると示されている場合、オプティマイザは、全表スキャンが最も効率的であると判断できます。ただし、統計でマネージャが少ないことが示されている場合、索引を読み取ってからROWIDによる表アクセスを行うほうが全表スキャンよりも効率的なことがあります。

データベースには、自由に使用できる多数の内部統計およびツールがあるため、オプティマイザは通常、文の実行の最適な方法を決める上でユーザーよりも優位な立場にあります。このため、すべてのSQL文でオプティマイザが使用されます。

コストベースの最適化

問合せ最適化は、SQL文を実行するための最も効率的な方法を選択する全体的なプロセスです。SQLは非手続き型言語であるため、オプティマイザでマージ、再編成、処理の順序を自由に選択できます。

アクセスするデータに関して収集された統計に基づいて、各SQL文が最適化されます。オプティマイザは、複数のアクセス方法(全表スキャンや索引スキャンなど)および様々な結合方法(ネステッド・ループ結合やハッシュ結合、様々な結合順序および可能な変換など)を調べることで、SQL文の最適な計画を決定します。

指定された問合せおよび環境では、オプティマイザは関連する数値コストを可能な計画の各ステップに割り当てた後、これらの値を総合的に要因分解して計画の全体的なコスト見積りを生成します。代替計画のコストを計算した後、オプティマイザは最もコストの低い見積りの計画を選択します。このため、オプティマイザは、従来のルールベース・オプティマイザ(RBO)との対比で、コストベース・オプティマイザ(CBO)と呼ばれることがあります。

注意:

オプティマイザは、Oracle Databaseのあるバージョンとその次のバージョンで同じ決定を行うとはかぎりません。新しいバージョンのオプティマイザでは、より高度な情報を使用でき、かつより多くのオプティマイザ変換が可能なため、異なる決定が行われる場合があります。

関連項目:
コスト

実行計画

実行計画とは、SQL文の推奨実行方法を示したものです。

この計画により、SQL文を実行するためにOracle Databaseで使用するステップの組合せが示されます。各処理では、データベースからデータ行を物理的に検索するか、文を発行したユーザーのためにデータ行を準備します。

実行計画では、計画全体のコスト(行0に示されます)および個々の操作ごとのコストが表示されます。コストは、計画の比較で使用できるように実行計画のみが表示される内部的な単位です。そのため、コストの値をチューニングしたり変更したりすることはできません。

次の図では、オプティマイザは、入力SQL文の実行計画として2つの使用可能な計画を生成し、統計を使用してそれらのコストを見積り、コストを比較して、最もコストの低い計画を選択します。

図4-1 実行計画

問合せブロック

オプティマイザへの入力は、SQL文の解析済の表現です。

元のSQL文内の各SELECTブロックは、内部的には問合せブロックによって表されます。問合せブロックは、トップレベルの文、副問合せまたはマージされていないビューのいずれでもかまいません。

例4-1 問合せブロック

次のSQL文は、2つの問合せブロックで構成されています。括弧内の副問合せは、内側の問合せブロックです。SQL文の残りの部分が外側の問合せブロックで、副問合せによって提供されたIDを持つ部門内の従業員の名前を取り出します。問合せの形式によって、問合せブロックの相互関係が判断されます。

SELECT first_name, last_name
FROM   hr.employees
WHERE  department_id
IN     (SELECT department_id
FROM   hr.departments
WHERE  location_id = 1800);

関連項目:

- ビューのマージ

- SQL処理の概要は、『Oracle Database概要』を参照してください。

問合せサブプラン

各問合せブロックについて、オプティマイザは、問合せサブプランを生成します。

データベースは、問合せブロックを下位から上位へ順番に最適化します。このため、データベースは最も内側の問合せブロックを最初に最適化してそのサブプランを生成し、そして問合せ全体を表す外側の問合せブロックを生成します。

問合せブロックに使用できる可能性のある計画の数は、FROM句にあるオブジェクトの数に比例します。この数は、オブジェクトの数によって指数関数的に上昇します。たとえば、5つの表の結合に使用できる可能性のある計画の数は、2つの表の結合に使用できる可能性のある計画の数より大幅に多くなります。

オプティマイザの例え

オプティマイザの1つの例えとして、オンライン旅行アドバイザがあります。

ある旅行者が自転車に乗ってA地点からB地点に移動するための最も効率的なルートを知りたいと思っています。問合せは、「A地点からB地点への最も効率的なルートが知りたい」、「A地点からC地点経由でB地点に行く最も効率的なルートが知りたい」などのようなディレクティブになります。旅行アドバイザは、速度や難易度などの要因に基づく内部アルゴリズムを使用して、最も効率的なルートを決定します。旅行者は、「できるだけ速く到着したい」、「できるだけ楽なルートで行きたい」などのディレクティブを使用することで、旅行アドバイザの決定に影響を与えることができます。

この例えでは、旅行アドバイザが作成する可能なルートが実行計画に該当します。内部的には、アドバイザは、全体ルートをいくつかのサブルート(サブプラン)に分け、各サブルートについて別々に効率性を判断することも可能です。たとえば、旅行アドバイザは、あるサブルートについては所要時間15分難易度中、別のサブルートについては所要時間22分難易度低などのように見積ることが考えられます。

アドバイザは、ユーザーが指定した目的と、道路や交通の状況に関する利用可能な統計情報に基づいて、最も効率的な(コストの低い)全体ルートを選択します。統計情報が正確であればあるほど、より適切なアドバイスを提供できます。たとえば、アドバイザが交通渋滞、通行止めおよび道路の状態の悪さについて頻繁に確認していない場合、推奨されたルートは、結局は非効率な(コストが高い)ものになることがあります。

オプティマイザのコンポーネントについて

オプティマイザには、3つのコンポーネント(トランスフォーマ、エスティメータおよびプラン・ジェネレータ)が含まれています。

次の図に、コンポーネントを示します。

図4-2 オプティマイザのコンポーネント

問合せブロックのセットは、解析済の問合せを表します。解析済の問合せは、オプティマイザへの入力です。次の表にオプティマイザ操作を示します。

表4-1 オプティマイザ操作

フェーズ

操作

説明

詳細情報

1

問合せトランスフォーマ

オプティマイザは、オプティマイザがより優れた実行計画を生成できるように、問合せの形式を変更することが有用かどうかを判断します。

問合せトランスフォーマ

2

エスティメータ

オプティマイザは、データ・ディクショナリ内の統計に基づき、各計画のコストを見積ります。

「エスティメータ」

3

プラン・ジェネレータ

オプティマイザは各計画のコストを比較し、コストが最も低い計画(実行計画と呼ばれます)を選択して、行ソース・ジェネレータに渡します。

「プラン・ジェネレータ」

問合せトランスフォーマ

一部の文では、問合せトランスフォーマは、元のSQL文を、意味的に同等でよりコストの低いSQL文にリライトすることが有利かどうかを判断します。

実行可能な代替案がある場合、データベースでは、代替案のコストが別々に計算され、最もコストの低い代替案が選択されます。次の図は、ORを使用する入力問合せを、UNION ALLを使用する出力問合せにリライトする問合せトランスフォーマを示しています。

図4-3 問合せトランスフォーマ

エスティメータ

エスティメータは、指定された実行計画の全体コストを判断する、オプティマイザのコンポーネントです。

エスティメータは、3つの異なる計測を使用してコストを決定します。

- 選択性
問合せで選択される行セットの中の行の割合で、0は行がないことを表し、1はすべての行を表します。選択性は、問合せの述語(WHERE last_name LIKE 'A%'など)や述語の組合せに関連します。述語は、選択性の値が0に近付くほど選択性が高くなり、値が1に近付くほど選択性が低く(非選択性が高く)なります。

注意:

選択性は、実行計画では表示されない内部的な計算です。

- カーディナリティ
カーディナリティは、実行計画で各操作によって戻される行数です。これは最適な計画の作成に不可欠であり、すべてのコスト機能に共通の入力です。エスティメータは、DBMS_STATSによって収集される表統計からカーディナリティを導出することもでき、述語(フィルタ、結合など)や、DISTINCTまたはGROUP BY操作などの影響を考慮した後で導出することもできます。実行計画のRows列には、予測カーディナリティが表示されます。

- コスト
このメジャーは、作業単位または使用されるリソースを表します。問合せオプティマイザはディスクI/O、CPU使用量、メモリー使用量を作業単位として使用します。

次の図に示すように、統計が使用可能な場合、エスティメータは統計を使用してメジャーを計算します。統計によって、メジャーの正確さの度合いは改良されます。

図4-4 エスティメータ

例4-1で示されている問合せの場合、エスティメータは、選択性、予測カーディナリティ(合計10行が戻される)およびコストのメジャーを使用して、その合計コストを3と見積ります。

--------------------------------------------------------------------------------
| Id| Operation                    |Name             |Rows|Bytes|Cost %CPU|Time|
--------------------------------------------------------------------------------
| 0 | SELECT STATEMENT             |                 | 10| 250| 3 (0)| 00:00:01|
| 1 |  NESTED LOOPS                |                 |   |    |      |         |
| 2 |   NESTED LOOPS               |                 | 10| 250| 3 (0)| 00:00:01|
|*3 |    TABLE ACCESS FULL         |DEPARTMENTS      |  1|   7| 2 (0)| 00:00:01|
|*4 |    INDEX RANGE SCAN          |EMP_DEPARTMENT_IX| 10|    | 0 (0)| 00:00:01|
| 5 |   TABLE ACCESS BY INDEX ROWID|EMPLOYEES        | 10| 180| 1 (0)| 00:00:01|
--------------------------------------------------------------------------------

選択性

選択性は行セットの一部の行を表します。

行セットは、実表、ビュー、または結合の結果のいずれでもかまいません。選択性は、last_name = 'Smith'などの問合せ述語、またはlast_name = 'Smith' AND job_id = 'SH_CLERK'などの述語の組合せに拘束されています。

注意:

選択性は、実行計画では表示されない内部的な計算です。

述語は、行セット内の特定の行数をフィルタします。したがって、述語の選択性は、どれだけの行数が述語テストを通過するかを示します。選択性には、0.0から1.0の範囲があります。選択性が0.0の場合、行セットから行は選択されません。一方、選択性が1.0の場合、すべての行が選択されます。値が0.0に近づくほど述語の選択性は高くなり、値が1.0に近づくほど選択性は低くなります。

オプティマイザは統計を使用できるかどうかに応じて、選択性を見積ります。

- 統計が使用不可
OPTIMIZER_DYNAMIC_SAMPLING初期化パラメータの値に応じて、オプティマイザは、動的統計と内部のデフォルト値のいずれかを使用します。述語のタイプに応じて、使用する内部デフォルト値が異なります。たとえば、等価述語(last_name = 'Smith')の内部デフォルト値は範囲述語(last_name > 'Smith')の内部デフォルト値より小さくなります。これは等価述語の方が少ない行数を戻すことが予測されるためです。

- 統計が使用可能
統計が使用可能な場合、エスティメータは統計を使用して選択性を推測します。150の個別の従業員の名字があると仮定します。等価述語last_name = 'Smith'の場合、選択性はlast_nameの個別値の数nの逆数です。この例では、問合せは150の個別値から1つの個別値を含む行を選択するため、選択性は.006になります。

last_name列にヒストグラムがある場合、エスティメータは個別値の数かわりにヒストグラムを使用します。ヒストグラムには列内の異なる値の分布が示されているので、特にデータの偏りがある列では、より適切な選択性の見積りが行われます。

関連項目:

ヒストグラム

カーディナリティ

カーディナリティは、実行計画で各操作によって戻される行数です。

たとえば、全表スキャンによって戻される行数に関するオプティマイザの見積りが100である場合、この操作のカーディナリティ予測は100です。カーディナリティ予測は、実行計画のRows列に表示されます。

オプティマイザは、入力として表レベルと列レベルの両方の統計または動的統計を使用する一連の複雑な計算式に基づいて各操作のカーディナリティを判定します。オプティマイザは、単一の等価述語が、ヒストグラムを持たない単一表問合せに存在する場合は、最も単純な計算式のいずれかを使用します。この場合、オプティマイザは、データ配分が均一であると想定し、表内の行の合計数を、WHERE句の述語で使用されている列内の個別値の数で割ることで、問合せのカーディナリティを計算します。

たとえば、ユーザーhrが次のようにemployees表を問い合せるとします。

SELECT first_name, last_name
FROM   employees
WHERE  salary='10200';

employees表には107の行があります。現在のデータベース統計では、salary列の個別値の数が58と示されています。したがって、オプティマイザは、107/58=1.84という計算式を使用して、結果セットのカーディナリティを2と見積ります。

カーディナリティの見積りは、実行計画のすべての側面に影響を及ぼすため、できるだけ正確である必要があります。オプティマイザが結合のコストを判断する際、カーディナリティが重要になります。たとえば、employeesおよびdepartments表のネステッド・ループ結合では、employees内の行数は、データベースでdepartments表をプローブする頻度を決定します。カーディナリティはまた、ソートのコストを計算する上でも重要です。

コスト

オプティマイザのコスト・モデルは、問合せで使用が予測されるマシン・リソースから構成されます。

コストは、計画のリソース使用量の見積りを表す内部の数値メジャーです。コストは、オプティマイザ環境での問合せに固有です。コストを見積もるために、オプティマイザでは次のような要因が考慮されます。

- システム・リソース(推定されるI/O、CPU、メモリーなど)

- 返される推定行数(カーディナリティ)

- 初期データ・セットのサイズ

- データの分散

- アクセス構造

注意:

コストは、オプティマイザが同じ問合せに対する様々な計画を比較するために使用する内部尺度です。コストをチューニングしたり変更することはできません。

実行時間はコストの関数ですが、コストは直接に時間とは一致しません。たとえば、問合せAの計画のコストが問合せBの計画より低い場合、次の結果が考えられます。

- AのほうがBより高速で実行される。

- AのほうがBより低速で実行される。

- AがBと同じ時間で実行される。

したがって、異なる問合せのコストを相互に比較することはできません。また、異なるオプティマイザ・モードを使用する意味的に同等の問合せのコストは比較できません。

例4-2 サンプル実行計画のコスト

実行計画では、計画全体のコスト(行0に示されます)および個々の操作ごとのコストが表示されます。たとえば、次の計画は全体コストが14であることを示しています。

EXPLAINED SQL STATEMENT:
------------------------
SELECT prod_category, AVG(amount_sold) FROM   sales s, products p WHERE
p.prod_id = s.prod_id GROUP BY prod_category

Plan hash value: 4073170114

----------------------------------------------------------------------
| Id  | Operation                | Name                 | Cost (%CPU)|
----------------------------------------------------------------------
|   0 | SELECT STATEMENT         |                      |    14 (100)|
|   1 |  HASH GROUP BY           |                      |    14  (22)|
|   2 |   HASH JOIN              |                      |    13  (16)|
|   3 |    VIEW                  | index$_join$_002     |     7  (15)|
|   4 |     HASH JOIN            |                      |            |
|   5 |      INDEX FAST FULL SCAN| PRODUCTS_PK          |     4   (0)|
|   6 |      INDEX FAST FULL SCAN| PRODUCTS_PROD_CAT_IX |     4   (0)|
|   7 |    PARTITION RANGE ALL   |                      |     5   (0)|
|   8 |     TABLE ACCESS FULL    | SALES                |     5   (0)|
----------------------------------------------------------------------

アクセス・パスは、実表からデータを得るときに実行される作業単位数です。計画の全体コストを判断するために、オプティマイザは各アクセス・パスにコストを割り当てます。

- 表スキャンまたは高速全索引スキャン
表スキャンまたは高速全索引スキャンの間、データベースは単一I/Oでディスクから多数のブロックを読み取ります。スキャンのコストは、スキャンされるブロック数およびマルチブロックREADカウントに左右されます。

- 索引スキャン
索引スキャンのコストは、Bツリーにおけるレベル、つまりスキャンされる索引リーフ・ブロック数、索引キーのROWIDを使用してフェッチされる行数に左右されます。ROWIDを使用して行をフェッチするコストは、索引クラスタ化係数に依存します。

結合コストは、結合されている2つの行セットの個別のアクセス・コストの組合せと、結合操作のコストを表します。

プラン・ジェネレータ

プラン・ジェネレータは、別のアクセス・パス、結合方法および結合順序を試行することによって、問合せブロックに対する様々な計画を探索します。

データベースでは、様々な組合せを使用して、同じ結果をもたらすことができるため、様々な計画が可能になります。オプティマイザは、コストが最も低い計画を選択します。

次の図は、入力問合せの様々な計画をテストするオプティマイザを示しています。

図4-5 プラン・ジェネレータ

オプティマイザのトレース・ファイルの次のスニペットは、オプティマイザが実行するいくつかの計算を示しています。

GENERAL PLANS
***************************************
Considering cardinality-based initial join order.
Permutations for Starting Table :0
Join order[1]:  DEPARTMENTS[D]#0  EMPLOYEES[E]#1

***************
Now joining: EMPLOYEES[E]#1
***************
NL Join
Outer table: Card: 27.00  Cost: 2.01  Resp: 2.01  Degree: 1  Bytes: 16
Access path analysis for EMPLOYEES
. . .
Best NL cost: 13.17
. . .
SM Join
SM cost: 6.08
resc: 6.08 resc_io: 4.00 resc_cpu: 2501688
resp: 6.08 resp_io: 4.00 resp_cpu: 2501688
. . .
SM Join (with index on outer)
Access Path: index (FullScan)
. . .
HA Join
HA cost: 4.57
resc: 4.57 resc_io: 4.00 resc_cpu: 678154
resp: 4.57 resp_io: 4.00 resp_cpu: 678154
Best:: JoinMethod: Hash
Cost: 4.57  Degree: 1  Resp: 4.57  Card: 106.00 Bytes: 27
. . .

***********************
Join order[2]:  EMPLOYEES[E]#1  DEPARTMENTS[D]#0
. . .

***************
Now joining: DEPARTMENTS[D]#0
***************
. . .
HA Join
HA cost: 4.58
resc: 4.58 resc_io: 4.00 resc_cpu: 690054
resp: 4.58 resp_io: 4.00 resp_cpu: 690054
Join order aborted: cost > best plan cost
***********************

トレース・ファイルは、オプティマイザが最初に結合の外部表としてdepartments表の使用を試みていることを示しています。オプティマイザは、ネステッド・ループ結合(NL)、ソート/マージ(SM)およびハッシュ結合(HA)という3つの異なる結合方法のコストを計算します。オプティマイザは、最も効率的な方法としてハッシュ結合を選択します。

Best:: JoinMethod: Hash
Cost: 4.57  Degree: 1  Resp: 4.57  Card: 106.00 Bytes: 27

その後、オプティマイザは、外部表としてemployeesを使用して、別の結合順序を試行します。この結合順序のコストは、前の結合順序のコストよりも高いので、放棄されます。

オプティマイザは、内部カットオフを使用して計画数を削減し、最もコストの低い計画を検索しようとします。カットオフの基準は、現行の最適な計画のコストです。現行の最適コストが大きい場合、オプティマイザはコストがより低い別の計画を探索します。現行の最適コストが低い場合は、さらなる大幅なコストの改善ができないため、オプティマイザは検索を速やかに終了します。

自動チューニング・オプティマイザについて

オプティマイザは、どのように起動されるかによって異なる操作を実行します。

データベースには、次のタイプの最適化が用意されています。

- 標準の最適化
オプティマイザは、SQLをコンパイルして実行計画を生成します。標準モードでは、ほとんどのSQL文に対して妥当な実行計画が生成されます。標準モードでは、オプティマイザは、通常はミリ秒単位の厳密な時間的制約に従って動作し、その間に最適な計画を見つける必要があります。

- SQLチューニング・アドバイザの最適化
SQLチューニング・アドバイザがオプティマイザを起動した場合、オプティマイザは自動チューニング・オプティマイザと呼ばれます。この場合、オプティマイザは、追加の分析を実行して、標準モードで生成された計画をさらに改善します。オプティマイザの出力は、実行計画ではなく、さらに優れた計画を生成するための一連のアクションと、その理論的根拠および予測されるメリットを示します。

関連項目:

- SQLチューニング・アドバイザを使用したSQLの分析

- SQLチューニング・アドバイザの詳細は、『Oracle Database 2日でパフォーマンス・チューニング・ガイド』を参照してください

適応問合せ最適化について

Oracle Databaseの適応問合せ最適化により、オプティマイザは実行計画に対する実行時の調整を行い、より優れた統計を導くための追加情報を検出できます。

適応最適化は、最適な計画を生成するために既存の統計が十分でない場合に役に立ちます。次の図は、適応問合せ最適化の機能セットを示しています。

図4-6 適応問合せ最適化

適応問合せ計画

適応計画を使用すると、オプティマイザが文の最終計画を決定するのを実行時まで遅延させることができます。

この項の内容は次のとおりです。

- 適応問合せ計画の目的

- 適応問合せ計画の仕組み

- 適応問合せ計画: 結合方法の例

- 適応問合せ計画: パラレル配分方法

関連項目:

- 「オプティマイザ統計の概要」

- 「SQLチューニング・アドバイザについて」

- 「SQL計画管理について」

適応問合せ計画の目的

オプティマイザは、実行時に得た情報に基づいて計画を適応させることができるので、問合せのパフォーマンスが大幅に向上します。

適応計画が役立つのは、誤ったカーディナリティの見積りにより、オプティマイザが最適ではないデフォルトの計画を選択する場合です。実際の実行統計に基づいて実行時に計画を適応させることができるので、より最適な最終計画が生成されます。オプティマイザは最終計画を選択すると、以降の実行でその計画を使用します。そのため、最適ではない計画が再利用されることはありません。

適応問合せ計画の仕組み

適応計画には事前定義された複数のサブプランとオプティマイザ統計コレクタが含まれます。

サブプランは、オプティマイザが実行時に代替案として切り替えることが可能な、計画の一部分です。たとえば、実行時にネステッド・ループ結合をハッシュ結合に切り替えることができます。オプティマイザ統計コレクタは、実行時統計を収集するために、キー・ポイントで計画に挿入される行ソースです。オプティマイザはこれらの統計を利用して、複数のサブプランから最終的な計画を決定します。

文の実行時に、統計コレクタによって実行に関する情報が収集され、サブプランの受け取った行の一部がバッファされます。コレクタによって検出された情報に基づき、オプティマイザでサブプランが選択されます。この時点で、コレクタでは統計の収集と行のバッファリングが停止され、かわりに行が渡されます。以後、子カーソルの実行では、オプティマイザによって同じ計画が使用され、この計画がキャッシュから破棄されるか、別のオプティマイザ機能(適応カーソル共有や統計フィードバックなど)によって無効化されるまで使用が続きます。

OPTIMIZER_FEATURES_ENABLEが12.1.0.1以降の場合、データベースでは適応計画が使用され、OPTIMIZER_ADAPTIVE_REPORTING_ONLY初期化パラメータは、デフォルトであるfalseに設定されます。

関連項目:

「適応最適化の制御」

適応問合せ計画: 結合方法の例

この例では、実行時に収集された情報に基づいてオプティマイザが異なる計画を選択できる仕組みを示します。

次の問合せでは、表order_itemsと表prod_infoの結合を示しています。

SELECT product_name
FROM   order_items o, prod_info p
WHERE  o.unit_price = 15
AND    quantity > 1
AND    p.product_id = o.product_id

この文の適応問合せ計画では、2つの使用可能な計画が示されています。1つはネステッド・ループ結合を使用する計画、もう1つはハッシュ結合を使用する計画です。

SELECT * FROM TABLE(DBMS_XPLAN.display_cursor(FORMAT => 'ADAPTIVE'));

SQL_ID    7hj8dwwy6gm7p, child number 0
-------------------------------------
SELECT product_name FROM   order_items o, prod_info p WHERE
o.unit_price = 15 AND    quantity > 1 AND    p.product_id = o.product_id

Plan hash value: 1553478007

-----------------------------------------------------------------------------
| Id | Operation                     | Name     |Rows|Bytes|Cost (%CPU)|Time|
-----------------------------------------------------------------------------
|   0| SELECT STATEMENT              |              | |     |7(100)|        |
| * 1|  HASH JOIN                    |              |4| 128 | 7 (0)|00:00:01|
|-  2|   NESTED LOOPS                |              |4| 128 | 7 (0)|00:00:01|
|-  3|    NESTED LOOPS               |              |4| 128 | 7 (0)|00:00:01|
|-  4|     STATISTICS COLLECTOR      |              | |     |      |        |
| * 5|      TABLE ACCESS FULL        | ORDER_ITEMS  |4|  48 | 3 (0)|00:00:01|
|-* 6|     INDEX UNIQUE SCAN         | PROD_INFO_PK |1|     | 0 (0)|        |
|-  7|    TABLE ACCESS BY INDEX ROWID| PROD_INFO    |1|  20 | 1 (0)|00:00:01|
|   8|   TABLE ACCESS FULL           | PROD_INFO    |1|  20 | 1 (0)|00:00:01|
-----------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

1 - access("P"."PRODUCT_ID"="O"."PRODUCT_ID")
5 - filter(("O"."UNIT_PRICE"=15 AND "QUANTITY">1))
6 - access("P"."PRODUCT_ID"="O"."PRODUCT_ID")

Note
-----
- this is an adaptive plan (rows marked '-' are inactive)

結合述語によって行がフィルタ処理されることで、データベースでprod_infoのかなりの部分をスキャンせずに済むのであれば、ネステッド・ループ結合が適しています。ただし、行がほとんどフィルタ処理されていない場合は、ハッシュ結合の右表をスキャンすることが適切です。

次の図は、適応プロセスを示しています。前述の例の問合せでは、デフォルトの計画の適応部分には2つのサブプランが含まれており、それらのサブプランではそれぞれ異なる結合方法を使用します。オプティマイザは、結合の左側のカーディナリティに応じて、各結合方法が最適になるタイミングを自動的に判断します。

統計コレクタは、使用する結合方法を決定できるように、order_items表から取得された行を十分にバッファします。オプティマイザによって決定されたしきい値を行カウントが下回っている場合、オプティマイザは、ネステッド・ループ結合を選択します。それ以外の場合、オプティマイザは、ハッシュ結合を選択します。この場合、order_items表の行カウントがしきい値を上回っているため、オプティマイザは最終計画でハッシュ結合を選択し、バッファリングを無効にします。

図4-7 適応結合方法

実行計画のNoteセクションには、この計画が適応計画であるかどうか、および計画のどの行がアクティブでないかが示されます。

関連項目:

- 「適応最適化の制御」

- 適応問合せ計画を示す詳細な例は、「実行計画の読取り: 詳細」を参照してください。

適応問合せ計画: パラレル配分方法

通常、パラレル実行では、パラレル・ソート、集計、結合などの操作を実行するためにデータを再配分する必要があります。

Oracle Databaseでは様々なデータ配分方法を使用できます。データベースでは、配分される行数および操作のパラレル・サーバー・プロセス数に基づいて方法が選択されます。

たとえば、次のような代替ケースについて考えてみます。

- 多くのパラレル・サーバー・プロセスで少ない行を配分する。
ブロードキャスト配分方法が選択される可能性があります。この場合、各パラレル・サーバー・プロセスで結果セットの各行を受け取ります。

- 少ないパラレル・サーバー・プロセスで多くの行を配分する。
データの再配分時にデータの偏りが見つかった場合、文のパフォーマンスに悪影響を及ぼす可能性があります。各パラレル・サーバー・プロセスで同じ行数を受け取るようにするために、ハッシュ配分が選択される可能性が高くなります。

ハイブリッド・ハッシュ配分手法は適応パラレル・データ配分です。この配分方法では実行時まで最終的なデータ配分方法は決定されません。オプティマイザは、操作のプロデューサ側のパラレル・サーバー・プロセスの前に統計コレクタを挿入します。行数がしきい値(並列度(DOP)の2倍で定義)よりも少ない場合は、データの配分方法がハッシュからブロードキャストに切り替わります。それ以外の場合、配分方法はハッシュになります。

ブロードキャスト配分

次の図は、departments表とemployees表の間のハイブリッド・ハッシュ結合を示し、ここでは、問合せコーディネータによって8つのパラレル・サーバー・プロセスが指示されています。P5からP8はプロデューサで、P1からP4はコンシューマです。各プロデューサに、それぞれ固有のコンシューマがあります。

図4-8 DOPが4の適応問合せ

データベースは、departments表をスキャンする各プロデューサ・プロセスの前に統計コレクタを挿入します。問合せコーディネータは、収集された統計を集計します。配分方法は実行時の統計に基づきます。図4-8では、行数がしきい値(8)、つまりDOP (4)の2倍を下回っているため、オプティマイザによってdepartments表に対してブロードキャスト手法が選択されます。

ハイブリッド・ハッシュ配分

より多くの行数を戻す例について検討します。次の例では、しきい値は8、すなわちDOPの指定値4の2倍です。ただし、統計コレクタでは行数(27)がしきい値(8)を上回っているため(手順10)、オプティマイザによってブロードキャスト配分のかわりにハイブリッド・ハッシュ配分が選択されます。(time列には00:00:01と表示される必要がありますが、計画がページに収まるように0:01と表示されています。)

EXPLAIN PLAN FOR
SELECT /*+ parallel(4) full(e) full(d) */ department_name, sum(salary)
FROM   employees e, departments d
WHERE  d.department_id=e.department_id
GROUP BY department_name;

Plan hash value: 2940813933
-----------------------------------------------------------------------------------------------
|Id|Operation                          | Name    |Rows|Bytes|Cost |Time| TQ |IN-OUT|PQ Distrib|
-----------------------------------------------------------------------------------------------
| 0|SELECT STATEMENT                   |DEPARTMENTS| 27|621 |6(34)|0:01|     |    |           |
| 1| PX COORDINATOR                    |           |   |    |     |    |     |    |           |
| 2|  PX SEND QC (RANDOM)              | :TQ10003  | 27|621 |6(34)|0:01|Q1,03|P->S| QC (RAND) |
| 3|   HASH GROUP BY                   |           | 27|621 |6(34)|0:01|Q1,03|PCWP|           |
| 4|    PX RECEIVE                     |           | 27|621 |6(34)|0:01|Q1,03|PCWP|           |
| 5|     PX SEND HASH                  | :TQ10002  | 27|621 |6(34)|0:01|Q1,02|P->P| HASH      |
| 6|      HASH GROUP BY                |           | 27|621 |6(34)|0:01|Q1,02|PCWP|           |
|*7|       HASH JOIN                   |           |106|2438|5(20)|0:01|Q1,02|PCWP|           |
| 8|        PX RECEIVE                 |           | 27|432 |2 (0)|0:01|Q1,02|PCWP|           |
| 9|         PX SEND HYBRID HASH       | :TQ10000  | 27|432 |2 (0)|0:01|Q1,00|P->P|HYBRID HASH|
|10|          STATISTICS COLLECTOR     |           |   |    |     |    |Q1,00|PCWC|           |
|11|           PX BLOCK ITERATOR       |           | 27|432 |2 (0)|0:01|Q1,00|PCWC|           |
|12|            TABLE ACCESS FULL      |DEPARTMENTS| 27|432 |2 (0)|0:01|Q1,00|PCWP|           |
|13|        PX RECEIVE                 |           |107|749 |2 (0)|0:01|Q1,02|PCWP|           |
|14|         PX SEND HYBRID HASH (SKEW)| :TQ10001  |107|749 |2 (0)|0:01|Q1,01|P->P|HYBRID HASH|
|15|          PX BLOCK ITERATOR        |           |107|749 |2 (0)|0:01|Q1,01|PCWC|           |
|16|           TABLE ACCESS FULL       | EMPLOYEES |107|749 |2 (0)|0:01|Q1,01|PCWP|           |
-----------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

7 - access("D"."DEPARTMENT_ID"="E"."DEPARTMENT_ID")

Note
-----
- Degree of Parallelism is 4 because of hint

32 rows selected.

関連項目:

パラレル・データ配分手法の詳細は、『Oracle Database VLDBおよびパーティショニング・ガイド』を参照してください。

適応問合せ計画: ビットマップ索引プルーニング

適応計画では、一致する行の数が大幅に削減されない索引をプルーニングします。

オプティマイザがスター型変換計画を生成した場合、オプティマイザはビットマップ索引の適切な組合せを選択して、関連するROWIDのセットをできるだけ効率的に削減する必要があります。多数の索引が存在する場合、一部の索引が、ROWIDのセットの大幅な削減につながらず、かつ問合せの実行中の処理コストを増加させることがあります。適応計画では、パフォーマンスを低下させる索引を使用しないことでこの問題を解決できます。

例4-3 ビットマップ索引プルーニング

この例では、次のスター問合せを発行し、carsファクト表を複数のディメンション表に結合します(出力例も示します)。

SELECT /*+ star_transformation(r) */ l.color_name, k.make_name,
h.filter_col, count(*)
FROM   cars r, colors l, makes k, models d, hcc_tab h
WHERE  r.make_id = k.make_id
AND    r.color_id = l.color_id
AND    r.model_id = d.model_id
AND    r.high_card_col = h.high_card_col
AND    d.model_name = 'RAV4'
AND    k.make_name = 'Toyota'
AND    l.color_name = 'Burgundy'
AND    h.filter_col = 100
GROUP BY l.color_name, k.make_name, h.filter_col;

COLOR_NA MAKE_N FILTER_COL   COUNT(*)
-------- ------ ---------- ----------
Burgundy Toyota        100      15000

次のサンプル実行計画は、問合せで手順12と手順17でビットマップ・ノードに対して行が生成されなかったことを示しています。適応オプティマイザは、CAR_MODEL_IDX索引およびCAR_MAKE_IDX索引を使用して行をフィルタリングすることは効率的でないと判断しました。問合せではダッシュ(-)で始まる計画の手順は使用されませんでした。

-----------------------------------------------------------
| Id  | Operation                         | Name           |
-----------------------------------------------------------
|   0 | SELECT STATEMENT                  |                |
|   1 |  SORT GROUP BY NOSORT             |                |
|   2 |   HASH JOIN                       |                |
|   3 |    VIEW                           | VW_ST_5497B905 |
|   4 |     NESTED LOOPS                  |                |
|   5 |      BITMAP CONVERSION TO ROWIDS  |                |
|   6 |       BITMAP AND                  |                |
|   7 |        BITMAP MERGE               |                |
|   8 |         BITMAP KEY ITERATION      |                |
|   9 |          TABLE ACCESS FULL        | COLORS         |
|  10 |          BITMAP INDEX RANGE SCAN  | CAR_COLOR_IDX  |
|- 11 |        STATISTICS COLLECTOR       |                |
|- 12 |         BITMAP MERGE              |                |
|- 13 |          BITMAP KEY ITERATION     |                |
|- 14 |           TABLE ACCESS FULL       | MODELS         |
|- 15 |           BITMAP INDEX RANGE SCAN | CAR_MODEL_IDX  |
|- 16 |        STATISTICS COLLECTOR       |                |
|- 17 |         BITMAP MERGE              |                |
|- 18 |          BITMAP KEY ITERATION     |                |
|- 19 |           TABLE ACCESS FULL       | MAKES          |
|- 20 |           BITMAP INDEX RANGE SCAN | CAR_MAKE_IDX   |
|  21 |      TABLE ACCESS BY USER ROWID   | CARS           |
|  22 |    MERGE JOIN CARTESIAN           |                |
|  23 |     MERGE JOIN CARTESIAN          |                |
|  24 |      MERGE JOIN CARTESIAN         |                |
|  25 |       TABLE ACCESS FULL           | MAKES          |
|  26 |       BUFFER SORT                 |                |
|  27 |        TABLE ACCESS FULL          | MODELS         |
|  28 |      BUFFER SORT                  |                |
|  29 |       TABLE ACCESS FULL           | COLORS         |
|  30 |     BUFFER SORT                   |                |
|  31 |      TABLE ACCESS FULL            | HCC_TAB        |
-----------------------------------------------------------

Note
-----
- dynamic statistics used: dynamic sampling (level=2)
- star transformation used for this statement
- this is an adaptive plan (rows marked '-' are inactive)

適応統計

問合せ述語が複雑すぎて実表の統計のみに基づくことは十分でない場合、オプティマイザでは適応統計を使用できます。

次の各トピックでは、適応統計のタイプについて説明します。

- 動的統計

- 自動再最適化

- SQL計画ディレクティブ

動的統計

SQL文のコンパイル時に、オプティマイザは、最適な実行計画を生成するために使用可能な統計が十分にあるかどうかを検討し、動的統計を使用するかどうかを判断します。

使用可能な統計が不十分な場合、オプティマイザは動的統計を使用して統計を増強します。動的統計の一つに、動的サンプリングによって収集された情報があります。オプティマイザでは、表スキャン、索引アクセス、結合およびGROUP BY操作の統計を使用でき、その結果、オプティマイザの決定の品質が向上します。

関連項目:

動的統計およびオプティマイザ統計の詳細は、「補足的な動的統計」を参照してください。

自動再最適化

自動再最適化では、オプティマイザによって、最初の実行後に以降の実行の計画が変更されます。

適応問合せ計画は、すべての種類の計画変更に適しているわけではありません。たとえば、非効率な結合順序の問合せは、最適には実行されませんが、適応問合せ計画は、実行時の結合順序の適応をサポートしていません。SQL文の最初の実行の最後に、オプティマイザは実行時に収集された情報を使用して、自動再最適化にコスト・ベネフィットがあるかどうかを判断します。実行情報がオプティマイザの見積りと大幅に異なる場合、オプティマイザは次回実行時に置き換えるための計画を探します。

オプティマイザは、前回の実行時に収集された情報を使用して代替計画を決定します。オプティマイザは、問合せを複数回再最適化でき、そのたびに追加データを収集し、計画が改善されます。

自動再最適化には、統計フィードバックとパフォーマンス・フィードバックの2つの形式があります。

関連項目:

「適応最適化の制御」

再最適化: 統計フィードバック

統計フィードバック(旧カーディナリティ・フィードバック)と呼ばれる再最適化の形式は、カーディナリティの見積りが誤っている繰返し問合せの計画を自動的に改善します。

オプティマイザは、統計がない、統計が不正確である、述語が複雑であるなど、多数の理由でカーディナリティを誤って見積ることがあります。統計フィードバックを使用した再最適化の基本プロセスは次のとおりです。

1. SQL文の最初の実行時に、オプティマイザが実行計画を生成します。
オプティマイザは、次のような場合に、共有SQL領域の統計フィードバックの監視を有効化することがあります。

- 表に統計がない場合

- 接続フィルタ述語または選言フィルタ述語が表に複数ある場合

- オプティマイザが選択性の見積りを正確に計算できないような複雑な演算子が述語に含まれる場合

実行の最後に、オプティマイザは最初のカーディナリティの見積りと、実行時に計画の各操作で返された実際の行数を比較します。見積りが実際のカーディナリティと大きく異なる場合、オプティマイザは以降に使用するために正しい見積りを保存します。オプティマイザは、最初の実行時に取得された情報を他のSQL文が有効に利用できるようにSQL計画ディレクティブも作成します。

2. 最初の実行後、オプティマイザは統計フィードバックの監視を無効にします。

3. 問合せが再度実行された場合、オプティマイザは、その通常の見積りではなく、修正されたカーディナリティの見積りを使用します。

例4-4 統計フィードバック

次の例では、データベースが統計フィードバックを使用して、誤った見積りを調整する仕組みを示します。

1. ユーザーoeは、orders、order_itemsおよびproduct_information表の次の問合せを実行します。

SELECT o.order_id, v.product_name
FROM   orders o,
( SELECT order_id, product_name
FROM   order_items o, product_information p
WHERE  p.product_id = o.product_id
AND    list_price < 50
AND    min_price < 40 ) v
WHERE  o.order_id = v.order_id

2. カーソル内の計画を問い合せてみると、見積られた行数(E-Rows)が実際の行数(A-Rows)よりも非常に少ないことがわかりました。

--------------------------------------------------------------------------------------------------
| Id | Operation             | Name          |Starts|E-Rows|A-Rows|A-Time|Buffers|OMem|1Mem|O/1/M|
--------------------------------------------------------------------------------------------------
| 0| SELECT STATEMENT      |                   |   1|     | 269 |00:00:00.14|1338|    |    |     |
| 1|  NESTED LOOPS         |                   |   1|   1 | 269 |00:00:00.14|1338|    |    |     |
| 2|   MERGE JOIN CARTESIAN|                   |   1|   4 |9135 |00:00:00.05|  33|    |    |     |
|*3|    TABLE ACCESS FULL  |PRODUCT_INFORMATION|   1|   1 |  87 |00:00:00.01|  32|    |    |     |
| 4|    BUFFER SORT        |                   |  87| 105 |9135 |00:00:00.02|   1|4096|4096|1/0/0|
| 5|     INDEX FULL SCAN   |ORDER_PK           |   1| 105 | 105 |00:00:00.01|   1|    |    |     |
|*6|   INDEX UNIQUE SCAN   |ORDER_ITEMS_UK     |9135|   1 | 269 |00:00:00.04|1305|    |    |     |
--------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

3 - filter(("MIN_PRICE"<40 AND "LIST_PRICE"<50))
6 - access("O"."ORDER_ID"="ORDER_ID" AND "P"."PRODUCT_ID"="O"."PRODUCT_ID")

3. ユーザーoeは、手順1の問合せを再実行します。

4. カーソル内の計画を問い合せてみると、2回目の実行ではオプティマイザが統計フィードバック(Noteを参照)を使用し、異なる計画を選択したことがわかりました。

--------------------------------------------------------------------------------------------------
|Id | Operation             | Name   | Starts |E-Rows|A-Rows|A-Time|Buffers|Reads|OMem|1Mem|O/1/M|
--------------------------------------------------------------------------------------------------
| 0| SELECT STATEMENT       |                   |  1|   | 269 |00:00:00.05|60|1|     |     |     |
| 1|  NESTED LOOPS          |                   |  1|269| 269 |00:00:00.05|60|1|     |     |     |
|*2|   HASH JOIN            |                   |  1|313| 269 |00:00:00.05|39|1|1398K|1398K|1/0/0|
|*3|    TABLE ACCESS FULL   |PRODUCT_INFORMATION|  1| 87|  87 |00:00:00.01|15|0|     |     |     |
| 4|    INDEX FAST FULL SCAN|ORDER_ITEMS_UK     |  1|665| 665 |00:00:00.01|24|1|     |     |     |
|*5|   INDEX UNIQUE SCAN    |ORDER_PK           |269|  1| 269 |00:00:00.01|21|0|     |     |     |
--------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

2 - access("P"."PRODUCT_ID"="O"."PRODUCT_ID")
3 - filter(("MIN_PRICE"<40 AND "LIST_PRICE"<50))
5 - access("O"."ORDER_ID"="ORDER_ID")

Note
-----
- statistics feedback used for this statement

この出力では、手順1で見積られた行数(269)は、実際の行数と一致しています。

再最適化: パフォーマンス・フィードバック

再最適化の別の形式は、パフォーマンス・フィードバックです。この再最適化は、PARALLEL_DEGREE_POLICYがADAPTIVEに設定されている場合に、繰返しSQL文の自動的に選択された並列度を改善するために役立ちます。

パフォーマンス・フィードバックを使用した再最適化の基本プロセスは次のとおりです。

1. SQL文の最初の実行時に、PARALLEL_DEGREE_POLICYがADAPTIVEに設定されていると、オプティマイザはその文をパラレルに実行するかどうか、また、実行する場合はどの程度の並列度を使用するかを決定します。
オプティマイザは、文の推定パフォーマンスに基づいて並列度を選択します。すべての文に対して追加のパフォーマンス監視が有効になります。

2. 最初の実行の最後に、オプティマイザは次のことを比較します。

- オプティマイザによって選択された並列度

- 文の実際の実行時に収集されたパフォーマンス統計(CPU時間など)に基づいて計算された並列度

2つの値が大幅に異なる場合、その文は再解析の対象としてマークされ、最初の実行統計がフィードバックとして保存されます。このフィードバックは、以降の実行で並列度の計算精度を向上させるのに役立ちます。

3. 問合せが再度実行された場合、オプティマイザは、最初の実行時に収集されたパフォーマンス統計を使用して、より適切な文の並列度を決定します。

注意:

PARALLEL_DEGREE_POLICYがADAPTIVEに設定されていない場合でも、統計フィードバックが文に選択された並列度に影響する場合があります。

SQL計画ディレクティブ

SQL計画ディレクティブは、オプティマイザがより最適な計画を生成するために使用する追加情報です。

たとえば、問合せ最適化中に、表が動的統計の候補であるかどうかを判断する場合、統計リポジトリに対して表のディレクティブが問い合されます。問合せで結合列にデータの偏りがある2つの表を結合する場合、SQL計画ディレクティブでは、動的統計を使用して正確なカーディナリティの見積りを取得するようオプティマイザに指示できます。

オプティマイザは、文レベルではなく、問合せ式のSQL計画ディレクティブを収集します。このようにして、オプティマイザはディレクティブを複数のSQL文に適用できます。データベースは自動的に、ディレクティブを保持し、それらをSYSAUX表領域に格納します。パッケージDBMS_SPDを使用してディレクティブを管理できます。

関連項目:

- 「SQL計画ディレクティブ」

- 「SQL計画ディレクティブの管理」

- DBMS_SPDパッケージの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください

SQL計画ベースラインのオプティマイザ管理について

SQL計画管理は、データベースで既知の計画または確認済の計画のみが使用されるようにオプティマイザで実行計画を自動的に管理するメカニズムです。

このメカニズムにより、SQL計画ベースラインを構築できます。これには、各SQL文の承認済計画が1つ以上含まれます。

オプティマイザは、SQL文の計画履歴およびSQL計画ベースラインにアクセスし、それらを管理できます。この機能は、SQL計画管理アーキテクチャの中核を成すものです。SQL計画管理では、オプティマイザには次の主な目的があります。

- 繰返し可能なSQL文の識別

- 一連のSQL文に関する計画履歴および場合によってはSQL計画ベースラインの保持

- 計画履歴に存在しない計画の検出

- SQL計画ベースラインに存在しない、潜在的により優れた計画の検出

オプティマイザは、通常のコストベースの検索方法を使用します。

関連項目:

「SQL計画ベースラインの管理」

5 問合せ変換

オプティマイザは、複数の問合せ変換技法を使用します。この章では、最も重要なことについて説明します。

この章の内容は次のとおりです。

- OR拡張

- ビューのマージ

- 述語のプッシュ

- 副問合せのネスト解除

- マテリアライズド・ビューを使用したクエリー・リライト

- スター型変換

- インメモリー集計

- 表拡張

- 結合の因数分解

関連項目:

問合せトランスフォーマ

OR拡張

OR拡張では、オプティマイザは、OR演算子を含むWHERE句がある問合せを、UNION ALL演算子を使用する問合せに変換します。

データベースでは、様々な理由でOR拡張が実行されます。たとえば、より効率的なアクセス・パスや、デカルト積を回避する代替の結合方法を有効にできます。通常と同じように、オプティマイザは、変換された文のコストが元の文のコストよりも低い場合にのみ、拡張を実行します。

次の例では、ユーザーshが、sales.prod_idおよびsales.promo_id列で連結索引を作成し、OR条件を使用してsales表を問い合せます。

CREATE INDEX sales_prod_promo_ind
ON sales(prod_id, promo_id);

SELECT *
FROM   sales
WHERE  promo_id=33
OR     prod_id=136;

前述の問合せでは、promo_id=33およびprod_id=136条件はそれぞれ、索引アクセス・パスを活用できるため、オプティマイザは、文を例5-1の問合せに変換します。

例5-1 変換された問合せ: UNION ALL条件

この例の問合せ変換では、オプティマイザは、索引を使用してsales表にアクセスする実行計画を選択し、結果をアセンブルします。計画を、例5-2に示します。

SELECT *
FROM   sales
WHERE  prod_id=136
UNION ALL
SELECT *
FROM   sales
WHERE  promo_id=33
AND    LNNVL(prod_id=136);

例5-2 salesの問合せの実行計画

--------------------------------------------------------------------------------
| Id| Operation                                   | Name                 | Rows|
--------------------------------------------------------------------------------
| 0 | SELECT STATEMENT                            |                      |     |
| 1 |  CONCATENATION                              |                      |     |
| 2 |   TABLE ACCESS BY GLOBAL INDEX ROWID BATCHED| SALES                | 710 |
| 3 |    INDEX RANGE SCAN                         | SALES_PROD_PROMO_IND | 710 |
| 4 |   PARTITION RANGE ALL                       |                      | 229K|
| 5 |    TABLE ACCESS FULL                        | SALES                | 229K|
--------------------------------------------------------------------------------

ビューのマージ

ビューのマージでは、オプティマイザは、ビューを表す問合せブロックを、それを包含する問合せブロックにマージします。ビューのマージにより、オプティマイザが追加の結合順序、アクセス方法およびその他の変換を考慮できるようになり、計画を向上させることができます。

たとえば、ビューがマージされ、複数の表が1つの問合せブロックに存在するようになると、ビューの内部の表で、オプティマイザが結合の絞込みを使用してビューの外部の表を削除できるようになります。マージにより常に計画が改善されるような特定の単純なビューの場合、オプティマイザは、コストを考慮せずに自動的にビューをマージします。それ以外の場合、オプティマイザは、コストを使用して判断を行います。オプティマイザは、コストや妥当性の制約など、多くの理由でビューをマージしないことを選択することもあります。

OPTIMIZER_SECURE_VIEW_MERGINGがtrue (デフォルト)の場合、Oracle Databaseでは、ビューのマージおよび述語のプッシュによってビュー作成者のセキュリティ意図が侵害されないことを確認するために、チェックが実行されます。特定のビューでこれらの追加のセキュリティ・チェックを無効にするには、このビューのユーザーにMERGE VIEW権限を付与します。特定のユーザーのすべてのビューで追加のセキュリティ・チェックを無効にするには、そのユーザーにMERGE ANY VIEW権限を付与します。

注意:

ヒントを使用して、妥当性ではなく、コストやヒューリスティックが原因で拒否されたビューのマージをオーバーライドすることができます。

この項の内容は次のとおりです。

- ビューのマージにおける問合せブロック

- 単純ビューのマージ

- 複合ビューのマージ

関連項目:

- MERGE ANY VIEW権限およびMERGE VIEW権限の詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

- OPTIMIZER_SECURE_VIEW_MERGING初期化パラメータの詳細は、『Oracle Databaseリファレンス』を参照してください。

ビューのマージにおける問合せブロック

オプティマイザは、個別の問合せブロックによるネストされた副問合せまたはマージされていないビューをそれぞれ表します。データベースは、問合せブロックを下位から上位へ順番に最適化します。このため、データベースは最も内側の問合せブロックを最初に最適化し、その計画の一部を生成して、問合せ全体を表す外側の問合せブロックの計画を生成します。

パーサーは、問合せで参照される各ビューを個別の問合せブロックに拡張します。ブロックは、基本的にはビュー定義を表しますが、このため必然的にビューの結果も表すことになります。オプティマイザの1つのオプションは、ビューの問合せブロックを個別に分析し、サブプランを生成して、実行計画全体の生成にビュー・サブプランを使用することで、残りの問合せを処理することです。ただし、この手法では、ビューが個別に最適化されるため、最適ではない実行計画となる可能性があります。

ビューのマージにより、パフォーマンスが向上する場合があります。例5-3に示されているように、ビューのマージでは、ビューから外側の問合せブロックに表がマージされ、内側の問合せブロックが削除されます。そのため、ビューの個別の最適化は必要ありません。

単純ビューのマージ

単純ビューのマージでは、オプティマイザは選択表示結合ビューをマージします。たとえば、employees表の問合せにはdepartments表とlocations表を結合する副問合せが含まれます。

マージ後は追加の結合順序およびアクセス・パスが使用可能になるため、単純ビューのマージにより、多くの場合、より最適な計画が作成されます。次の理由により、単純ビューのマージでは、ビューが有効にならない場合があります。

- 次のような、選択表示結合ビューに含まれていない構成メンバーがビューに含まれている。

- GROUP BY

- DISTINCT

- 外部結合

- MODEL

- CONNECT BY

- 集合演算子

- 集計

- ビューがセミ結合またはアンチ結合の右側に表示される。

- ビューのSELECTリスト内に副問合せが含まれている。

- 外側の問合せブロックにPL/SQLファンクションが含まれている。

- ビューが外部結合に含まれており、ビューをマージできるかどうかを判断する複数の追加の妥当性要件の1つを満たさない。

例5-3 単純ビューのマージ

次の問合せでは、hr.employees表がdept_locs_vビューに結合されます。このビューは、各部門の所在地を戻します。dept_locs_vは、departments表とlocations表が結合されたものです。

SELECT e.first_name, e.last_name, dept_locs_v.street_address,
dept_locs_v.postal_code
FROM   employees e,
( SELECT d.department_id, d.department_name,
l.street_address, l.postal_code
FROM   departments d, locations l
WHERE  d.location_id = l.location_id ) dept_locs_v
WHERE  dept_locs_v.department_id = e.department_id
AND    e.last_name = 'Smith';

データベースは、departmentsおよびlocationsを結合してビューの行を生成し、この結果をemployeesに結合することで、この問合せを実行できます。問合せにはdept_locs_vビューが含まれており、このビューには2つの表が含まれているため、オプティマイザは、次の結合順序のいずれかを使用する必要があります。

- employees、dept_locs_v(departments、locations)

- employees、dept_locs_v(locations、departments)

- dept_locs_v(departments、locations)、employees

- dept_locs_v(locations、departments)、employees

また、結合方法にも制約があります。このビューの列には索引が存在しないため、索引ベースのネステッド・ループ結合は、employeesで始まる結合順序では実行できません。オプティマイザは、ビューのマージを行わずに、次の実行計画を生成します。

-----------------------------------------------------------------
| Id  | Operation                    | Name        | Cost (%CPU)|
-----------------------------------------------------------------
|   0 | SELECT STATEMENT             |             |     7  (15)|
|*  1 |  HASH JOIN                   |             |     7  (15)|
|   2 |   TABLE ACCESS BY INDEX ROWID| EMPLOYEES   |     2   (0)|
|*  3 |    INDEX RANGE SCAN          | EMP_NAME_IX |     1   (0)|
|   4 |   VIEW                       |             |     5  (20)|
|*  5 |    HASH JOIN                 |             |     5  (20)|
|   6 |     TABLE ACCESS FULL        | LOCATIONS   |     2   (0)|
|   7 |     TABLE ACCESS FULL        | DEPARTMENTS |     2   (0)|
-----------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------
1 - access("DEPT_LOCS_V"."DEPARTMENT_ID"="E"."DEPARTMENT_ID")
3 - access("E"."LAST_NAME"='Smith')
5 - access("D"."LOCATION_ID"="L"."LOCATION_ID")

ビューのマージでは、ビューから外側の問合せブロックに表がマージされ、内側の問合せブロックが削除されます。ビューのマージ後、問合せは次のようになります。

SELECT e.first_name, e.last_name, l.street_address, l.postal_code
FROM   employees e, departments d, locations l
WHERE  d.location_id = l.location_id
AND    d.department_id = e.department_id
AND    e.last_name = 'Smith';

3つの表すべてが1つの問合せブロックにあるため、オプティマイザは、次の6つの結合順序から選択できます。

- employees、departments、locations

- employees、locations、departments

- departments、employees、locations

- departments、locations、employees

- locations、employees、departments

- locations、departments、employees

これで、employeesおよびdepartmentsへの結合は、索引ベースで実行できるようになりました。ビューのマージ後、オプティマイザは、ネステッド・ループを使用する、より効率的な次の計画を選択します。

-------------------------------------------------------------------
| Id  | Operation                      | Name        | Cost (%CPU)|
-------------------------------------------------------------------
|   0 | SELECT STATEMENT               |             |     4   (0)|
|   1 |  NESTED LOOPS                  |             |            |
|   2 |   NESTED LOOPS                 |             |     4   (0)|
|   3 |    NESTED LOOPS                |             |     3   (0)|
|   4 |     TABLE ACCESS BY INDEX ROWID| EMPLOYEES   |     2   (0)|
|*  5 |      INDEX RANGE SCAN          | EMP_NAME_IX |     1   (0)|
|   6 |     TABLE ACCESS BY INDEX ROWID| DEPARTMENTS |     1   (0)|
|*  7 |      INDEX UNIQUE SCAN         | DEPT_ID_PK  |     0   (0)|
|*  8 |    INDEX UNIQUE SCAN           | LOC_ID_PK   |     0   (0)|
|   9 |   TABLE ACCESS BY INDEX ROWID  | LOCATIONS   |     1   (0)|
-------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------
5 - access("E"."LAST_NAME"='Smith')
7 - access("E"."DEPARTMENT_ID"="D"."DEPARTMENT_ID")
8 - access("D"."LOCATION_ID"="L"."LOCATION_ID")

関連項目:

単純ビューのマージの特殊なケースである外部結合ビューのマージの詳細は、Oracleオプティマイザのブログ(https://blogs.oracle.com/optimizer/)を参照してください。

複合ビューのマージ

複合ビューのマージでは、オプティマイザは、GROUP BYおよびDISTINCTビューを含むビューをマージします。単純ビューのマージと同様、複合マージでは、オプティマイザは、追加の結合順序とアクセス・パスを考慮することができます。

オプティマイザは、結合の評価が実行されるまで、GROUP BYまたはDISTINCT操作の評価を遅延することができます。これらの操作を遅延すると、データの特性によって、パフォーマンスが向上したり低下したりすることがあります。結合でフィルタが使用される場合、結合後まで操作を遅延することで、操作が実行されるデータセットを減らすことができます。早期に操作を評価することで、以降の結合で処理されるデータの量を減らすことができます。そうしないと、結合により、操作で処理されるデータの量が増える可能性があります。オプティマイザは、コストを使用してビューのマージを評価し、コストがより低い場合にのみビューをマージします。

コスト以外でも、オプティマイザは、次の理由で複合ビューのマージを実行できない場合があります。

- 外部問合せ表に、ROWID列または一意列がない。

- ビューがCONNECT BY問合せブロックにある。

- ビューにGROUPING SETS、ROLLUPまたはPIVOT句が含まれている。

- ビューまたは外側の問合せブロックにMODEL句が含まれている。

例5-4 GROUP BYでの複合ビューの結合

次のビューでは、GROUP BY句が使用されます。

CREATE VIEW cust_prod_totals_v AS
SELECT SUM(s.quantity_sold) total, s.cust_id, s.prod_id
FROM   sales s
GROUP BY s.cust_id, s.prod_id;

次の問合せでは、毛皮をあしらったセーターを少なくとも100着購入した米国の顧客がすべて検索されます。

SELECT c.cust_id, c.cust_first_name, c.cust_last_name, c.cust_email
FROM   customers c, products p, cust_prod_totals_v
WHERE  c.country_id = 52790
AND    c.cust_id = cust_prod_totals_v.cust_id
AND    cust_prod_totals_v.total > 100
AND    cust_prod_totals_v.prod_id = p.prod_id
AND    p.prod_name = 'T3 Faux Fur-Trimmed Sweater';

cust_prod_totals_vビューは、複合ビューのマージの対象です。マージ後、問合せは次のようになります。

SELECT c.cust_id, cust_first_name, cust_last_name, cust_email
FROM   customers c, products p, sales s
WHERE  c.country_id = 52790
AND    c.cust_id = s.cust_id
AND    s.prod_id = p.prod_id
AND    p.prod_name = 'T3 Faux Fur-Trimmed Sweater'
GROUP BY s.cust_id, s.prod_id, p.rowid, c.rowid, c.cust_email, c.cust_last_name,
c.cust_first_name, c.cust_id
HAVING SUM(s.quantity_sold) > 100;

変換された問合せは、変換されていない問合せよりもコストが低いため、オプティマイザはビューをマージすることを選択します。変換されていない問合せでは、GROUP BY演算子は、ビュー内のsales表全体に適用されます。変換された問合せでは、productsおよびcustomersへの結合により、sales表の行の大部分がフィルタ処理で除外されるため、GROUP BY操作のコストは低くなります。sales表は小さくならないため、結合はよりコストの高い操作となりますが、GROUP BY操作でも、元の問合せの行セットのサイズはあまり小さくならないので、コストはそれほど変わりません。前述の特性のいずれかが変わると、ビューのマージは、コストが低いとはかぎらなくなります。最終計画(これはビューを含みません)は、次のようになります。

--------------------------------------------------------
| Id  | Operation             | Name      | Cost (%CPU)|
--------------------------------------------------------
|   0 | SELECT STATEMENT      |           |  2101  (18)|
|*  1 |  FILTER               |           |            |
|   2 |   HASH GROUP BY       |           |  2101  (18)|
|*  3 |    HASH JOIN          |           |  2099  (18)|
|*  4 |     HASH JOIN         |           |  1801  (19)|
|*  5 |      TABLE ACCESS FULL| PRODUCTS  |    96   (5)|
|   6 |      TABLE ACCESS FULL| SALES     |  1620  (15)|
|*  7 |     TABLE ACCESS FULL | CUSTOMERS |   296  (11)|
--------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter(SUM("QUANTITY_SOLD")>100)
3 - access("C"."CUST_ID"="CUST_ID")
4 - access("PROD_ID"="P"."PROD_ID")
5 - filter("P"."PROD_NAME"='T3 Faux Fur-Trimmed Sweater')
7 - filter("C"."COUNTRY_ID"='US')

例5-5 DISTINCTでの複合ビューの結合

cust_prod_vビューの次の問合せでは、DISTINCT演算子が使用されます。

SELECT c.cust_id, c.cust_first_name, c.cust_last_name, c.cust_email
FROM   customers c, products p,
( SELECT DISTINCT s.cust_id, s.prod_id
FROM   sales s) cust_prod_v
WHERE  c.country_id = 52790
AND    c.cust_id = cust_prod_v.cust_id
AND    cust_prod_v.prod_id = p.prod_id
AND    p.prod_name = 'T3 Faux Fur-Trimmed Sweater';

ビューのマージによってよりコストの低い計画が作成されると判断すると、オプティマイザは、問合せを次のような同等の問合せにリライトします。

SELECT nwvw.cust_id, nwvw.cust_first_name, nwvw.cust_last_name, nwvw.cust_email
FROM   ( SELECT DISTINCT(c.rowid), p.rowid, s.prod_id, s.cust_id,
c.cust_first_name, c.cust_last_name, c.cust_email
FROM   customers c, products p, sales s
WHERE  c.country_id = 52790
AND    c.cust_id = s.cust_id
AND    s.prod_id = p.prod_id
AND    p.prod_name = 'T3 Faux Fur-Trimmed Sweater' ) nwvw;

前述の問合せの計画は次のようになります。

-------------------------------------------
| Id  | Operation             | Name      |
-------------------------------------------
|   0 | SELECT STATEMENT      |           |
|   1 |  VIEW                 | VM_NWVW_1 |
|   2 |   HASH UNIQUE         |           |
|*  3 |    HASH JOIN          |           |
|*  4 |     HASH JOIN         |           |
|*  5 |      TABLE ACCESS FULL| PRODUCTS  |
|   6 |      TABLE ACCESS FULL| SALES     |
|*  7 |     TABLE ACCESS FULL | CUSTOMERS |
-------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------
3 - access("C"."CUST_ID"="S"."CUST_ID")
4 - access("S"."PROD_ID"="P"."PROD_ID")
5 - filter("P"."PROD_NAME"='T3 Faux Fur-Trimmed Sweater')
7 - filter("C"."COUNTRY_ID"='US')

この計画には、ビューのマージが行われた後でも、予測ビューとして知られるvm_nwvw_1という名前のビューが含まれています。予測ビューは、DISTINCTビューがマージされた問合せに表示されます。または、GROUP BYビューが、GROUP BY、HAVINGまたは集計も含まれている外側の問合せブロックにマージされる問合せに表示されます。後者の場合、予測ビューには、元の外側の問合せブロックのGROUP BY、HAVINGおよび集計が含まれます。

予測ビューの前述の例では、オプティマイザがビューをマージするときに、DISTINCT演算子を外側の問合せブロックに移動し、元の問合せとの意味的な等価性を維持するためにいくつかの列を追加します。その後、問合せでは、外側の問合せブロックのSELECTリスト内の、目的の列のみを選択できます。最適化では、ビューのマージによって得られるすべてのメリットが保持されます。それらのメリットには、すべての表が1つの問合せブロック内にある、オプティマイザは、最終的な結合順序で必要に応じて表の順序を変更できる、すべての結合が完了するまでDISTINCT操作が遅延されるなどがあります。

述語のプッシュ

述語のプッシュでは、オプティマイザは関連する述語を、それを含む問合せブロックからビューの問合せブロックにプッシュします。マージされていないビューでは、プッシュされた述語は、索引へのアクセスまたはフィルタとして使用できるので、この方法を使用するとマージされていないビューのサブプランが改善されます。

たとえば、次のように表hr.contract_workersを作成するとします。

DROP TABLE contract_workers;
CREATE TABLE contract_workers AS (SELECT * FROM employees where 1=2);
INSERT INTO contract_workers VALUES (306, 'Bill', 'Jones', 'BJONES',
'555.555.2000', '07-JUN-02', 'AC_ACCOUNT', 8300, 0,205, 110);
INSERT INTO contract_workers VALUES (406, 'Jill', 'Ashworth', 'JASHWORTH',
'555.999.8181', '09-JUN-05', 'AC_ACCOUNT', 8300, 0,205, 50);
INSERT INTO contract_workers VALUES (506, 'Marcie', 'Lunsford', 'MLUNSFORD',
'555.888.2233', '22-JUL-01', 'AC_ACCOUNT', 8300, 0,205, 110);
COMMIT;
CREATE INDEX contract_workers_index ON contract_workers(department_id);

employeesおよびcontract_workersを参照するビューを作成します。ビューは、次のようにUNION集合演算子を使用した問合せによって定義されます。

CREATE VIEW all_employees_vw AS
( SELECT employee_id, last_name, job_id, commission_pct, department_id
FROM   employees )
UNION
( SELECT employee_id, last_name, job_id, commission_pct, department_id
FROM   contract_workers );

それから次のようにしてビューを問い合せます。

SELECT last_name
FROM   all_employees_vw
WHERE  department_id = 50;

ビューはUNION集合問合せのため、オプティマイザはビューの問合せをアクセス問合せブロックにマージすることはできません。そのかわりに、オプティマイザは、その述語であるWHERE句の条件department_id=50をビューのUNION集合問合せにプッシュすることで、アクセス文を変換できます。同等の変換された問合せは次のとおりです。

SELECT last_name
FROM   ( SELECT employee_id, last_name, job_id, commission_pct, department_id
FROM   employees
WHERE  department_id=50
UNION
SELECT employee_id, last_name, job_id, commission_pct, department_id
FROM   contract_workers
WHERE  department_id=50 );

変換された問合せは、各問合せブロックで索引アクセスを考慮できるようになります。

副問合せのネスト解除

副問合せのネスト解除では、オプティマイザはネストされた問合せを同等の結合文に変換してから、その結合を最適化します。この変換により、オプティマイザはアクセス・パス、結合方法および結合順序の選択時に副問合せの表を考慮できます。オプティマイザがこの変換を実行できるのは、結果の結合文が元の文と同じ行を戻すことが保証されており、副問合せにAVGなどの集計機能が含まれていない場合のみです。

たとえば、ユーザーshとして接続して、次の問合せを実行するとします。

SELECT *
FROM   sales
WHERE  cust_id IN ( SELECT cust_id
FROM   customers );

customers.cust_id列はプライマリ・キーのため、オプティマイザは複雑な問合せを、同じデータを戻すことが保証されている次の結合文に変換できます。

SELECT sales.*
FROM   sales, customers
WHERE  sales.cust_id = customers.cust_id;

オプティマイザが複雑な文を結合文に変換できない場合は、親の文と副問合せを個別の文として、それぞれに対して実行計画を選択します。それからオプティマイザは副問合せを実行し、戻された行を使用して親の問合せを実行します。実行計画全体の実行速度を上げるため、オプティマイザはサブプランを効率的な順序で並べます。

マテリアライズド・ビューを使用したクエリー・リライト

マテリアライズド・ビューは、データベースがマテリアライズして表に保存した問合せの結果です。

ユーザーの問合せが、マテリアライズド・ビューに関連付けられた問合せと互換性がある場合、オプティマイザは、その問合せをマテリアライズド・ビューの観点からリライトできます。この手法では、ほとんどの問合せ結果がデータベースで再計算されるため、問合せの実行が改善されます。

オプティマイザは、ユーザー問合せと互換性のあるマテリアライズド・ビューを検索し、1つ以上のマテリアライズド・ビューを選択してユーザー問合せをリライトします。問合せをリライトするためのマテリアライズド・ビューの使用はコストベースです。したがって、マテリアライズド・ビューを使用せずに生成された計画のコストが、マテリアライズド・ビューを使用して生成された計画のコストより低い場合、問合せはリライトされません。

次のマテリアライズド・ビュー、cal_month_sales_mvについて検討します。これは各月の販売金額(ドル)を集計するものです。

CREATE MATERIALIZED VIEW cal_month_sales_mv
ENABLE QUERY REWRITE
AS
SELECT t.calendar_month_desc, SUM(s.amount_sold) AS dollars
FROM   sales s, times t
WHERE  s.time_id = t.time_id
GROUP BY t.calendar_month_desc;

販売数は通常の月で約百万と仮定します。ビューには、各月の販売金額(ドル)について、あらかじめ計算されている集計があります。次の問合せを考えてみます。これは各月の販売金額の合計を問い合せるものです。

SELECT t.calendar_month_desc, SUM(s.amount_sold)
FROM   sales s, times t
WHERE  s.time_id = t.time_id
GROUP BY t.calendar_month_desc;

クエリー・リライトを行わない場合、データベースはsalesディレクトリにアクセスして販売金額の合計を計算する必要があります。この方法ではsalesからの何百万行もの読取りが行われるため、問合せのレスポンス時間は必然的に遅くなります。また結合では、データベースが何百万もの行で結合を計算する必要があるため、問合せレスポンスはさらに遅くなります。クエリー・リライトを使用すると、オプティマイザは次のように問合せを透過的にリライトします。

SELECT calendar_month, dollars
FROM   cal_month_sales_mv;

関連項目:

クエリー・リライトの詳細は、『Oracle Databaseデータ・ウェアハウス・ガイド』を参照してください

スター型変換

スター型変換は、スター・スキーマ内のファクト表の全表スキャンを回避するオプティマイザ変換です。

この項の内容は次のとおりです。

- スター・スキーマについて

- スター型変換の目的

- スター型変換の仕組み

- スター型変換の制御

- スター型変換: シナリオ

- 一時表の変換: シナリオ

スター・スキーマについて

スター・スキーマはデータをファクトとディメンションに分割します。

ファクトは、販売などのイベントの測定結果で、通常は数値です。ディメンションは、日付、場所、製品などのファクトを識別するカテゴリです。

ファクト表には、スキーマのディメンション表の主キーで構成される複合キーがあります。ディメンション表は、問合せを制限する値を選択できるようにする検索表または参照表として機能します。

通常、図では、中央のファクト表が直線でディメンション表に結ばれる形で表示され、星型のように見えます。次の図では、ファクト表としてsales、ディメンション表としてproducts、times、customersおよびchannelsが示されています。

図5-1 スター・スキーマ

スノーフレーク・スキーマは、ディメンション表が他の表を参照するスター・スキーマです。スノーストーム・スキーマは、スノーフレーク・スキーマの組合せです。

関連項目:

スター・スキーマの詳細は、『Oracle Databaseデータ・ウェアハウス・ガイド』を参照してください。

スター型変換の目的

ファクト表とディメンション表の結合では、スター型変換により、ファクト表の全スキャンを回避できます。

スター型変換は、制約ディメンション行に結合される関連ファクト行のみをフェッチすることで、パフォーマンスを向上させます。場合によっては、問合せにディメンション表の他の列の制限的なフィルタが含まれていることがあります。フィルタの組合せにより、データベースがファクト表から処理するデータ・セットを大幅に減らすことができます。

スター型変換の仕組み

スター型変換では、制約ディメンションに対応する、ビットマップ・セミ結合述語と呼ばれる副問合せ述語が追加されます。

オプティマイザは、ファクト結合列に索引が存在する場合に変換を実行します。副問合せによって提供されるキー値のビットマップANDおよびOR操作を駆動することによって、データベースでは、ファクト表から関連行のみを取り出せば済みます。ディメンション表の述語によってかなりのデータがフィルタ処理で除外される場合、変換は、ファクト表の全スキャンよりも効率的であると考えられます。

データベースがファクト表から関連行を取り出した後、データベースで、元の述語を使用してディメンション表にそれらの行を後戻り結合する必要がある場合があります。次の条件が当てはまる場合、データベースでは、ディメンション表の後戻り結合を回避できます。

- ディメンション表のすべての述語がセミ結合副問合せ述語の一部である。

- 副問合せから選択された列が一意である。

- ディメンション列がSELECTリストやGROUP BY句などの中にない。

スター型変換の制御

STAR_TRANSFORMATION_ENABLED初期化パラメータは、スター型変換を制御します。このパラメータの値は、次のいずれかです。

- true
オプティマイザは、ファクト表と制約ディメンション表を自動的に識別することで、スター型変換を実行します。オプティマイザは、変換された計画のコストが他の計画のコストよりも低い場合にのみ、スター型変換を実行します。さらに、オプティマイザは、マテリアライズによりパフォーマンスが向上する場合は常に、一時表の変換を自動的に試行します(「一時表の変換: シナリオ」を参照)。

- false (デフォルト)
オプティマイザは、スター型変換を実行しません。

- TEMP_DISABLE
この値は、オプティマイザが一時表の変換を試行しないこと以外は、trueと同じです。

関連項目:

STAR_TRANSFORMATION_ENABLED初期化パラメータの詳細は、『Oracle Databaseリファレンス』を参照してください。

スター型変換: シナリオ

このシナリオでは、スター問合せのスター型変換を示します。

例5-6 スター問合せ

次の問合せでは、カリフォルニアのすべての市における、1999年の第1四半期と第2四半期のインターネットでの売上の総額を検索します。

SELECT c.cust_city,
t.calendar_quarter_desc,
SUM(s.amount_sold) sales_amount
FROM   sales s,
times t,
customers c,
channels ch
WHERE  s.time_id = t.time_id
AND    s.cust_id = c.cust_id
AND    s.channel_id = ch.channel_id
AND    c.cust_state_province = 'CA'
AND    ch.channel_desc = 'Internet'
AND    t.calendar_quarter_desc IN ('1999-01','1999-02')
GROUP BY c.cust_city, t.calendar_quarter_desc;

次に出力の例を示します。

CUST_CITY                      CALENDA SALES_AMOUNT
------------------------------ ------- ------------
Montara                        1999-02      1618.01
Pala                           1999-01      3263.93
Cloverdale                     1999-01        52.64
Cloverdale                     1999-02       266.28
. . .

この例では、salesはファクト表であり、他の表はディメンション表です。sales表に製品のすべての売上ごとに1つの行が含まれるため、この表には何十億もの売上レコードが含まれている可能性があります。ただし、特定の四半期については、カリフォルニアでインターネットを通じて顧客に販売された製品はあまり多くありません。

例5-7 スター型変換

この例は、例5-6の問合せのスター型変換を示しています。この変換により、salesの全表スキャンは回避されます。

SELECT c.cust_city, t.calendar_quarter_desc, SUM(s.amount_sold) sales_amount
FROM   sales s, times t, customers c
WHERE  s.time_id = t.time_id
AND    s.cust_id = c.cust_id
AND    c.cust_state_province = 'CA'
AND    t.calendar_quarter_desc IN ('1999-01','1999-02')
AND    s.time_id IN ( SELECT time_id
FROM   times
WHERE  calendar_quarter_desc IN('1999-01','1999-02') )
AND    s.cust_id IN ( SELECT cust_id
FROM   customers
WHERE  cust_state_province='CA' )
AND    s.channel_id IN ( SELECT channel_id
FROM   channels
WHERE  channel_desc = 'Internet' )
GROUP BY c.cust_city, t.calendar_quarter_desc;

例5-8 スター型変換の実行計画の一部

この例は、例5-7のスター型変換の編集済の実行計画を示しています。

行26は、sales表に全表スキャンのかわりに索引アクセス・パスがあることを示しています。channels(行14)、times(行19)およびcustomers(行24)の副問合せから得られる各キー値について、データベースは、salesファクト表の索引からビットマップを取得します(行15、20、25)。

ビットマップの各ビットは、ファクト表の行に対応します。副問合せからのキー値がファクト表の行内の値と同じ場合、ビットが設定されます。たとえば、ビットマップ101000... (省略記号は、残りの列の値が0であることを示します)の場合、ファクト表の行1および3に、副問合せからのキー値と一致する値があります。

行12、17および22の操作が副問合せからのキーに対して繰り返され、対応するビットマップが取得されます。例5-7では、customers副問合せにより、州がCAである顧客のIDが検索されます。ビットマップ101000... は、customers表の副問合せからの顧客IDキー値103515に対応すると仮定します。また、customers副問合せにより、ビットマップが010000...であるキー値103516が生成されると仮定します。これは、salesの行2のみが、副問合せからのキー値と一致する値を持つことを意味します。

データベースでは、(OR演算子を使用して)各副問合せのビットマップがマージされます(行11、16、21)。customersの例では、2つのビットマップのマージ後、customers副問合せの単一のビットマップ111000...が生成されます。

101000...   # bitmap corresponding to key 103515
010000...   # bitmap corresponding to key 103516
---------
111000...   # result of OR operation

行10で、マージされたビットマップにAND演算子が適用されます。データベースですべてのOR操作が実行され、結果として生成されたchannelsのビットマップが100000...であると仮定します。このビットマップおよびcustomers副問合せからのビットマップでAND操作が実行されると、結果は次のようになります。

100000...   # channels bitmap after all OR operations performed
111000...   # customers bitmap after all OR operations performed
---------
100000...   # bitmap result of AND operation for channels and customers

行9では、データベースで、最終ビットマップの対応するROWIDが生成されます。データベースは、ROWIDを使用してsalesファクト表から行を取り出します(行26)。ここで示した例では、データベースは1つのROWIDのみを生成します。このROWIDは、最初の行に対応し、したがって、sales表全体をスキャンするのではなく、単一の行のみをフェッチします。

-------------------------------------------------------------------------------
| Id  | Operation                         | Name
-------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                  |
|   1 |  HASH GROUP BY                    |
|*  2 |   HASH JOIN                       |
|*  3 |    TABLE ACCESS FULL              | CUSTOMERS
|*  4 |    HASH JOIN                      |
|*  5 |     TABLE ACCESS FULL             | TIMES
|   6 |     VIEW                          | VW_ST_B1772830
|   7 |      NESTED LOOPS                 |
|   8 |       PARTITION RANGE SUBQUERY    |
|   9 |        BITMAP CONVERSION TO ROWIDS|
|  10 |         BITMAP AND                |
|  11 |          BITMAP MERGE             |
|  12 |           BITMAP KEY ITERATION    |
|  13 |            BUFFER SORT            |
|* 14 |             TABLE ACCESS FULL     | CHANNELS
|* 15 |            BITMAP INDEX RANGE SCAN| SALES_CHANNEL_BIX
|  16 |          BITMAP MERGE             |
|  17 |           BITMAP KEY ITERATION    |
|  18 |            BUFFER SORT            |
|* 19 |             TABLE ACCESS FULL     | TIMES
|* 20 |            BITMAP INDEX RANGE SCAN| SALES_TIME_BIX
|  21 |          BITMAP MERGE             |
|  22 |           BITMAP KEY ITERATION    |
|  23 |            BUFFER SORT            |
|* 24 |             TABLE ACCESS FULL     | CUSTOMERS
|* 25 |            BITMAP INDEX RANGE SCAN| SALES_CUST_BIX
|  26 |       TABLE ACCESS BY USER ROWID  | SALES
-------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

2 - access("ITEM_1"="C"."CUST_ID")
3 - filter("C"."CUST_STATE_PROVINCE"='CA')
4 - access("ITEM_2"="T"."TIME_ID")
5 - filter(("T"."CALENDAR_QUARTER_DESC"='1999-01'
OR "T"."CALENDAR_QUARTER_DESC"='1999-02'))
14 - filter("CH"."CHANNEL_DESC"='Internet')
15 - access("S"."CHANNEL_ID"="CH"."CHANNEL_ID")
19 - filter(("T"."CALENDAR_QUARTER_DESC"='1999-01'
OR "T"."CALENDAR_QUARTER_DESC"='1999-02'))
20 - access("S"."TIME_ID"="T"."TIME_ID")
24 - filter("C"."CUST_STATE_PROVINCE"='CA')
25 - access("S"."CUST_ID"="C"."CUST_ID")

Note
-----
- star transformation used for this statement

一時表の変換: シナリオ

例5-8では、オプティマイザは、表channelsをsales表に後戻り結合しません。それは、表channelsが外部で参照されず、channel_idが一意であるためです。ただし、オプティマイザが後戻り結合をなくすことができない場合、データベースでは、一時表に副問合せの結果が格納されて、ビットマップ・キーの生成および後戻り結合のためにディメンションを再スキャンすることが回避されます。さらに、問合せがパラレルに実行される場合、データベースでは、各パラレル実行サーバーで、副問合せを再度実行するのではなく、一時表から結果を選択できるようにするために、結果がマテリアライズされます。

例5-9 一時表を使用したスター型変換

この例では、customersの副問合せの結果が一時表にマテリアライズされます。

SELECT t1.c1 cust_city, t.calendar_quarter_desc calendar_quarter_desc,
SUM(s.amount_sold) sales_amount
FROM   sales s, sh.times t, sys_temp_0fd9d6621_e7e24 t1
WHERE  s.time_id=t.time_id
AND    s.cust_id=t1.c0
AND    (t.calendar_quarter_desc='1999-q1' OR t.calendar_quarter_desc='1999-q2')
AND    s.cust_id IN    ( SELECT t1.c0
FROM   sys_temp_0fd9d6621_e7e24 t1 )
AND    s.channel_id IN ( SELECT ch.channel_id
FROM   channels ch
WHERE  ch.channel_desc='internet' )
AND    s.time_id IN    ( SELECT t.time_id
FROM   times t
WHERE  t.calendar_quarter_desc='1999-q1'
OR     t.calendar_quarter_desc='1999-q2' )
GROUP BY t1.c1, t.calendar_quarter_desc

オプティマイザは、customersを一時表sys_temp_0fd9d6621_e7e24と置き換え、列cust_idおよびcust_cityへの参照を一時表の対応する列と置き換えます。データベースでは、(c0 NUMBER, c1 VARCHAR2(30))という2つの列を持つ一時表が作成されます。これらの列は、customers表のcust_idおよびcust_cityに対応します。データベースでは、前述の問合せの実行の開始時に、次の問合せを実行することで、一時表が移入されます。

SELECT c.cust_id, c.cust_city FROM customers WHERE c.cust_state_province = 'CA'

例5-10 一時表を使用したスター型変換の実行計画の一部

次の例は、例5-9の問合せの編集済の実行計画を示しています。

-------------------------------------------------------------------------------
| Id  | Operation                          | Name
-------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                   |
|   1 |  TEMP TABLE TRANSFORMATION         |
|   2 |   LOAD AS SELECT                   |
|*  3 |    TABLE ACCESS FULL               | CUSTOMERS
|   4 |   HASH GROUP BY                    |
|*  5 |    HASH JOIN                       |
|   6 |     TABLE ACCESS FULL              | SYS_TEMP_0FD9D6613_C716F
|*  7 |     HASH JOIN                      |
|*  8 |      TABLE ACCESS FULL             | TIMES
|   9 |      VIEW                          | VW_ST_A3F94988
|  10 |       NESTED LOOPS                 |
|  11 |        PARTITION RANGE SUBQUERY    |
|  12 |         BITMAP CONVERSION TO ROWIDS|
|  13 |          BITMAP AND                |
|  14 |           BITMAP MERGE             |
|  15 |            BITMAP KEY ITERATION    |
|  16 |             BUFFER SORT            |
|* 17 |              TABLE ACCESS FULL     | CHANNELS
|* 18 |             BITMAP INDEX RANGE SCAN| SALES_CHANNEL_BIX
|  19 |           BITMAP MERGE             |
|  20 |            BITMAP KEY ITERATION    |
|  21 |             BUFFER SORT            |
|* 22 |              TABLE ACCESS FULL     | TIMES
|* 23 |             BITMAP INDEX RANGE SCAN| SALES_TIME_BIX
|  24 |           BITMAP MERGE             |
|  25 |            BITMAP KEY ITERATION    |
|  26 |             BUFFER SORT            |
|  27 |              TABLE ACCESS FULL     | SYS_TEMP_0FD9D6613_C716F
|* 28 |             BITMAP INDEX RANGE SCAN| SALES_CUST_BIX
|  29 |        TABLE ACCESS BY USER ROWID  | SALES
-------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

3 - filter("C"."CUST_STATE_PROVINCE"='CA')
5 - access("ITEM_1"="C0")
7 - access("ITEM_2"="T"."TIME_ID")
8 - filter(("T"."CALENDAR_QUARTER_DESC"='1999-01' OR
"T"."CALENDAR_QUARTER_DESC"='1999-02'))
17 - filter("CH"."CHANNEL_DESC"='Internet')
18 - access("S"."CHANNEL_ID"="CH"."CHANNEL_ID")
22 - filter(("T"."CALENDAR_QUARTER_DESC"='1999-01' OR
"T"."CALENDAR_QUARTER_DESC"='1999-02'))
23 - access("S"."TIME_ID"="T"."TIME_ID")
28 - access("S"."CUST_ID"="C0")

この計画の行1、2および3では、customers副問合せが一時表にマテリアライズされます。行6では、データベースで、(副問合せではなく)一時表がスキャンされて、ファクト表からビットマップが作成されます。行27では、customersをスキャンするかわりに、後戻り結合のために、一時表がスキャンされます。フィルタは一時表のマテリアライズの間に適用されているため、データベースでは、一時表のcustomersにフィルタを適用する必要はありません。

インメモリー集計

インメモリー集計の基本的なアプローチは、スキャン中に集計することです。

典型的なスター・クエリーの場合など、集計に関係する問合せブロック、および単一の大きな表から複数の小さな表への結合を最適化するために、変換ではKEY VECTORおよびVECTOR GROUP BY操作を使用します。これらの操作では、結合と集計に効率的なインメモリー配列を使用します。基礎となる表がインメモリー列表の場合に特に効果的です。

この項の内容は次のとおりです。

- インメモリー集計の目的

- インメモリー集計の仕組み

- インメモリー集計の制御

- インメモリー集計: シナリオ

- インメモリー集計: 例

インメモリー集計の目的

小さな表と大きな表の間の結合の結果を集計する問合せのパフォーマンスを向上させるために、VECTOR GROUP BY変換は、CPU使用率、特にCPUキャッシュを最適化します。

データベースは最初の集計(SQLエンジンが最大量の行を処理する必要のある場所)までの作業を加速します。表スキャンと結合操作の完了を待機せずに、大きな表のスキャンで、ベクター結合およびgroup-by操作(集計)が同時に発生することがあります。

インメモリー集計の仕組み

通常の分析問合せはファクト表から集計し、ファクト表を1つ以上のディメンションに結合します。

このタイプの問合せは、大量のデータをスキャンし、オプションでフィルタ処理を行い、1列から40列までのGROUP BYを実行します。オプティマイザは、キー・ベクター(個別の結合キー)のサイズや個別のグループ化キーの数などの考慮事項に基づいて、ベクター変換を使用するかどうかを決定します。ディメンション結合キーのカーディナリティが低い場合に、オプティマイザはこの変換を選択する傾向があります。

VECTOR GROUP BY集計では、大きな表で実行する行ごとの処理時間を短縮するために、小さな表の処理に前もって時間が割かれます。通常の分析問合せでは、次に示す処理ステージに行が分散されるため、この最適化が可能です。

1. 表のフィルタ処理と行セットの生成

2. 行セットの結合

3. 行の集計

ステージ間の作業単位をデータ・フロー演算子(DFO)と呼びます。VECTOR GROUP BY集計では、ディメンションごとにDFOを使用して、キー・ベクター構造と一時表を作成します。ファクト表のメジャー列を集計する場合、データベースではこのキー・ベクターを使用して、ファクト結合キーをその稠密グループ化キーに変換します。遅延マテリアライズ・ステップは、稠密グループ化キーで一時表に結合します。

キー・ベクター

キー・ベクターは、稠密結合キーと稠密グループ化キー間をマップするデータ構造です。

稠密キーは、ネイティブ整数として格納され、値の範囲を持つ数値キーです。稠密結合キーは、結合列が特定のファクト表またはディメンションから取得されるすべての結合キーを表します。稠密グループ化キーは、グループ化列が特定のファクト表またはディメンションから取得されるすべてのグループ化キーを表します。キー・ベクターは、高速参照を可能にします。

例5-11 キー・ベクター

hr.locations表に、次のようなcountry_idの値があるとします(結果のうち冒頭の一部のみを示しています)。

SQL> SELECT country_id FROM locations;

CO
--
IT
IT
JP
JP
US
US
US
US
CA
CA
CN

複合分析問合せは、フィルタWHERE country_id='US'をlocations表に適用します。このフィルタのキー・ベクターは、次の1次元配列のようになります。

0
0
0
0
1
1
1
1
0
0
0

前の配列では、1はcountry_id='US'の稠密グループ化キーです。0の値は、このフィルタに一致しないlocationsの行を示します。問合せでフィルタWHERE country_id IN ('US','JP')を使用する場合、配列は次のようになります。ここで、2はJPの稠密グループ化キー、1はUSの稠密グループ化キーです。

0
0
2
2
1
1
1
1
0
0
0

インメモリー集計の2つのフェーズ

通常、VECTOR GROUP BY集計は各ディメンションを順番に処理してから、ファクト表を処理します。

インメモリー集計を実行する場合、データベースは次のように処理を行います。

1. 各ディメンションを次の順序で処理します。

a. 一意の稠密グループ化キーを検索します。

b. キー・ベクターを作成します。

c. 一時表を作成します(CURSOR DURATION MEMORY)。

次の図に、DFO 0のディメンション表のスキャンで開始し、一時表の作成で終了する、このフェーズのステップを示します。最も単純な形式のパラレルGROUP BYまたは結合処理では、データベースは自身のDFO内で各結合またはGROUP BYを処理します。

図5-2 インメモリー集計のフェーズ1

2. ファクト・テーブルを処理します。

a. 前のフェーズで作成したキー・ベクターを使用して、すべての結合と集計を処理します。

b. 結果を各一時表に再び結合します。

図5-3に、2つのディメンションがあるファクト表の結合のフェーズ2を示します。DFO 0では、データベースはファクト表の全スキャンを実行し、各ディメンションのキー・ベクターを使用して不一致の行をフィルタで除外します。DFO 2は、DFO 0の結果をDFO 1と結合します。DFO 4は、DFO 2の結果をDFO 3と結合します。

図5-3 インメモリー集計のフェーズ2

インメモリー集計の制御

VECTOR GROUP BY集計では、新規SQLまたはパブリック初期化パラメータは不要です。

次のヒントのペアを使用できます。

- 問合せブロック・ヒント
VECTOR_TRANSFORMでは、コストにかかわらず、指定した問合せブロックに対してベクター変換を有効にします。NO_VECTOR_TRANSFORMは、指定した問合せブロックからのベクター変換を無効にします。

- 表ヒント
次のヒントのペアを使用できます。

- VECTOR_TRANSFORM_FACTでは、ベクター変換で生成されたファクト表に、指定したFROM式が含まれます。NO_VECTOR_TRANSFORM_FACTでは、ベクター変換で生成されたファクト表から、指定したFROM式が除外されます。

- VECTOR_TRANSFORM_DIMSでは、ベクター変換で生成された有効なディメンションに、指定したFROM式が含まれます。NO_VECTOR_TRANSFORM_DIMSでは、ベクター変換で生成された有効なディメンションから、指定したFROM式が除外されます。

関連項目:

VECTOR_TRANSFORM_FACTおよびVECTOR_TRANSFORM_DIMSヒントの詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

インメモリー集計: シナリオ

この項では、VECTOR GROUP BY集計の仕組みの概念的な例を示します。

注意:

シナリオに使用しているスキーマ表はサンプルではなく、表示されている実行計画も実際のものではありません。

この項の内容は次のとおりです。

スター・スキーマのサンプル分析問合せ

このシナリオのサンプル・スター・スキーマには、sales_onlineファクト表と、2つのディメンション表geographyおよびproductsが含まれます。

geographyの各行は、geog_id列で一意に識別されます。productsの各行は、prod_id列で一意に識別されます。sales_onlineの各行は、geog_id列、prod_id列および販売量で一意に識別されます。

表5-1 geography表のサンプル行

country

state

city

geog_id

USA

WA

seattle

2

USA

WA

spokane

3

USA

CA

SF

7

USA

CA

LA

8

表5-2 products表のサンプル行

manuf

category

subcategory

prod_id

Acme

sport

bike

4

Acme

sport

ball

3

Acme

electric

bulb

1

Acme

electric

switch

8

表5-3 sales_online表のサンプル行

prod_id

geog_id

amount

8

1

100

9

1

150

8

2

100

4

3

110

2

30

130

6

20

400

3

1

100

1

7

120

3

8

130

4

3

200

仕事上でマネージャに、「各サブカテゴリのAcme製品が、ワシントンでオンライン販売された数と、カリフォルニアで販売された数はいくつだったか」と聞かれたとします。この質問に答えるには、sales_onlineファクト表の分析問合せでproductsおよびgeographyディメンション表を次のように結合します。

SELECT p.category, p.subcategory, g.country, g.state, SUM(s.amount)
FROM   sales_online s, products p, geography g
WHERE  s.geog_id = g.geog_id
AND    s.prod_id = p.prod_id
AND    g.state IN ('WA','CA')
AND    p.manuf = 'ACME'
GROUP BY category, subcategory, country, state

手順1: geographyディメンションのキー・ベクターと一時表の作成

この問合せのVECTOR GROUP BY集計の最初のフェーズでは、データベースはワシントンまたはカリフォルニア州の市について、各市/州の組合せに対する稠密グループ化キーを作成します。

表5-6では、1はUSA,WAグループ化キーで、2はUSA,CAグループ化キーです。

表5-4 geographyの稠密グループ化キー

country

state

city

geog_id

dense_gr_key_geog

USA

WA

seattle

2

1

USA

WA

spokane

3

1

USA

CA

SF

7

2

USA

CA

LA

8

2

geography表のキー・ベクターは、表5-5の最後の列で表される配列のようになります。値は、geography稠密グループ化キーです。したがって、キー・ベクターは、sales_onlineのどの行がgeography.stateフィルタ基準(CAまたはWAの州の販売)を満たし、各行がどの国/州グループ(USA、WAグループまたはUSA、CAグループ)に属するかを示します。

表5-5 オンライン販売

prod_id

geog_id

amount

geographyのキー・ベクター

8

1

100

0

9

1

150

0

8

2

100

1

4

3

110

1

2

30

130

0

6

20

400

0

3

1

100

0

1

7

120

2

3

8

130

2

4

3

200

1

内部的に、データベースは次のような一時表を作成します。

CREATE TEMPORARY TABLE tt_geography AS
SELECT MAX(country), MAX(state), KEY_VECTOR_CREATE(...) dense_gr_key_geog
FROM   geography
WHERE  state IN ('WA','CA')
GROUP BY country, state

表5-6に、tt_geography一時表の行を示します。USA、WAの組合せに対する稠密グループ化キーは1で、USA、CAの組合せに対する稠密グループ化キーは2です。

表5-6 tt_geography

country

state

dense_gr_key_geog

USA

WA

1

USA

CA

2

手順2: productsディメンションのキー・ベクターと一時表の作成

データベースでは、Acme製品の個々のカテゴリ/サブカテゴリの組合せに対して稠密グループ化キーが作成されます。

たとえば、表5-7では、4がAcme electric switchの稠密グループ化キーです。

表5-7 products表のサンプル行

manuf

category

subcategory

prod_id

dense_gr_key_prod

Acme

sport

bike

4

1

Acme

sport

ball

3

2

Acme

electric

bulb

1

3

Acme

electric

switch

8

4

products表のキー・ベクターは、表5-8の最後の列で表される配列のようになります。値は、products稠密グループ化キーを表します。たとえば、4はAcme electric switchのオンライン販売を表します。したがって、キー・ベクターは、sales_onlineのどの行がproductsフィルタ基準(Acme製品の販売)を満たすかを示します。

表5-8 キー・ベクター

prod_id

geog_id

amount

productsのキー・ベクター

8

1

100

4

9

1

150

0

8

2

100

4

4

3

110

1

2

30

130

0

6

20

400

0

3

1

100

2

1

7

120

3

3

8

130

2

4

3

200

1

内部的に、データベースは次のような一時表を作成します。

CREATE TEMPORTARY TABLE tt_products AS
SELECT MAX(category), MAX(subcategory), KEY_VECTOR_CREATE(...) dense_gr_key_prod
FROM   products
WHERE  manuf = 'ACME'
GROUP BY category, subcategory

表5-9に、この一時表の行を示します。

表5-9 tt_products

category

subcategory

dense_gr_key_prod

sport

bike

1

sport

ball

2

electric

bulb

3

electric

switch

4

手順3: キー・ベクター問合せ変換

このフェーズでは、データベースはファクト表を処理します。

オプティマイザは、元の問合せを、キー・ベクターにアクセスする次の同等の問合せに変換します。

SELECT KEY_VECTOR_PROD(prod_id),
KEY_VECTOR_GEOG(geog_id),
SUM(amount)
FROM   sales_online
WHERE  KEY_VECTOR_PROD_FILTER(prod_id) IS NOT NULL
AND    KEY_VECTOR_GEOG_FILTER(geog_id) IS NOT NULL
GROUP BY KEY_VECTOR_PROD(prod_id), KEY_VECTOR_GEOG(geog_id)

前の変換は、はるかに複雑な内部SQLの正確なレンディションではなく、基本概念を示すように設計された概念的な表現です。

手順4: ファクト表からの行フィルタ

このフェーズでは、グループ化キーの各組合せの販売量を取得します。

データベースは、キー・ベクターを使用して、ファクト表から不要な行をフィルタで除外します。表5-10では、最初の3列がsales_online表を表します。最後の2列は、geographyおよびproducts表の稠密グループ化キーを提供します。

表5-10 sales_online表の稠密グループ化キー

prod_id

geog_id

amount

dense_gr_key_prod

dense_gr_key_geog

7

1

100

4

9

1

150

8

2

100

4

1

4

3

110

1

1

2

30

130

6

20

400

3

1

100

2

1

7

120

3

2

3

8

130

2

2

4

3

200

1

1

表5-11に示すように、データベースはsales_onlineから、どちらの稠密グループ化キーもnull値でない行のみを取得しており、すべてのフィルタ基準を満たす行が示されています。

表5-11 sales_online表からフィルタされた行

geog_id

prod_id

amount

dense_gr_key_prod

dense_gr_key_geog

2

8

100

4

1

3

4

110

1

1

3

4

200

1

1

7

1

120

3

2

8

3

130

2

2

手順5: 配列を使用した集計

データベースでは、多次元配列を使用して集計を実行します。

表5-12では、geographyグループ化キーは水平で、productsグループ化キーは垂直です。データベースは、各稠密グループ化キーの組合せの交差部分の値を加算します。たとえば、geographyグループ化キー1とproductsグループ化キー1の交差部分では、110と200の合計は310です。

表5-12 集計配列

dgkp/dgkg

1

2

1

110,200

2

130

3

120

4

100

手順6: 一時表への再結合

処理の最終ステージでは、データベースが稠密グループ化キーを使用して行を一時表に再結合し、地域とカテゴリの名前を取得します。

結果は次のようになります。

CATEGORY SUBCATEGORY COUNTRY STATE AMOUNT
-------- ----------- ------- ----- ------
electric bulb        USA     CA    120
electric switch      USA     WA    100
sport    ball        USA     CA    130
sport    bike        USA     WA    310

インメモリー集計: 例

この例では、仕事上の問いは「各カレンダ年に販売されたカテゴリごとの製品数はいくつか」というものです。

times、productsおよびsalesの各表を結合する次の問合せを作成します。

SELECT t.calendar_year, p.prod_category, SUM(quantity_sold)
FROM   times t, products p, sales s
WHERE  t.time_id = s.time_id
AND    p.prod_id = s.prod_id
GROUP BY t.calendar_year, p.prod_category;

例5-12 VECTOR GROUP BY実行計画

次の例に、現在のカーソルに含まれる実行計画を示します。手順4と8では、ディメンション表timesおよびproductsのキー・ベクターを作成しています。手順17と18では、前に作成したキー・ベクターを使用しています。手順3、7および15では、VECTOR GROUP BY操作を行っています。

SQL_ID  0yxqj2nq8p9kt, child number 0
-------------------------------------
SELECT t.calendar_year, p.prod_category, SUM(quantity_sold) FROM
times t, products p, sales f WHERE  t.time_id = f.time_id AND
p.prod_id   = f.prod_id GROUP BY t.calendar_year, p.prod_category

Plan hash value: 2377225738
------------------------------------------------------------------------------------------------------
|Id| Operation                           | Name              |Rows|Bytes|Cost(%CPU)|Time|Pstart|Pstop|
------------------------------------------------------------------------------------------------------
| 0|SELECT STATEMENT                     |                         |    |     |285(100)|        | |  |
| 1| TEMP TABLE TRANSFORMATION           |                         |    |     |        |        | |  |
| 2|  LOAD AS SELECT                     |SYS_TEMP_0FD9D6644_11CBE8|    |     |        |        | |  |
| 3|   VECTOR GROUP BY                   |                         |   5|  80 |  3(100)|00:00:01| |  |
| 4|    KEY VECTOR CREATE BUFFERED       | :KV0000                 |1826|29216|  3(100)|00:00:01| |  |
| 5|     TABLE ACCESS INMEMORY FULL      | TIMES                   |1826|21912|  1(100)|00:00:01| |  |
| 6|  LOAD AS SELECT                     |SYS_TEMP_0FD9D6645_11CBE8|    |     |        |        | |  |
| 7|   VECTOR GROUP BY                   |                         |   5| 125 |  1(100)|00:00:01| |  |
| 8|    KEY VECTOR CREATE BUFFERED       | :KV0001                 |  72| 1800|  1(100)|00:00:01| |  |
| 9|     TABLE ACCESS INMEMORY FULL      | PRODUCTS                |  72| 1512|  0  (0)|        | |  |
|10|  HASH GROUP BY                      |                         |  18| 1440|282 (99)|00:00:01| |  |
|11|   HASH JOIN                         |                         |  18| 1440|281 (99)|00:00:01| |  |
|12|    HASH JOIN                        |                         |  18| 990 |278(100)|00:00:01| |  |
|13|     TABLE ACCESS FULL               |SYS_TEMP_0FD9D6644_11CBE8|   5|  80 |  2  (0)|00:00:01| |  |
|14|     VIEW                            | VW_VT_AF278325          |  18| 702 |276(100)|00:00:01| |  |
|15|      VECTOR GROUP BY                |                         |  18| 414 |276(100)|00:00:01| |  |
|16|       HASH GROUP BY                 |                         |  18| 414 |276(100)|00:00:01| |  |
|17|        KEY VECTOR USE               | :KV0000                 |918K|  20M|276(100)|00:00:01| |  |
|18|         KEY VECTOR USE              | :KV0001                 |918K|  16M|272(100)|00:00:01| |  |
|19|          PARTITION RANGE ALL        |                         |918K|  13M|257(100)|00:00:01|1|28|
|20|           TABLE ACCESS INMEMORY FULL| SALES                   |918K|  13M|257(100)|00:00:01|1|28|
|21|    TABLE ACCESS FULL                |SYS_TEMP_0FD9D6645_11CBE8|  5 |  125|  2  (0)|00:00:01| |  |
------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------
11 - access("ITEM_10"=INTERNAL_FUNCTION("C0") AND "ITEM_11"="C2")
12 - access("ITEM_8"=INTERNAL_FUNCTION("C0") AND "ITEM_9"="C2")

Note
-----
- vector transformation used for this statement

45 rows selected.

表拡張

表拡張では、オプティマイザが、パーティション表のread-mostly部分では索引を使用するが、表のアクティブ部分では索引を使用しない計画を生成します。

この項の内容は次のとおりです。

- 表拡張の目的

- 表拡張の仕組み

- 表拡張: シナリオ

- 表拡張とスター型変換: シナリオ

表拡張の目的

索引ベースの計画を使用すると、パフォーマンスを高めることができますが、索引のメンテナンスによりオーバーヘッドが発生します。多くのデータベースで、DMLはデータの一部にのみ影響を及ぼします。

表拡張では、更新のボリュームが大きい表に対して索引ベースの計画を使用します。read-mostlyデータのみで索引を作成し、アクティブ・データの索引オーバーヘッドを排除できます。こうして、表拡張でパフォーマンスを向上させ、索引のメンテナンスを回避できます。

表拡張の仕組み

表のパーティション化により、表拡張が可能になります。

パーティション表にローカル索引が存在する場合、オプティマイザは、特定のパーティションに対してその索引を使用不可とマークすることができます。実際、一部のパーティションは索引付けされていません。

表拡張では、オプティマイザは、問合せをUNION ALL文に変換します。一部の副問合せは索引付けされたパーティションにアクセスし、他の副問合せは索引付けされていないパーティションにアクセスします。オプティマイザは、パーティションで使用可能な最も効率的なアクセス方法を選択できます。このとき、そのアクセス方法が、問合せでアクセスされるすべてのパーティションに対して存在するかどうかは関係ありません。

オプティマイザは、必ずしも表拡張を選択するとはかぎりません。

- 表拡張はコストベースです。
データベースは、拡張された表の各パーティションに、UNION ALLのすべてのブランチで1回だけアクセスしますが、それに結合される表には各ブランチでアクセスします。

- セマンティクスの問題により、拡張が無効になる場合があります。
たとえば、外部結合の右側にある表は、表拡張の対象としては無効です。

EXPAND_TABLEヒントを使用して表拡張を制御できます。ヒントは、コストベースの決定を上書きしますが、セマンティクス・チェックは上書きしません。

関連項目:

- 「ヒントによるオプティマイザへの影響」

- SQLヒントの詳細は、『Oracle Database SQL言語リファレンス』を参照してください

表拡張: シナリオ

オプティマイザは、問合せで使用されている述語に基づいて、各表からどのパーティションにアクセスする必要があるかを追跡します。パーティション・プルーニングにより、オプティマイザは、表拡張を使用してより最適な計画を生成できるようになります。

前提条件

この例では、次のことを前提としています。

- time_id列でレンジ・パーティション化されているsh.sales表に対してスター・クエリーを実行します。

- 表拡張のメリットを確認するために、特定のパーティションで索引を無効にします。

表拡張を使用する手順は次のとおりです。

1. shユーザーとしてデータベースにログインします。

2. 次の問合せを実行します。

SELECT *
FROM   sales
WHERE  time_id >= TO_DATE('2000-01-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS')
AND    prod_id = 38;

3. DBMS_XPLANを問い合せて計画をEXPLAINします。

SET LINESIZE 150
SET PAGESIZE 0
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(format => 'BASIC,PARTITION'));

次の計画のPstartおよびPstop列に示されているように、オプティマイザは、フィルタから、表内の28パーティションのうちの16のパーティションにのみアクセスする必要があると判断します。

Plan hash value: 3087065703

--------------------------------------------------------------------------
|Id| Operation                                  | Name      |Pstart|Pstop|
--------------------------------------------------------------------------
| 0| SELECT STATEMENT                           |              |    |    |
| 1|  PARTITION RANGE ITERATOR                  |              | 13 | 28 |
| 2|   TABLE ACCESS BY LOCAL INDEX ROWID BATCHED| SALES        | 13 | 28 |
| 3|    BITMAP CONVERSION TO ROWIDS             |              |    |    |
|*4|     BITMAP INDEX SINGLE VALUE              |SALES_PROD_BIX| 13 | 28 |
--------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

4 - access("PROD_ID"=38)

オプティマイザは、アクセス対象のパーティションを決定した後、それらのパーティションのすべてで使用可能な索引について検討します。前述の計画では、オプティマイザは、sales_prod_bixビットマップ索引を使用することを選択しました。

4. sales表のSALES_1995パーティションの索引を無効にします。

ALTER INDEX sales_prod_bix MODIFY PARTITION sales_1995 UNUSABLE;

このDDLにより、パーティション1の索引が無効になります。このパーティションには、1996年以前のすべての売上が含まれています。

注意:

USER_IND_PARTITIONSビューを問い合せて、パーティションの情報を取得できます。

5. 売上の問合せを再度実行し、DBMS_XPLANを問い合せて計画を取得します。
出力から、計画が変更されなかったことがわかります。

Plan hash value: 3087065703

---------------------------------------------------------------------------
|Id| Operation                                  | Name        |Pstart|Pstop
---------------------------------------------------------------------------
| 0| SELECT STATEMENT                           |               |    |    |
| 1|  PARTITION RANGE ITERATOR                  |               | 13 | 28 |
| 2|   TABLE ACCESS BY LOCAL INDEX ROWID BATCHED| SALES         | 13 | 28 |
| 3|    BITMAP CONVERSION TO ROWIDS             |               |    |    |
|*4|     BITMAP INDEX SINGLE VALUE              | SALES_PROD_BIX| 13 | 28 |
---------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

4 - access("PROD_ID"=38)

索引が無効にされたパーティションは問合せに関係しないので、計画は同じです。問合せでアクセスされるすべてのパーティションが索引付けされている場合、データベースでは、索引を使用して問合せに答えられます。問合せは、28のうち16のパーティションにのみアクセスするため、パーティション1の索引を無効にしても計画に影響しません。

6. パーティション28(SALES_Q4_2003)の索引を無効にします(これは、問合せでアクセスする必要のあるパーティションです)。

ALTER INDEX sales_prod_bix MODIFY PARTITION sales_q4_2003 UNUSABLE;
ALTER INDEX sales_time_bix MODIFY PARTITION sales_q4_2003 UNUSABLE;

問合せでアクセスする必要のあるパーティションの索引を無効にすることにより、(表拡張をしなければ)問合せでこの索引を使用できなくなります。

7. DBMS_XPLANを使用して計画を問い合せます。
次の計画に示されているように、オプティマイザは、索引を使用しません。

Plan hash value: 3087065703

---------------------------------------------------------------------------
| Id| Operation                              | Name           |Pstart|Pstop
---------------------------------------------------------------------------
| 0 | SELECT STATEMENT                       |                |      |    |
| 1 |  PARTITION RANGE ITERATOR              |                |  13  | 28 |
|*2 |   TABLE ACCESS FULL                    | SALES          |  13  | 28 |
---------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("PROD_ID"=38)

前述の例では、問合せで16のパーティションにアクセスします。これらのうち15のパーティションで、索引が使用可能ですが、最後のパーティションでは索引は使用できません。オプティマイザは、いずれか1つのアクセス・パスを選択する必要があるため、どのパーティションでも索引を使用できません。

8. 表拡張を使用すると、オプティマイザは、元の問合せを次のようにリライトします。

SELECT *
FROM   sales
WHERE  time_id >= TO_DATE('2000-01-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS')
AND    time_id <  TO_DATE('2003-10-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS')
AND    prod_id = 38
UNION ALL
SELECT *
FROM   sales
WHERE  time_id >= TO_DATE('2003-10-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS')
AND    time_id < TO_DATE('2004-01-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS')
AND    prod_id = 38;

この問合せでは、UNION ALL内の最初の問合せブロックは、索引付けされているパーティションにアクセスし、2番目の問合せブロックは、索引付けされていないパーティションにアクセスします。2つの副問合せにより、アクセス先のすべてのパーティションの表スキャンを使用するよりも、索引の使用がより最適である場合は、オプティマイザは、最初の問合せブロックで索引を使用することを選択できます。

9. DBMS_XPLANを使用して計画を問い合せます。
計画は次のようになります。

Plan hash value: 2120767686

---------------------------------------------------------------------------
|Id| Operation                                    | Name     |Pstart|Pstop|
---------------------------------------------------------------------------
| 0| SELECT STATEMENT                             |               |   |   |
| 1|  VIEW                                        | VW_TE_2       |   |   |
| 2|   UNION-ALL                                  |               |   |   |
| 3|    PARTITION RANGE ITERATOR                  |               | 13| 27|
| 4|     TABLE ACCESS BY LOCAL INDEX ROWID BATCHED| SALES         | 13| 27|
| 5|      BITMAP CONVERSION TO ROWIDS             |               |   |   |
|*6|       BITMAP INDEX SINGLE VALUE              | SALES_PROD_BIX| 13| 27|
| 7|    PARTITION RANGE SINGLE                    |               | 28| 28|
|*8|     TABLE ACCESS FULL                        | SALES         | 28| 28|
---------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

6 - access("PROD_ID"=38)
8 - filter("PROD_ID"=38)

この計画に示されているように、2つの問合せブロックでUNION ALLが使用されます(手順2)。1つ目の問合せブロックのパーティション13から27までのアクセスには、索引が選択されます(手順6)。パーティション28では索引を使用できないため、2つ目の問合せブロックでは全表スキャンが選択されます(手順8)。

表拡張とスター型変換: シナリオ

スター型変換により、特定のタイプの問合せで、大きなファクト表の大部分にアクセスすることを回避できます(「スター型変換」を参照)。スター型変換では、いくつかの索引を定義する必要があります。それらの索引により、アクティブに更新される表ではオーバーヘッドが生じる可能性があります。表拡張では、オプティマイザが表の索引付けされた部分でのみスター型変換を検討できるようにするために、アクティブでないパーティションでのみ索引を定義することが可能です。

前提条件

この例では、次のことを前提としています。

- 「スター型変換: シナリオ」で使用されているものと同じスキーマを問い合せます。

- salesの最後のパーティションは、多くの場合タイム・パーティション表と同様に、アクティブに更新されます。

- オプティマイザで表拡張を使用します。

スター・クエリーで表拡張を使用する手順は次のとおりです。

1. 次のように、最後のパーティションの索引を無効にします。

ALTER INDEX sales_channel_bix MODIFY PARTITION sales_q4_2003 UNUSABLE;
ALTER INDEX sales_cust_bix MODIFY PARTITION sales_q4_2003 UNUSABLE;

2. 次のスター・クエリーを実行します。

SELECT t.calendar_quarter_desc, SUM(s.amount_sold) sales_amount
FROM   sales s, times t, customers c, channels ch
WHERE  s.time_id = t.time_id
AND    s.cust_id = c.cust_id
AND    s.channel_id = ch.channel_id
AND    c.cust_state_province = 'CA'
AND    ch.channel_desc = 'Internet'
AND    t.calendar_quarter_desc IN ('1999-01','1999-02')
GROUP BY t.calendar_quarter_desc;

3. DBMS_XPLANを使用してカーソルを問い合せます。次の計画が表示されます。

---------------------------------------------------------------------------
|Id| Operation                          | Name            | Pstart| Pstop |
---------------------------------------------------------------------------
| 0| SELECT STATEMENT                   |                 |       |       |
| 1|  HASH GROUP BY                     |                 |       |       |
| 2|   VIEW                             |VW_TE_14         |       |       |
| 3|    UNION-ALL                       |                 |       |       |
| 4|     HASH JOIN                      |                 |       |       |
| 5|      TABLE ACCESS FULL             |TIMES            |       |       |
| 6|      VIEW                          |VW_ST_1319B6D8   |       |       |
| 7|       NESTED LOOPS                 |                 |       |       |
| 8|        PARTITION RANGE SUBQUERY    |                 |KEY(SQ)|KEY(SQ)|
| 9|         BITMAP CONVERSION TO ROWIDS|                 |       |       |
|10|          BITMAP AND                |                 |       |       |
|11|           BITMAP MERGE             |                 |       |       |
|12|            BITMAP KEY ITERATION    |                 |       |       |
|13|             BUFFER SORT            |                 |       |       |
|14|              TABLE ACCESS FULL     |CHANNELS         |       |       |
|15|             BITMAP INDEX RANGE SCAN|SALES_CHANNEL_BIX|KEY(SQ)|KEY(SQ)|
|16|           BITMAP MERGE             |                 |       |       |
|17|            BITMAP KEY ITERATION    |                 |       |       |
|18|             BUFFER SORT            |                 |       |       |
|19|              TABLE ACCESS FULL     |TIMES            |       |       |
|20|             BITMAP INDEX RANGE SCAN|SALES_TIME_BIX   |KEY(SQ)|KEY(SQ)|
|21|           BITMAP MERGE             |                 |       |       |
|22|            BITMAP KEY ITERATION    |                 |       |       |
|23|             BUFFER SORT            |                 |       |       |
|24|              TABLE ACCESS FULL     |CUSTOMERS        |       |       |
|25|             BITMAP INDEX RANGE SCAN|SALES_CUST_BIX   |KEY(SQ)|KEY(SQ)|
|26|        TABLE ACCESS BY USER ROWID  |SALES            | ROWID | ROWID |
|27|     NESTED LOOPS                   |                 |       |       |
|28|      NESTED LOOPS                  |                 |       |       |
|29|       NESTED LOOPS                 |                 |       |       |
|30|        NESTED LOOPS                |                 |       |       |
|31|         PARTITION RANGE SINGLE     |                 |    28 |    28 |
|32|          TABLE ACCESS FULL         |SALES            |    28 |    28 |
|33|         TABLE ACCESS BY INDEX ROWID|CHANNELS         |       |       |
|34|          INDEX UNIQUE SCAN         |CHANNELS_PK      |       |       |
|35|        TABLE ACCESS BY INDEX ROWID |CUSTOMERS        |       |       |
|36|         INDEX UNIQUE SCAN          |CUSTOMERS_PK     |       |       |
|37|       INDEX UNIQUE SCAN            |TIMES_PK         |       |       |
|38|      TABLE ACCESS BY INDEX ROWID   |TIMES            |       |       |
---------------------------------------------------------------------------

この計画では、表拡張が使用されます。最後のパーティションを除くすべてのパーティションにアクセスするUNION ALLブランチは、スター型変換を使用します。パーティション28の索引は無効化されているため、データベースは、全表スキャンを使用して最後のパーティションにアクセスします。

結合の因数分解

結合の因数分解として知られるコストベースの変換では、オプティマイザが、UNION ALL問合せのブランチの共通の計算を因数分解できます。

この項の内容は次のとおりです。

- 結合の因数分解の目的

- 結合の因数分解の仕組み

- 因数分解と結合順序: シナリオ

- 外部結合の因数分解: シナリオ

結合の因数分解の目的

UNION ALL問合せは、データベース・アプリケーション、特にデータ統合アプリケーションでは一般的です。多くの場合、UNION ALL問合せのブランチは、同じ実表を参照します。結合の因数分解を使用しない場合、オプティマイザは、UNION ALL問合せの各ブランチを単独で評価します。そのため、データ・アクセスや結合などの処理が繰り返し実行されることになります。結合の因数分解の変換では、UNION ALLブランチ間で共通の計算を共有できます。大きな実表を追加でスキャンすることを回避できるため、パフォーマンスが大幅に向上します。

結合の因数分解の仕組み

結合の因数分解では、3つ以上のUNION ALLブランチから複数の表を因数分解できます。次の例を使用して、結合の因数分解について説明します。

例5-13 UNION ALL問合せ

次の問合せでは、4つの表(t1、t2、t3およびt4)および2つのUNION ALLブランチの問合せを示しています。

SELECT t1.c1, t2.c2
FROM   t1, t2, t3
WHERE  t1.c1 = t2.c1
AND    t1.c1 > 1
AND    t2.c2 = 2
AND    t2.c2 = t3.c2
UNION ALL
SELECT t1.c1, t2.c2
FROM   t1, t2, t4
WHERE  t1.c1 = t2.c1
AND    t1.c1 > 1
AND    t2.c3 = t4.c3

前述の問合せで、表t1は、フィルタ述語t1.c1 > 1および結合述語t1.c1 = t2.c1と同様に、両方のUNION ALLブランチにあります。変換が行われない場合、データベースでは、表t1のスキャンとフィルタリングを2回(各ブランチに対して1回)実行する必要があります。

例5-14 因数分解された問合せ

次の問合せでは、結合の因数分解を使用して例5-13の問合せを変換します。

SELECT t1.c1, VW_JF_1.item_2
FROM   t1, (SELECT t2.c1 item_1, t2.c2 item_2
FROM   t2, t3
WHERE  t2.c2 = t3.c2
AND    t2.c2 = 2
UNION ALL
SELECT t2.c1 item_1, t2.c2 item_2
FROM   t2, t4
WHERE  t2.c3 = t4.c3) VW_JF_1
WHERE  t1.c1 = VW_JF_1.item_1
AND    t1.c1 > 1

この場合、表t1が因数分解されたため、データベースでは、t1の表のスキャンおよびフィルタリングが1回のみ実行されます。t1のサイズが大きい場合、この因数分解により、t1を2回スキャンおよびフィルタリングするための大きなパフォーマンス・コストを回避できます。

注意:

UNION ALL問合せのブランチに、DISTINCTファンクションを使用する句がある場合、結合の因数分解は無効です。

因数分解と結合順序: シナリオ

結合の因数分解では、結合順序の可能性を高めることができます。

例5-15 5つの表を含む問合せ

次の問合せで、ビューVは、例5-13の問合せと同じです。

SELECT *
FROM   t5, (SELECT t1.c1, t2.c2
FROM   t1, t2, t3
WHERE  t1.c1 = t2.c1
AND    t1.c1 > 1
AND    t2.c2 = 2
AND    t2.c2 = t3.c2
UNION ALL
SELECT t1.c1, t2.c2
FROM   t1, t2, t4
WHERE  t1.c1 = t2.c1
AND    t1.c1 > 1
AND    t2.c3 = t4.c3) V
WHERE  t5.c1 = V.c1
結合の因数分解の前に、データベースでは、まずt1、t2およびt3を結合して、その後それらをt5に結合する必要があります。

例5-16 ビューVからのt1の因数分解

次の問合せに示されているように、結合の因数分解で、ビューVからt1を因数分解する場合、データベースでは、t1をt5に結合できます。

SELECT *
FROM   t5, ( SELECT t1.c1, VW_JF_1.item_2
FROM   t1, (SELECT t2.c1 item_1, t2.c2 item_2
FROM   t2, t3
WHERE  t2.c2 = t3.c2
AND    t2.c2 = 2
UNION ALL
SELECT t2.c1 item_1, t2.c2 item_2
FROM   t2, t4
WHERE  t2.c3 = t4.c3) VW_JF_1
WHERE  t1.c1 = VW_JF_1.item_1
AND    t1.c1 > 1 )
WHERE  t5.c1 = V.c1

前述の問合せ変換により、新しい結合順序が作成されます。ただし、結合の因数分解では、特定の結合順序が設定されます。たとえば、前述の問合せでは、表t2およびt3は、ビューVW_JF_1のUNION ALL問合せの最初のブランチにあります。データベースでは、t1(これはVW_JF_1ビュー内で定義されていません)と結合する前に、t2をt3に結合する必要があります。設定された結合順序は、必ずしも最適な結合順序とはかぎりません。このため、オプティマイザは、コストベースの変換フレームワークを使用して結合の因数分解を実行します。オプティマイザは、結合の因数分解を使用した計画のコストと、結合の因数分解を使用しない計画のコストを計算し、最もコストの低い計画を選択します。

例5-17 ビュー定義が削除されたビューVからのt1の因数分解

次の問合せは例5-16の問合せと同じですが、因数分解をわかりやすくするために、ビュー定義が削除されています。

SELECT *
FROM   t5, (SELECT t1.c1, VW_JF_1.item_2
FROM   t1, VW_JF_1
WHERE  t1.c1 = VW_JF_1.item_1
AND    t1.c1 > 1)
WHERE  t5.c1 = V.c1

外部結合の因数分解: シナリオ

データベースは、外部結合、アンチ結合およびセミ結合の因数分解をサポートしていますが、サポートしているのは、そのような結合の右の表に対してのみです。たとえば、結合の因数分解では、t2を因数分解することで、次のUNION ALL問合せを変換できます。

SELECT t1.c2, t2.c2
FROM   t1, t2
WHERE  t1.c1 = t2.c1(+)
AND    t1.c1 = 1
UNION ALL
SELECT t1.c2, t2.c2
FROM   t1, t2
WHERE  t1.c1 = t2.c1(+)
AND    t1.c1 = 2

次の例は、変換を示しています。表t2は、副問合せのUNION ALLブランチに表示されなくなります。

SELECT VW_JF_1.item_2, t2.c2
FROM   t2, (SELECT t1.c1 item_1, t1.c2 item_2
FROM   t1
WHERE  t1.c1 = 1
UNION ALL
SELECT t1.c1 item_1, t1.c2 item_2
FROM   t1
WHERE  t1.c1 = 2) VW_JF_1
WHERE  VW_JF_1.item_1 = t2.c1(+)

第III部 問合せの実行計画

問合せのパフォーマンスが最適でない場合、実行計画は、問題を把握して解決方法を提供するための主要なツールになります。

この部には次の章が含まれます:

- 実行計画の生成と表示

- 実行計画の読取り

6 実行計画の生成と表示

この章の内容は次のとおりです。

- 実行計画の概要

- 計画の生成と表示について

- 実行計画の生成

- PLAN_TABLE出力の表示

実行計画の概要

文を実行するためにOracle Databaseが使用するステップの組合せが実行計画です。各処理では、データベースからデータ行を物理的に検索するか、文を発行したユーザーのためにデータ行を準備します。実行計画には、文がアクセスする各表へのアクセス・パスと、適切な結合方法に基づく表の順序(結合順序)が含まれています。

関連項目:

結合

計画の生成と表示について

EXPLAIN PLAN文は、SELECT、UPDATE、INSERTおよびDELETE文に関して、オプティマイザによって選択された実行計画を表示します。この項の内容は次のとおりです。

- 計画の説明について

- 実行計画の変化理由

- 排除行数の最少化のガイドライン

- 実行計画の評価のガイドライン

- EXPLAIN PLANの制限事項

- PLAN_TABLEの作成のガイドライン

計画の説明について

文の実行計画とは、その文を実行するためにデータベースで行われる一連の処理です。

行ソース・ツリーは、実行計画の中核です。このツリーには、次の情報が表示されます。

- 文によって参照される表の順序

- 文で言及される各表へのアクセス方法

- 文の結合操作の影響を受ける表の結合方法

- フィルタ、ソート、集計などのデータ操作

PLAN TABLEには、行ソース・ツリーの他、次の情報が含まれています。

- 最適化。各操作のコストとカーディナリティについて。

- パーティション化。アクセスされたパーティションのセットなど。

- パラレル実行。結合入力の配分方法など。

EXPLAIN PLANの結果を使用して、オプティマイザが特定の実行計画(たとえば、ネステッド・ループ結合)を選択するかどうかを判断できます。また、オプティマイザの決定(たとえば、オプティマイザがハッシュ結合でなくネステッド・ループ結合を選択した理由)を理解するためにも役立ちます。

関連項目:

- SQLの行ソース生成

- EXPLAIN PLAN文の詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

実行計画の変化理由

実行計画は基礎となるオプティマイザ入力が変化するたびに変化します。

EXPLAIN PLANの出力は、EXPLAINされたSQL文をデータベースがどのように実行するかを示します。実行環境とEXPLAIN PLAN環境は異なるため、この計画は、SQL文で使用される実際の実行計画とは異なる可能性があります。

注意:

実行計画の変更から生じる可能性があるSQLパフォーマンスの低下を回避するには、SQL計画の管理を使用することを検討してください。

関連項目:

「SQL計画ベースラインの管理」

スキーマの相違

スキーマは、様々な理由で異なる場合があります。

主な理由は次のとおりです。

- 実行とEXPLAIN PLANのデータベースが異なる場合。

- 文をEXPLAINするユーザーが、文を実行するユーザーとは異なる場合。2人のユーザーが同じデータベース内の異なるオブジェクトを指していれば、異なる実行計画が発生します。

- 2つの操作間でスキーマが変更された場合(多くは索引の変更)。

コストの相違

スキーマが同じであっても、コストに違いがある場合、オプティマイザは異なる実行計画を選択する可能性があります。

コストに影響を与えるいくつかの要因には次のものがあります。

- データ量と統計

- バインド変数の型と値

- グローバルまたはセッション・レベルで設定された初期化パラメータ

排除行数の最少化のガイドライン

EXPLAIN PLANを調べることにより、次の場合の排除行数を確認できます。

- 全体スキャン

- 選択性のないレンジ・スキャン

- 遅延した述語フィルタ

- 誤った結合順序

- 遅延したフィルタ処理

例6-1の計画では、最後のステップは非常に選択性のないレンジ・スキャンです。このレンジ・スキャンは76563回実行され、11432983行にアクセスし、アクセスした行の99パーセントを排除して76563行を保持します。11432983行にアクセスした結果、必要な行が76563行のみであると認識された理由について考えます。

例6-1 EXPLAIN PLAN内の排除行数の確認

Rows      Execution Plan
--------  ----------------------------------------------------
12  SORT AGGREGATE
2   SORT GROUP BY
76563    NESTED LOOPS
76575     NESTED LOOPS
19      TABLE ACCESS FULL CN_PAYRUNS_ALL
76570      TABLE ACCESS BY INDEX ROWID CN_POSTING_DETAILS_ALL
76570       INDEX RANGE SCAN (object id 178321)
76563     TABLE ACCESS BY INDEX ROWID CN_PAYMENT_WORKSHEETS_ALL
11432983      INDEX RANGE SCAN (object id 186024)

実行計画の評価のガイドライン

実行計画の操作のみでは、よく調整された文とうまく機能しない文を区別できません。たとえば、文による索引の使用がEXPLAIN PLAN出力で示されたとしても、その文が効率的に機能するとはかぎりません。効率的でない索引もあります。この場合、次を調べることをお薦めします。

- 使用される索引の列

- その索引の選択性(アクセスされる表の一部)

EXPLAIN PLANを使用してアクセス計画を判断し、後からテストによってそれが最適な計画であることを確認するのが最もよい方法です。計画を評価する際は、文の正確なリソース使用量を調べてください。

V$SQL_PLANビューを使用した計画の評価のガイドライン

EXPLAIN PLANコマンドを実行して計画を表示するかわりに、V$SQL_PLANビューを問い合せて計画を表示できます。V$SQL_PLANには、共有SQL領域に格納されたすべての文の実行計画が含まれます。その定義は、PLAN_TABLEに類似しています。「PLAN_TABLE列」を参照してください。

V$SQL_PLANがEXPLAIN PLANよりも優れている点は、特定の文の実行に使用されたコンパイル環境を知らなくてもかまわないということです。EXPLAIN PLANの場合は、文の実行時に同じ計画を取得するために同一環境をセットアップする必要があります。

V$SQL_PLAN_STATISTICSビューは、出力行数や経過時間など、計画に含まれる操作ごとに実際の実行統計を提供します。出力行数を除き、すべての統計は累積されます。たとえば、結合操作の統計には、2つの入力の統計も含まれます。V$SQL_PLAN_STATISTICSの統計は、STATISTICS_LEVEL初期化パラメータをALLに設定してコンパイルされたカーソルに使用できます。

V$SQL_PLAN_STATISTICS_ALLビューを使用すると、行数と経過時間に関してオプティマイザにより提供される見積りを並べて表示できます。このビューでは、各カーソルのV$SQL_PLANおよびV$SQL_PLAN_STATISTICS情報が結合されます。

関連項目:

- V$SQL_PLAN_MONITORビューについては、「データベース操作の監視」を参照してください

- V$SQL_PLANビューの詳細は、『Oracle Databaseリファレンス』を参照してください。

- STATISTICS_LEVEL初期化パラメータについては、『Oracle Databaseリファレンス』を参照してください

EXPLAIN PLANの制限事項

Oracle Databaseでは、日付バインド変数の暗黙的な型変換を実行する文でのEXPLAIN PLANをサポートしません。一般にバインド変数では、EXPLAIN PLANが実際の実行計画を表していない場合があります。

TKPROFは、SQL文のテキストからバインド変数の型を判断することはできません。型はCHARACTERであると想定され、これ以外の場合はエラー・メッセージが表示されます。この制限事項は、SQL文に適切な型変換を入れることで対処できます。

関連項目:

アプリケーション・トレースの実行

PLAN_TABLEの作成のガイドライン

PLAN_TABLEは、グローバル一時表に対するパブリック・シノニムとして自動的に作成されます。この一時表に、すべてのユーザーに対するEXPLAIN PLAN文の出力が保持されます。PLAN_TABLEは、EXPLAIN PLAN文が実行計画について記述している行を挿入するデフォルトのサンプル出力表です。表内の列の詳細は、「PLAN_TABLE列」を参照してください。

PLAN_TABLE表は各ユーザーに対し自動的に設定されますが、SQLスクリプトcatplan.sqlを使用して、グローバル一時表とPLAN_TABLEシノニムを手動で作成できます。このスクリプトの名前と位置は、使用するオペレーティング・システムによって異なります。UNIXおよびLinux上では、このスクリプトは$ORACLE_HOME/rdbms/adminディレクトリにあります。

たとえば、SQL*Plusセッションを開始し、SYSDBA権限で接続し、そして次のようにスクリプトを実行します。

@$ORACLE_HOME/rdbms/admin/catplan.sql

データベースのバージョンを更新した場合は、列が変更される可能性があるため、ローカルのPLAN_TABLE表を削除して再作成することをお薦めします。表を指定する場合は、スクリプトの実行が失敗したり、TKPROFが失敗する場合があります。

名前PLAN_TABLEを使用しない場合は、catplan.sqlスクリプトの実行後に新しいシノニムを作成します。次に例を示します。

CREATE OR REPLACE PUBLIC SYNONYM my_plan_table for plan_table$

実行計画の生成

EXPLAIN PLAN文により、オプティマイザがSQL文に対して選択した実行計画を確認できます。文が発行されると、オプティマイザが実行計画を選択した後で、計画を説明するデータがデータベース表に挿入されます。EXPLAIN PLAN文を発行してから、出力表を問い合せてください。

1つの文に対するEXPLAIN PLANの実行

EXPLAIN PLAN文の基本的な使用方法は次のとおりです。

- SQLスクリプトCATPLAN.SQLを使用し、使用しているスキーマ内にPLAN_TABLEというサンプル出力表を作成します。「PLAN_TABLEの作成のガイドライン」を参照してください。

- SQL文の前に、EXPLAIN PLAN FOR句を含めます。

- EXPLAIN PLAN文を発行した後、Oracle Databaseから提供されるスクリプトまたはパッケージを使用して最新のPLAN TABLE出力を表示します。「PLAN_TABLE出力の表示」を参照してください。

- EXPLAIN PLANの出力実行順序は、最も右端にインデントされている行から始まります。次のステップは、その行の親です。2つの行が等しくインデントされている場合、通常、一番上の行が最初に実行されます。

注意:

- この章のEXPLAIN PLAN出力表は、utlxpls.sqlスクリプトで表示したものです。

- この章のEXPLAIN PLAN出力のステップは、システムによって異なる場合があります。データベース構成によって、オプティマイザは異なる実行計画を選択する場合があります。

SQL文をEXPLAINする場合は、文の直前でEXPLAIN PLAN FOR句を使用します。次に例を示します。

EXPLAIN PLAN FOR
SELECT last_name FROM employees;

計画をEXPLAINしたものがPLAN_TABLE表に挿入されます。PLAN_TABLEから実行計画を選択できるようになります。「PLAN_TABLE出力の表示」を参照してください。

文IDを使用したEXPLAIN PLANの実行

複数の文があるときは、文の識別子を指定し、その識別子で特定の実行計画を識別できます。SET STATEMENT IDを使用する前に、その文と同じ識別子を持つ既存の行を削除してください。

例6-2の場合は、st1が文の識別子として指定されています。

例6-2 STATEMENT ID句でのEXPLAIN PLANの使用方法

EXPLAIN PLAN
SET STATEMENT_ID = 'st1' FOR
SELECT last_name FROM employees;

デフォルト以外の表へのEXPLAIN PLAN出力の指示

次の文のように、INTO句を指定して異なる表を指定できます。

EXPLAIN PLAN
INTO my_plan_table FOR
SELECT last_name FROM employees;

次の文のように、INTO句を使用する場合は、文のIDを指定できます。

EXPLAIN PLAN
SET STATEMENT_ID = 'st1'
INTO my_plan_table FOR
SELECT last_name FROM employees;

関連項目:

EXPLAIN PLAN構文の詳細は、Oracle Database SQL言語リファレンスを参照してください。

PLAN_TABLE出力の表示

計画をEXPLAINした後、Oracle Databaseから提供される次のSQLスクリプトまたはPL/SQLパッケージを使用して最新のPLAN TABLE出力を表示します。

- UTLXPLS.SQL
このスクリプトは、シリアル処理のためのPLAN TABLE出力を表示します。例6-4は、UTLXPLS.SQLスクリプトを使用した場合のPLAN TABLE出力の例です。

- UTLXPLP.SQL
このスクリプトは、パラレル実行列を含むPLAN TABLE出力を表示します。

- DBMS_XPLAN.DISPLAYテーブル・ファンクション
このファンクションは、PLAN TABLE出力を表示するオプションを受け入れます。指定できるのは次のとおりです。

- PLAN_TABLEとは別の表を使用している場合のPLAN TABLE名

- EXPLAIN PLANに文の識別子を設定した場合の文の識別子

- 詳細レベルを決定するフォーマット・オプション: BASIC、SERIAL、TYPICALおよびALL

DBMS_XPLANを使用してPLAN_TABLE出力を表示する例を次に示します。

SELECT PLAN_TABLE_OUTPUT FROM TABLE(DBMS_XPLAN.DISPLAY());

SELECT PLAN_TABLE_OUTPUT
FROM TABLE(DBMS_XPLAN.DISPLAY('MY_PLAN_TABLE', 'st1','TYPICAL'));

関連項目:

DBMS_XPLANパッケージの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

実行計画の表示: 例

例6-3では、EXPLAIN PLANを使用して、IDが103より小さい従業員のemployee_id、job_title、salaryおよびdepartment_nameを選択するSQL文を確認します。

例6-3 EXPLAIN PLANの使用方法

EXPLAIN PLAN FOR
SELECT e.employee_id, j.job_title, e.salary, d.department_name
FROM   employees e, jobs j, departments d
WHERE  e.employee_id < 103
AND    e.job_id = j.job_id
AND    e.department_id = d.department_id;

例6-4 EXPLAIN PLAN出力

次の出力表では、例6-3にあるSQL文を実行するためにオプティマイザで選択する実行計画が示されています。

-----------------------------------------------------------------------------------
| Id  | Operation                     |  Name        | Rows  | Bytes | Cost (%CPU)|
-----------------------------------------------------------------------------------
|   0 | SELECT STATEMENT              |              |     3 |   189 |    10  (10)|
|   1 |  NESTED LOOPS                 |              |     3 |   189 |    10  (10)|
|   2 |   NESTED LOOPS                |              |     3 |   141 |     7  (15)|
|*  3 |    TABLE ACCESS FULL          | EMPLOYEES    |     3 |    60 |     4  (25)|
|   4 |    TABLE ACCESS BY INDEX ROWID| JOBS         |    19 |   513 |     2  (50)|
|*  5 |     INDEX UNIQUE SCAN         | JOB_ID_PK    |     1 |       |            |
|   6 |   TABLE ACCESS BY INDEX ROWID | DEPARTMENTS  |    27 |   432 |     2  (50)|
|*  7 |    INDEX UNIQUE SCAN          | DEPT_ID_PK   |     1 |       |            |
-----------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------
3 - filter("E"."EMPLOYEE_ID"<103)
5 - access("E"."JOB_ID"="J"."JOB_ID")
7 - access("E"."DEPARTMENT_ID"="D"."DEPARTMENT_ID"

------------------------------------------------------------------------------------------------
| Id | Operation                       | Name          | Rows  | Bytes | Cost (%CPU)| Time     |
------------------------------------------------------------------------------------------------
|  0 | SELECT STATEMENT                |               |     3 |   189 |     8  (13)| 00:00:01 |
|  1 |  NESTED LOOPS                   |               |       |       |            |          |
|  2 |   NESTED LOOPS                  |               |     3 |   189 |     8  (13)| 00:00:01 |
|  3 |    MERGE JOIN                   |               |     3 |   141 |     5  (20)| 00:00:01 |
|  4 |     TABLE ACCESS BY INDEX ROWID | JOBS          |    19 |   513 |     2   (0)| 00:00:01 |
|  5 |      INDEX FULL SCAN            | JOB_ID_PK     |    19 |       |     1   (0)| 00:00:01 |
|* 6 |     SORT JOIN                   |               |     3 |    60 |     3  (34)| 00:00:01 |
|  7 |      TABLE ACCESS BY INDEX ROWID| EMPLOYEES     |     3 |    60 |     2   (0)| 00:00:01 |
|* 8 |       INDEX RANGE SCAN          | EMP_EMP_ID_PK |     3 |       |     1   (0)| 00:00:01 |
|* 9 |    INDEX UNIQUE SCAN            | DEPT_ID_PK    |     1 |       |     0   (0)| 00:00:01 |
| 10 |   TABLE ACCESS BY INDEX ROWID   | DEPARTMENTS   |     1 |    16 |     1   (0)| 00:00:01 |
------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

6 - access("E"."JOB_ID"="J"."JOB_ID")
filter("E"."JOB_ID"="J"."JOB_ID")
8 - access("E"."EMPLOYEE_ID"<103)
9 - access("E"."DEPARTMENT_ID"="D"."DEPARTMENT_ID")

PLAN_TABLE出力のカスタマイズ

文の識別子を指定した場合は、PLAN_TABLEを問い合せるための独自のスクリプトを書くことができます。次に例を示します。

- START WITH ID = 0およびSTATEMENT_IDを指定します。

- CONNECT BY句を使用して親から子へツリーを移動します。結合キーは、STATEMENT_ID = PRIOR STATEMENT_IDおよびPARENT_ID = PRIOR IDです。

- 疑似列LEVEL(CONNECT BYに関連付けられている)を使用して子をインデントします。

SELECT cardinality "Rows",
lpad(' ',level-1)||operation||' '||options||' '||object_name "Plan"
FROM PLAN_TABLE
CONNECT BY prior id = parent_id
AND prior statement_id = statement_id
START WITH id = 0
AND statement_id = 'st1'
ORDER BY id;

Rows Plan
------- ----------------------------------------
SELECT STATEMENT
TABLE ACCESS FULL EMPLOYEES

Rows列のNULLは、オプティマイザが表に統計を持っていないことを示します。表をANALYZEすると、次の内容が表示されます。

Rows Plan
------- ----------------------------------------
16957 SELECT STATEMENT
16957  TABLE ACCESS FULL EMPLOYEES

COSTも選択できます。これは、実行計画を比較する場合や、オプティマイザが複数の中からある実行計画を選択した理由を理解する場合に便利です。

注意:

これらの単純な例は、再帰的SQLの場合には有効ではありません。

7 実行計画の読取り

この章の内容は次のとおりです。

- 実行計画の読取り: 基本

- 実行計画の読取り: 拡張

- 実行計画のリファレンス

実行計画の読取り: 基本

この項では、EXPLAIN PLANの例を使用して実行計画を説明します。次の問合せで実行計画が表示されます。

SELECT PLAN_TABLE_OUTPUT
FROM TABLE(DBMS_XPLAN.DISPLAY(NULL, 'statement_id','BASIC'));

この文の出力例を、例7-4および例7-1に示します。

例7-1 文ID ex_plan1のEXPLAIN PLAN

次の計画は、SELECT文の実行を示します。表employeesは、全表スキャンでアクセスされます。表employeesのすべての行がアクセスされ、各行がWHERE句の条件に基づいて評価されます。

EXPLAIN PLAN
SET statement_id = 'ex_plan1' FOR
SELECT phone_number
FROM   employees
WHERE  phone_number LIKE '650%';

---------------------------------------
| Id  | Operation         | Name      |
---------------------------------------
|   0 | SELECT STATEMENT  |           |
|   1 |  TABLE ACCESS FULL| EMPLOYEES |
---------------------------------------

例7-2 文ID ex_plan2のEXPLAIN PLAN

この計画は、SELECT文の実行を示します。この例では、データベース・レンジは、EMP_NAME_IX索引をスキャンして、WHERE句の基準を評価します。

EXPLAIN PLAN
SET statement_id = 'ex_plan2' FOR
SELECT last_name
FROM   employees
WHERE  last_name LIKE 'Pe%';

SELECT PLAN_TABLE_OUTPUT
FROM TABLE(DBMS_XPLAN.DISPLAY(NULL, 'ex_plan2','BASIC'));

----------------------------------------
| Id  | Operation        | Name        |
----------------------------------------
|   0 | SELECT STATEMENT |             |
|   1 |  INDEX RANGE SCAN| EMP_NAME_IX |
----------------------------------------

実行計画の読取り: 拡張

この項の内容は次のとおりです。

- 適応問合せ計画の読取り

- EXPLAIN PLANによるパラレル実行の表示

- EXPLAIN PLANによるビットマップ索引の表示

- EXPLAIN PLANによる結果キャッシュの表示

- EXPLAIN PLANによるパーティション・オブジェクトの表示

- PLAN_TABLE列

適応問合せ計画の読取り

適応オプティマイザは、実行時の統計に基づいて計画を適応させることを可能にするオプティマイザの機能です。すべての適応メカニズムでは、デフォルトの計画とは異なる、文の最終計画を実行できます。

適応問合せ計画は、現在の文の実行中にサブプランの中から選択されます。対照的に、自動再最適化では、現在の文の実行後に行われる自動再最適化の実行時にのみ計画が変更されます。

計画のNotesセクションのコメントに基づいて、データベースでSQL文の適応問合せ最適化が使用されたかどうかを判断できます。コメントには、行ソースが動的かどうか、または自動再最適化が計画に適用されたかどうかが示されます。

前提条件

このチュートリアルでは、次のことが前提となっています。

- STATISTICS_LEVEL初期化パラメータがALLに設定されています。

- データベースでは、適応実行にデフォルト設定が使用されています。

- ユーザーoeとして、次の別々の問合せを発行します。

SELECT o.order_id, v.product_name
FROM   orders o,
(  SELECT order_id, product_name
FROM   order_items o, product_information p
WHERE  p.product_id = o.product_id
AND    list_price < 50
AND    min_price < 40  ) v
WHERE  o.order_id = v.order_id

SELECT product_name
FROM   order_items o, product_information p
WHERE  o.unit_price = 15
AND    quantity > 1
AND    p.product_id = o.product_id

- 各問合せを実行する前に、DBMS_XPLAN.DISPLAY_PLANを問い合せてデフォルトの計画(つまり、適応メカニズムを適用する前にオプティマイザによって選択される計画)を確認します。

- 各問合せの実行後、DBMS_XPLAN.DISPLAY_CURSORを問い合せて最終計画と適応問合せ計画を確認します。

- SYSにより、oeに次の権限が付与されています。

- GRANT SELECT ON V_$SESSION TO oe

- GRANT SELECT ON V_$SQL TO oe

- GRANT SELECT ON V_$SQL_PLAN TO oe

- GRANT SELECT ON V_$SQL_PLAN_STATISTICS_ALL TO oe

適応最適化の結果を確認する手順は次のとおりです。

1. SQL*Plusを起動し、データベースにユーザーoeとして接続します。

2. ordersを問い合せます。

たとえば、次の文を使用します。

SELECT o.order_id, v.product_name
FROM   orders o,
(  SELECT order_id, product_name
FROM   order_items o, product_information p
WHERE  p.product_id = o.product_id
AND    list_price < 50
AND    min_price < 40  ) v
WHERE  o.order_id = v.order_id;

3. カーソル内に計画を表示します。

たとえば、次のコマンドを実行します。

SET LINESIZE 165
SET PAGESIZE 0
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(FORMAT=>'+ALLSTATS'));

次のサンプル出力はページに収まるようにあらかじめ折り返されています。この計画では、オプティマイザは、ネステッド・ループ結合を選択します。元のオプティマイザの見積りは、E-Rows列に示されています。一方、実行中に収集された実際の統計は、A-Rows列に示されています。MERGE JOIN操作では、見積られた行数と実際の行数の差異は大きなものになります。

--------------------------------------------------------------------------------------------
|Id| Operation             | Name          |Start|E-Rows|A-Rows|A-Time|Buff|OMem|1Mem|O/1/M|
--------------------------------------------------------------------------------------------
| 0| SELECT STATEMENT      |                |   1|   | 269|00:00:00.09|1338|    |    |     |
| 1|  NESTED LOOPS         |                |   1|  1| 269|00:00:00.09|1338|    |    |     |
| 2|   MERGE JOIN CARTESIAN|                |   1|  4|9135|00:00:00.03|  33|    |    |     |
|*3|    TABLE ACCESS FULL  |PRODUCT_INFORMAT|   1|  1|  87|00:00:00.01|  32|    |    |     |
| 4|    BUFFER SORT        |                |  87|105|9135|00:00:00.01|   1|4096|4096|1/0/0|
| 5|     INDEX FULL SCAN   | ORDER_PK       |   1|105| 105|00:00:00.01|   1|    |    |     |
|*6|   INDEX UNIQUE SCAN   | ORDER_ITEMS_UK |9135|  1| 269|00:00:00.03|1305|    |    |     |
--------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

3 - filter(("MIN_PRICE"<40 AND "LIST_PRICE"<50))
6 - access("O"."ORDER_ID"="ORDER_ID" AND "P"."PRODUCT_ID"="O"."PRODUCT_ID")

4. 手順2で実行したものと同じordersの問合せを実行します。

5. 手順3で実行したものと同じSELECT文を使用して、カーソル内に実行計画を表示します。
次の例は、オプティマイザがハッシュ結合を使用する別の計画を選択したことを示しています。Noteセクションには、オプティマイザが統計フィードバックを使用して、問合せの2回目の実行に対するコストの見積りを調整したことが示されています。これは自動再最適化のよい例です。

--------------------------------------------------------------------------------------------
|Id| Operation              |Name    |Start|E-Rows|A-Rows|A-Time|Buff|Reads|OMem|1Mem|O/1/M|
--------------------------------------------------------------------------------------------
| 0| SELECT STATEMENT       |               | 1 |   |269|00:00:00.02|60|1|     |     |     |
| 1|  NESTED LOOPS          |               | 1 |269|269|00:00:00.02|60|1|     |     |     |
|*2|   HASH JOIN            |               | 1 |313|269|00:00:00.02|39|1|1000K|1000K|1/0/0|
|*3|    TABLE ACCESS FULL   |PRODUCT_INFORMA| 1 | 87| 87|00:00:00.01|15|0|     |     |     |
| 4|    INDEX FAST FULL SCAN|ORDER_ITEMS_UK | 1 |665|665|00:00:00.01|24|1|     |     |     |
|*5|   INDEX UNIQUE SCAN    |ORDER_PK       |269|  1|269|00:00:00.01|21|0|     |     |     |
--------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

2 - access("P"."PRODUCT_ID"="O"."PRODUCT_ID")
3 - filter(("MIN_PRICE"<40 AND "LIST_PRICE"<50))
5 - access("O"."ORDER_ID"="ORDER_ID")

Note
-----
- statistics feedback used for this statement

6. V$SQLを問い合せて、パフォーマンスが改善されていることを確認します。
次の問合せは、2つの文のパフォーマンスを示しています(出力例も示します)。

SELECT CHILD_NUMBER, CPU_TIME, ELAPSED_TIME, BUFFER_GETS
FROM   V$SQL
WHERE  SQL_ID = 'gm2npz344xqn8';

CHILD_NUMBER   CPU_TIME ELAPSED_TIME BUFFER_GETS
------------ ---------- ------------ -----------
0      92006       131485        1831
1      12000        24156          60

実行された2つ目の文(子番号1)では、統計フィードバックが使用されました。CPU時間、経過時間およびバッファ取得はいずれも、大幅に低下しています。

7. order_itemsの問合せに対する計画をEXPLAINします。
たとえば、次の文を使用します。

EXPLAIN PLAN FOR
SELECT product_name
FROM   order_items o, product_information p
WHERE  o.unit_price = 15
AND    quantity > 1
AND    p.product_id = o.product_id

8. PLAN TABLE内に計画を表示します。
たとえば、次の文を実行します。

SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);

出力例は次のように表示されます。

-------------------------------------------------------------------------------
|Id| Operation                 | Name             |Rows|Bytes|Cost (%CPU)|Time|
-------------------------------------------------------------------------------
| 0| SELECT STATEMENT             |                      |4|128|7 (0)|00:00:01|
| 1|  NESTED LOOPS                |                      | |   |     |        |
| 2|   NESTED LOOPS               |                      |4|128|7 (0)|00:00:01|
|*3|    TABLE ACCESS FULL         |ORDER_ITEMS           |4|48 |3 (0)|00:00:01|
|*4|    INDEX UNIQUE SCAN         |PRODUCT_INFORMATION_PK|1|   |0 (0)|00:00:01|
| 5|   TABLE ACCESS BY INDEX ROWID|PRODUCT_INFORMATION   |1|20 |1 (0)|00:00:01|
-------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

3 - filter("O"."UNIT_PRICE"=15 AND "QUANTITY">1)
4 - access("P"."PRODUCT_ID"="O"."PRODUCT_ID")

この計画では、オプティマイザは、ネステッド・ループ結合を選択します。

9. 以前にEXPLAINした問合せを実行します。
たとえば、次の文を使用します。

SELECT product_name
FROM   order_items o, product_information p
WHERE  o.unit_price = 15
AND    quantity > 1
AND    p.product_id = o.product_id

10. カーソル内に計画を表示します。
たとえば、次のコマンドを実行します。

SET LINESIZE 165
SET PAGESIZE 0
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY(FORMAT=>'+ADAPTIVE'));

出力例は次のように表示されます。実行時(手順4)に収集された統計に基づいて、オプティマイザは、ネステッド・ループ結合ではなく、ハッシュ結合を選択します。ダッシュ(-)は、オプティマイザによって考慮されたが最終的に選択されなかった、ネステッド・ループ計画における手順を表します。スイッチは、適応問合せ計画機能を示しています。

-------------------------------------------------------------------------------
|Id | Operation                     | Name     |Rows|Bytes|Cost(%CPU)|Time    |
-------------------------------------------------------------------------------
|  0| SELECT STATEMENT              |                     |4|128|7(0)|00:00:01|
| *1|  HASH JOIN                    |                     |4|128|7(0)|00:00:01|
|- 2|   NESTED LOOPS                |                     | |   |    |        |
|- 3|    NESTED LOOPS               |                     | |128|7(0)|00:00:01|
|- 4|     STATISTICS COLLECTOR      |                     | |   |    |        |
| *5|      TABLE ACCESS FULL        | ORDER_ITEMS         |4| 48|3(0)|00:00:01|
|-*6|     INDEX UNIQUE SCAN         | PRODUCT_INFORMATI_PK|1|   |0(0)|00:00:01|
|- 7|    TABLE ACCESS BY INDEX ROWID| PRODUCT_INFORMATION |1| 20|1(0)|00:00:01|
|  8|   TABLE ACCESS FULL           | PRODUCT_INFORMATION |1| 20|1(0)|00:00:01|
-------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------
1 - access("P"."PRODUCT_ID"="O"."PRODUCT_ID")
5 - filter("O"."UNIT_PRICE"=15 AND "QUANTITY">1)
6 - access("P"."PRODUCT_ID"="O"."PRODUCT_ID")

Note
-----
- this is an adaptive plan (rows marked '-' are inactive)

関連項目:

- 「適応問合せ計画」

- 表7-8

- 「適応最適化の制御」

- STATISTICS_LEVEL初期化パラメータの詳細は、『Oracle Databaseリファレンス』を参照してください。

- DBMS_XPLANの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

EXPLAIN PLANによるパラレル実行の表示

パラレル問合せの計画は、シリアル問合せの計画とは重要な点で異なります。

EXPLAIN PLANおよびパラレル問合せについて

パラレル問合せのチューニングは、パラレルでない問合せのチューニングの場合と同様に駆動表を選択することにより、開始されます。ただし、選択を管理するルールは異なります。

シリアルの場合は、制限条件を適用した後に最も少ない行が生成される駆動表が最適です。データベースは、一意でない索引を使用して少数の行を大きな表に結合します。

たとえば、customer、accountおよびtransactionで構成された表階層の場合について考えます。

図7-1 表階層

この例では、customerが最も小さな表で、transactionが最も大きな表です。通常のOLTP問合せでは、特定の顧客のアカウントに関する取引情報を取得します。問合せはcustomer表から駆動されます。目標は論理I/Oを最少化することで、これにより、通常、物理I/OやCPUタイムを含むその他の重要なリソースも最少化されます。

パラレル問合せの場合は、通常では最も大きな表が駆動表になります。この場合はパラレル問合せを使用するのは効率的ではありません。各表からアクセスされる行がごくわずかであるためです。ここで、前月に特定のタイプの取引を持つすべての顧客を識別する必要が生じた場合を考えてみます。customer表には制限条件がないため、問合せはtransaction表から行うほうが効率的です。データベースは、transaction表から取り出した行をaccount表に結合し、最終的には結果セットをcustomer表に結合します。この場合、accountおよびcustomer表で使用される索引は、通常、最初の問合せで使用される一意でない索引ではなく、選択性の高い主キーまたは一意の索引になります。transaction表は大きく、列に選択性がないため、transaction表から駆動されるパラレル問合せを使用したほうが有効です。

パラレル操作には次のものがあります。

- PARALLEL_TO_PARALLEL

- PARALLEL_TO_SERIAL
PARALLEL_TO_SERIAL操作は、パラレル操作からの行が問合せコーディネータによって使用される場合、常に発生するステップです。この問合せでは発生しない他の種類の操作には、SERIAL操作があります。このような操作が発生した場合は、これらもボトルネックになる可能性があるため、パフォーマンスの改善のためにパラレル操作を検討します。

- PARALLEL_FROM_SERIAL

- PARALLEL_TO_PARALLEL
各ステップのワークロードがほぼ同じである場合、通常は、PARALLEL_TO_PARALLEL操作によって最適なパフォーマンスが得られます。

- PARALLEL_COMBINED_WITH_CHILD

- PARALLEL_COMBINED_WITH_PARENT
PARALLEL_COMBINED_WITH_PARENT操作は、ステップを親ステップと同時に実行する場合に発生します。

パラレル・ステップで多数の行が生成される場合、行の生成される速さにQCの処理が追いつかない場合があります。この状況を改善する方法はほとんどありません。

関連項目:

「PLAN_TABLE列」のOTHER_TAG列

EXPLAIN PLANによるパラレル問合せの表示: 例

EXPLAIN PLANをパラレル問合せとともに使用すると、データベースは1つのパラレル計画をコンパイルおよび実行します。この計画は、QC計画にパラレル・サポートに固有の行ソースを割り当てることで、シリアル計画から導出されます。

2つのパラレル実行サーバー・セットPQモデルで要求される、表キューの行ソース(PX SendおよびPX Receive)、グラニュル・イテレータおよびバッファ・ソートは、パラレル計画に直接挿入されます。この計画は、パラレルで実行された場合はすべてのパラレル実行サーバーで、またシリアルで実行された場合はすべてのQCで、同じ計画となります。

例7-3 パラレル問合せのEXPLAIN PLAN

次の単純な例は、パラレル問合せのEXPLAIN PLANを示しています。

CREATE TABLE emp2 AS SELECT * FROM employees;

ALTER TABLE emp2 PARALLEL 2;

EXPLAIN PLAN FOR
SELECT SUM(salary)
FROM   emp2
GROUP BY department_id;

SELECT PLAN_TABLE_OUTPUT FROM TABLE(DBMS_XPLAN.DISPLAY());

------------------------------------------------------------------------------------------------
| Id  | Operation              | Name     | Rows| Bytes |Cost %CPU|    TQ  |IN-OUT| PQ Distrib |
------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT         |          | 107 |  2782 |  3 (34) |        |      |            |
| 1 |  PX COORDINATOR          |          |     |       |         |        |      |            |
| 2 |   PX SEND QC (RANDOM)    | :TQ10001 | 107 |  2782 |  3 (34) |  Q1,01 | P->S | QC (RAND)  |
| 3 |    HASH GROUP BY         |          | 107 |  2782 |  3 (34) |  Q1,01 | PCWP |            |
| 4 |     PX RECEIVE           |          | 107 |  2782 |  3 (34) |  Q1,01 | PCWP |            |
| 5 |      PX SEND HASH        | :TQ10000 | 107 |  2782 |  3 (34) |  Q1,00 | P->P | HASH       |
| 6 |       HASH GROUP BY      |          | 107 |  2782 |  3 (34) |  Q1,00 | PCWP |            |
| 7 |        PX BLOCK ITERATOR |          | 107 |  2782 |  2 (0)  |  Q1,00 | PCWP |            |
| 8 |         TABLE ACCESS FULL| EMP2     | 107 |  2782 |  2 (0)  |  Q1,00 | PCWP |            |
------------------------------------------------------------------------------------------------

パラレル実行サーバーの1つのセットがパラレルにEMP2をスキャンし、2つ目のセットは、GROUP BY操作に対する集計を実行します。PX BLOCK ITERATOR行ソースは、EMP2表が複数のピースに分割されて、スキャンのワークロードがパラレル実行サーバー間で分けられることを表します。PX SENDおよびPX RECEIVE行ソースは、2つのパラレル実行サーバー・セットをパラレル・スキャンからの行フローとして接続するパイプを表し、HASH表キューを介して再びパーティション化されてから、上位スレーブ・セットにより読み取られて集計されます。PX SEND QC行ソースは、QCにランダム(RAND)な順序で送信される集計値を表します。PX COORDINATOR行ソースは、計画ツリーで下に表示されるパラレル計画を制御しスケジュールするQC(問合せコーディネータ)を表します。

EXPLAIN PLANによるビットマップ索引の表示

ビットマップ索引を使用する索引行ソースは、索引のタイプを示す語BITMAPとともにEXPLAIN PLAN出力に表示されます。

注意:

ビットマップ結合索引を使用した問合せは、ビットマップ結合索引のアクセス・パスを指示します。ビットマップ結合索引の操作は、ビットマップ索引と同じです。

例7-4 ビットマップ検索によるEXPLAIN PLAN

この例では、述語c1=2によってビットマップが生成され、そこから減算が行われます。このビットマップから、c2 = 6に対応するビットマップ内のビットが減算されます。同様に、c2 IS NULLに対応するビットマップ内のビットが減算され、この計画の中に2つのMINUS行ソースがある理由がわかります。NULL減算は、NOT NULL制約が列に設定されていないかぎり、意味上の正確さを保つために必要です。TO ROWIDSオプションは、表アクセスに必要な行IDを生成します。

EXPLAIN PLAN FOR  SELECT *
FROM   t
WHERE  c1 = 2
AND    c2 <> 6
OR     c3 BETWEEN 10 AND 20;

SELECT STATEMENT
TABLE ACCESS T BY INDEX ROWID
BITMAP CONVERSION TO ROWID
BITMAP OR
BITMAP MINUS
BITMAP MINUS
BITMAP INDEX C1_IND SINGLE VALUE
BITMAP INDEX C2_IND SINGLE VALUE
BITMAP INDEX C2_IND SINGLE VALUE
BITMAP MERGE
BITMAP INDEX C3_IND RANGE SCAN

EXPLAIN PLANによる結果キャッシュの表示

問合せにresult_cacheヒントが含まれる場合、ResultCache演算子が実行計画に挿入されます。

たとえば、次の問合せを考えてみます。

SELECT /*+ result_cache */ deptno, avg(sal)
FROM   emp
GROUP BY deptno;

次のコマンドを使用して、この問合せに対するEXPLAIN PLANを表示できます。

EXPLAIN PLAN FOR
SELECT /*+ result_cache */ deptno, avg(sal)
FROM emp
GROUP BY deptno;

SELECT PLAN_TABLE_OUTPUT FROM TABLE (DBMS_XPLAN.DISPLAY());

この問合せのEXPLAIN PLAN出力は、次のようになります。

--------------------------------------------------------------------------------
|Id| Operation          | Name                     |Rows|Bytes|Cost(%CPU)|Time |
--------------------------------------------------------------------------------
|0| SELECT STATEMENT    |                          | 11 | 77 | 4 (25)| 00:00:01|
|1|  RESULT CACHE       |b06ppfz9pxzstbttpbqyqnfbmy|    |    |       |         |
|2|   HASH GROUP BY     |                          | 11 | 77 | 4 (25)| 00:00:01|
|3|    TABLE ACCESS FULL| EMP                      |107 | 749| 3 (0) | 00:00:01|
--------------------------------------------------------------------------------

このEXPLAIN PLANでは、ResultCache演算子はそのCacheId(b06ppfz9pxzstbttpbqyqnfbmy)によって識別されます。このCacheIdを使用して、V$RESULT_CACHE_OBJECTSビューに対して問合せを実行できます。

EXPLAIN PLANによるパーティション・オブジェクトの表示

EXPLAIN PLANを使用して、特定の問合せのパーティション化オブジェクトへのOracle Databaseのアクセス方法を表示します。

プルーニング後にアクセスされたパーティションは、PARTITION START列とPARTITION STOP列に表示されます。レンジ・パーティションの行ソース名は、PARTITION RANGEです。ハッシュ・パーティションの場合、行ソース名はPARTITION HASHです。

結合されるいずれかの表のPLAN TABLEのDISTRIBUTION列にPARTITION(KEY)が存在する場合、結合はパーシャル・パーティション・ワイズ結合を使用して実装されます。パーシャル・パーティション・ワイズ結合が可能なのは、結合される表のいずれかが結合列でパーティション化されており、かつ、表がパラレル化されている場合です。

EXPLAIN PLAN出力の結合行ソースの前にパーティション行ソースがある場合、結合はフル・パーティション・ワイズ結合を使用して実装されます。フル・パーティション・ワイズ結合が可能なのは、両方の結合表がそれぞれの結合列でパーティション化されている場合のみです。次に、いくつかの種類のパーティションに対する実行計画の例を示します。

EXPLAIN PLANによるレンジ・パーティション化およびハッシュ・パーティション化の表示: 例

hire_dateで範囲ごとにパーティション化されている次のemp_range表を参考に、プルーニングの表示方法を例示します。Oracle Databaseサンプル・スキーマの表employeesおよびdepartmentsが存在することを想定しています。

CREATE TABLE emp_range
PARTITION BY RANGE(hire_date)
(
PARTITION emp_p1 VALUES LESS THAN (TO_DATE('1-JAN-1992','DD-MON-YYYY')),
PARTITION emp_p2 VALUES LESS THAN (TO_DATE('1-JAN-1994','DD-MON-YYYY')),
PARTITION emp_p3 VALUES LESS THAN (TO_DATE('1-JAN-1996','DD-MON-YYYY')),
PARTITION emp_p4 VALUES LESS THAN (TO_DATE('1-JAN-1998','DD-MON-YYYY')),
PARTITION emp_p5 VALUES LESS THAN (TO_DATE('1-JAN-2001','DD-MON-YYYY'))
)
AS SELECT * FROM employees;

最初の例では、次の文を検討します。

EXPLAIN PLAN FOR
SELECT * FROM emp_range;

次のような結果が表示されます。

--------------------------------------------------------------------
|Id| Operation           | Name      |Rows| Bytes|Cost|Pstart|Pstop|
--------------------------------------------------------------------
| 0| SELECT STATEMENT    |           |  105| 13965 | 2 |   |       |
| 1|  PARTITION RANGE ALL|           |  105| 13965 | 2 | 1 |     5 |
| 2|   TABLE ACCESS FULL | EMP_RANGE |  105| 13965 | 2 | 1 |     5 |
--------------------------------------------------------------------

データベースでは、表アクセス行ソースに加えて、パーティション行ソースが作成されます。これが、アクセスされるパーティションのセットに対して繰り返されます。この例では、述語がプルーニングに使用されていないので、パーティション・イテレータはすべてのパーティション(ALLオプション)を対象とします。PLAN_TABLEのPARTITION_START列とPARTITION_STOP列は、1から5のすべてのパーティションへのアクセスを示します。

次の例では、次の文を検討します。

EXPLAIN PLAN FOR
SELECT *
FROM   emp_range
WHERE  hire_date >= TO_DATE('1-JAN-1996','DD-MON-YYYY');

-----------------------------------------------------------------------
| Id | Operation                | Name   |Rows|Bytes|Cost|Pstart|Pstop|
-----------------------------------------------------------------------
|  0 | SELECT STATEMENT         |         | 3 | 399 |   2 |     |     |
|  1 |  PARTITION RANGE ITERATOR|         | 3 | 399 |   2 |   4 |   5 |
| *2 |   TABLE ACCESS FULL      |EMP_RANGE| 3 | 399 |   2 |   4 |   5 |
-----------------------------------------------------------------------

前の例では、hire_dateの述語を使用してその他のパーティションをプルーニングするため、パーティション行ソースはパーティション4から5を反復します。

最後に、次の文を検討します。

EXPLAIN PLAN FOR
SELECT *
FROM   emp_range
WHERE  hire_date < TO_DATE('1-JAN-1992','DD-MON-YYYY');

-----------------------------------------------------------------------
| Id  | Operation            | Name      |Rows|Bytes|Cost|Pstart|Pstop|
-----------------------------------------------------------------------
|   0 | SELECT STATEMENT       |           |    1 |   133 | 2 |   |   |
|   1 |  PARTITION RANGE SINGLE|           |    1 |   133 | 2 | 1 | 1 |
|*  2 |   TABLE ACCESS FULL    | EMP_RANGE |    1 |   133 | 2 | 1 | 1 |
-----------------------------------------------------------------------

この例では、パーティション1のみがアクセスされ、それがコンパイル時に認識されます。したがって、パーティション行ソースは必要ありません。

注意:

ハッシュ・パーティション・オブジェクトでは、パーティション行ソース名がPARTITION RANGEではなくPARTITION HASHであることを除き、同じ情報が表示されます。また、ハッシュ・パーティション化では、プルーニングが可能なのは等価述語かINリスト述語を使用している場合のみです。

コンポジット・パーティション・オブジェクトでのプルーニング情報: 例

Oracle Databaseでコンポジット・パーティション・オブジェクトのプルーニング情報を表示する方法を示すには、表emp_compを検討してください。この表は雇用日のレンジでパーティション化され、部門番号のハッシュでサプパーティション化されています。

CREATE TABLE emp_comp PARTITION BY RANGE(hire_date)
SUBPARTITION BY HASH(department_id) SUBPARTITIONS 3
(
PARTITION emp_p1 VALUES LESS THAN (TO_DATE('1-JAN-1992','DD-MON-YYYY')),
PARTITION emp_p2 VALUES LESS THAN (TO_DATE('1-JAN-1994','DD-MON-YYYY')),
PARTITION emp_p3 VALUES LESS THAN (TO_DATE('1-JAN-1996','DD-MON-YYYY')),
PARTITION emp_p4 VALUES LESS THAN (TO_DATE('1-JAN-1998','DD-MON-YYYY')),
PARTITION emp_p5 VALUES LESS THAN (TO_DATE('1-JAN-2001','DD-MON-YYYY'))
)
AS SELECT * FROM employees;

最初の例では、次の文を検討します。

EXPLAIN PLAN FOR
SELECT * FROM emp_comp;

-----------------------------------------------------------------------
|Id| Operation           | Name     | Rows  | Bytes |Cost|Pstart|Pstop|
-----------------------------------------------------------------------
| 0| SELECT STATEMENT    |          | 10120 |  1314K| 78 |    |       |
| 1|  PARTITION RANGE ALL|          | 10120 |  1314K| 78 |  1 |     5 |
| 2|   PARTITION HASH ALL|          | 10120 |  1314K| 78 |  1 |     3 |
| 3|    TABLE ACCESS FULL| EMP_COMP | 10120 |  1314K| 78 |  1 |    15 |
-----------------------------------------------------------------------

この例では、Oracle Databaseがコンポジット・オブジェクトの全パーティションの全サブパーティションにアクセスする場合の計画を示します。この目的を達成するために、2つのパーティション行ソースを使用します。1つはパーティションを反復するレンジ・パーティション行ソースで、もう1つはアクセスされる各パーティションのサブパーティションを反復するハッシュ・パーティション行ソースです。

次の例では、プルーニングを実行しないため、レンジ・パーティション行ソースはパーティション1から5を反復します。各パーティション内では、ハッシュ・パーティション行ソースは現在のパーティションのサブパーティション1から3を反復します。その結果、表アクセス行ソースがサブパーティション1から15にアクセスします。つまり、データベースはコンポジット・オブジェクトのすべてのサブパーティションにアクセスします。

EXPLAIN PLAN FOR
SELECT *
FROM   emp_comp
WHERE  hire_date = TO_DATE('15-FEB-1998', 'DD-MON-YYYY');

-----------------------------------------------------------------------
| Id | Operation              | Name    |Rows|Bytes |Cost|Pstart|Pstop|
-----------------------------------------------------------------------
|  0 | SELECT STATEMENT       |          | 20 | 2660 | 17 |     |     |
|  1 |  PARTITION RANGE SINGLE|          | 20 | 2660 | 17 |   5 |   5 |
|  2 |   PARTITION HASH ALL   |          | 20 | 2660 | 17 |   1 |   3 |
|* 3 |    TABLE ACCESS FULL   | EMP_COMP | 20 | 2660 | 17 |  13 |  15 |
-----------------------------------------------------------------------

この例では、最後のパーティション5のみがアクセスされます。このパーティションはコンパイル時に認識されるので、計画では表示する必要がありません。ハッシュ・パーティション行ソースは、そのパーティション内のすべてのサブパーティションのアクセスを表示します。つまり、サブパーティション1から3が表示されることになりますが、これはemp_comp表のサブパーティション13から15に変換されます。

次の文を考えてみます。

EXPLAIN PLAN FOR
SELECT *
FROM   emp_comp
WHERE  department_id = 20;

------------------------------------------------------------------------
| Id | Operation              |Name    |Rows | Bytes |Cost|Pstart|Pstop|
------------------------------------------------------------------------
|  0 | SELECT STATEMENT       |          | 101 | 13433 | 78 |    |     |
|  1 |  PARTITION RANGE ALL   |          | 101 | 13433 | 78 |  1 |   5 |
|  2 |   PARTITION HASH SINGLE|          | 101 | 13433 | 78 |  3 |   3 |
|* 3 |    TABLE ACCESS FULL   | EMP_COMP | 101 | 13433 | 78 |    |     |
------------------------------------------------------------------------

前の例では、述語deptno=20により各パーティション内のハッシュ・ディメンションでのプルーニングが可能になります。したがって、Oracle Databaseでは単一のサブパーティションのアクセスのみが必要です。このサブパーティションの番号はコンパイル時に認識されるので、ハッシュ・パーティション行ソースは必要ありません。

最後に、次の文を検討します。

VARIABLE dno NUMBER;
EXPLAIN PLAN FOR
SELECT *
FROM   emp_comp
WHERE  department_id = :dno;

-----------------------------------------------------------------------
| Id| Operation              | Name    |Rows| Bytes |Cost|Pstart|Pstop|
-----------------------------------------------------------------------
| 0 | SELECT STATEMENT       |          | 101| 13433 | 78 |     |     |
| 1 |  PARTITION RANGE ALL   |          | 101| 13433 | 78 |   1 |   5 |
| 2 |   PARTITION HASH SINGLE|          | 101| 13433 | 78 | KEY | KEY |
|*3 |    TABLE ACCESS FULL   | EMP_COMP | 101| 13433 | 78 |     |     |
-----------------------------------------------------------------------

最後の2つの例は、deptno=20がdepartment_id = :dnoに置き換えられたこと以外は同じです。この最後の場合、サブパーティションの番号はコンパイル時には不明であり、ハッシュ・パーティション行ソースが割り当てられます。Oracle Databaseでは、各パーティション内の1つのサブパーティションにのみアクセスするため、この行ソースのオプションはSINGLEです。手順2では、PARTITION_STARTおよびPARTITION_STOPの両方がKEYに設定されます。この値は、Oracle Databaseでは実行時にサブパーティションの数が決まることを意味します。

パーシャル・パーティション・ワイズ結合の例

例7-5および例7-6では、問合せオプティマイザがこの問合せのコストに基づいて異なる計画を選択する可能性があるため、PQ_DISTRIBUTEヒントにより、パーシャル・パーティション・ワイズ結合が明示的に強制されています。

例7-5 レンジ・パーティション化を使用したパーシャル・パーティション・ワイズ結合

次の例では、emp_range_didがパーティション化列department_idで結合され、パラレル化されます。dept2表がパーティション化されていないことにより、データベースでは、パーシャル・パーティション・ワイズ結合が使用可能になります。Oracle Databaseでは、結合前にdept2表を動的にパーティション化します。

CREATE TABLE dept2 AS SELECT * FROM departments;
ALTER TABLE dept2 PARALLEL 2;

CREATE TABLE emp_range_did PARTITION BY RANGE(department_id)
(PARTITION emp_p1 VALUES LESS THAN (150),
PARTITION emp_p5 VALUES LESS THAN (MAXVALUE) )
AS SELECT * FROM employees;

ALTER TABLE emp_range_did PARALLEL 2;

EXPLAIN PLAN FOR
SELECT /*+ PQ_DISTRIBUTE(d NONE PARTITION) ORDERED */ e.last_name,
d.department_name
FROM   emp_range_did e, dept2 d
WHERE  e.department_id = d.department_id;

------------------------------------------------------------------------------------------------
|Id| Operation                    |Name        |Row|Byte|Cost|Pstart|Pstop|TQ|IN-OUT|PQ Distrib|
------------------------------------------------------------------------------------------------
| 0| SELECT STATEMENT             |             |284 |16188|6 |   |   |       |     |          |
| 1|  PX COORDINATOR              |             |    |     |  |   |   |       |     |          |
| 2|   PX SEND QC (RANDOM)        |:TQ10001     |284 |16188|6 |   |   | Q1,01 |P->S |QC (RAND) |
|*3|    HASH JOIN                 |             |284 |16188|6 |   |   | Q1,01 |PCWP |          |
| 4|     PX PARTITION RANGE ALL   |             |284 |7668 |2 | 1 | 2 | Q1,01 |PCWC |          |
| 5|      TABLE ACCESS FULL       |EMP_RANGE_DID|284 |7668 |2 | 1 | 2 | Q1,01 |PCWP |          |
| 6|     BUFFER SORT              |             |    |     |  |   |   | Q1,01 |PCWC |          |
| 7|      PX RECEIVE              |             | 21 | 630 |2 |   |   | Q1,01 |PCWP |          |
| 8|       PX SEND PARTITION (KEY)|:TQ10000     | 21 | 630 |2 |   |   |       |S->P |PART (KEY)|
| 9|        TABLE ACCESS FULL     |DEPT2        | 21 | 630 |2 |   |   |       |     |          |
------------------------------------------------------------------------------------------------

この実行計画は、dept2表がシリアルにスキャンされ、emp_range_didの同じパーティション化列値(department_id)を持つすべての行が、パーティション・キーを示すPART (KEY)、表キューを介して、パーシャル・パーティション・ワイズ結合を実行する同じパラレル実行サーバーに送られることを示します。

例7-6 コンポジット・パーティション化を使用したパーシャル・パーティション・ワイズ結合

次の例では、emp_compがパーティション化列で結合され、パラレル化されます。dept2表がパーティション化されていないことにより、パーシャル・パーティション・ワイズ結合が使用可能になります。データベースでは、結合前にdept2を動的にパーティション化します。

ALTER TABLE emp_comp PARALLEL 2;

EXPLAIN PLAN FOR
SELECT /*+ PQ_DISTRIBUTE(d NONE PARTITION) ORDERED */ e.last_name,
d.department_name
FROM   emp_comp e, dept2 d
WHERE  e.department_id = d.department_id;

SELECT PLAN_TABLE_OUTPUT FROM TABLE(DBMS_XPLAN.DISPLAY());

------------------------------------------------------------------------------------------------
| Id| Operation                   | Name  |Rows |Bytes |Cost|Pstart|Pstop|TQ |IN-OUT|PQ Distrib|
------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT            |        | 445 | 17800 | 5 |   |   |       |      |          |
| 1 |  PX COORDINATOR             |        |     |       |   |   |   |       |      |          |
| 2 |   PX SEND QC (RANDOM)       |:TQ10001| 445 | 17800 | 5 |   |   | Q1,01 | P->S | QC (RAND)|
|*3 |    HASH JOIN                |        | 445 | 17800 | 5 |   |   | Q1,01 | PCWP |          |
| 4 |     PX PARTITION RANGE ALL  |        | 107 |  1070 | 3 | 1 | 5 | Q1,01 | PCWC |          |
| 5 |      PX PARTITION HASH ALL  |        | 107 |  1070 | 3 | 1 | 3 | Q1,01 | PCWC |          |
| 6 |       TABLE ACCESS FULL     |EMP_COMP| 107 |  1070 | 3 | 1 | 15| Q1,01 | PCWP |          |
| 7 |     PX RECEIVE              |        |  21 |   630 | 1 |   |   | Q1,01 | PCWP |          |
| 8 |      PX SEND PARTITION (KEY)|:TQ10000|  21 |   630 | 1 |   |   | Q1,00 | P->P |PART (KEY)|
| 9 |       PX BLOCK ITERATOR     |        |  21 |   630 | 1 |   |   | Q1,00 | PCWC |          |
|10 |        TABLE ACCESS FULL    |DEPT2   |  21 |   630 | 1 |   |   | Q1,00 | PCWP |          |
------------------------------------------------------------------------------------------------

この計画は、オプティマイザが2つの列の一方からパーシャル・パーティション・ワイズ結合を選択することを示します。PX SENDのノード・タイプはPARTITION(KEY)で、PQ Distrib列にはパーティション・キーを示すテキストPART (KEY)が含まれています。これは、EMP_COMPのスキャンと結合を実行するパラレル実行サーバーに送られる結合列department_idに基づいて、dept2表が再びパーティション化されることを意味します。

フル・パーティション・ワイズ結合の例

次の例では、emp_compとdept_hashがハッシュ・パーティション化列で結合され、フル・パーティション・ワイズ結合を使用できるようになります。PARTITION HASH行ソースが、PLAN TABLE出力の結合行ソースの上に表示されます。

CREATE TABLE dept_hash
PARTITION BY HASH(department_id)
PARTITIONS 3
PARALLEL 2
AS SELECT * FROM departments;

EXPLAIN PLAN FOR
SELECT /*+ PQ_DISTRIBUTE(e NONE NONE) ORDERED */ e.last_name,
d.department_name
FROM   emp_comp e, dept_hash d
WHERE  e.department_id = d.department_id;

------------------------------------------------------------------------------------------------
|Id| Operation                  | Name      |Rows|Bytes|Cost|Pstart|Pstop|TQ |IN-OUT|PQ Distrib|
------------------------------------------------------------------------------------------------
| 0| SELECT STATEMENT           |           | 106 | 2544 | 8 |   |    |       |      |         |
| 1|  PX COORDINATOR            |           |     |      |   |   |    |       |      |         |
| 2|   PX SEND QC (RANDOM)      | :TQ10000  | 106 | 2544 | 8 |   |    | Q1,00 | P->S |QC (RAND)|
| 3|    PX PARTITION HASH ALL   |           | 106 | 2544 | 8 | 1 |  3 | Q1,00 | PCWC |         |
|*4|     HASH JOIN              |           | 106 | 2544 | 8 |   |    | Q1,00 | PCWP |         |
| 5|      PX PARTITION RANGE ALL|           | 107 | 1070 | 3 | 1 |  5 | Q1,00 | PCWC |         |
| 6|       TABLE ACCESS FULL    | EMP_COMP  | 107 | 1070 | 3 | 1 | 15 | Q1,00 | PCWP |         |
| 7|      TABLE ACCESS FULL     | DEPT_HASH |  27 |  378 | 4 | 1 |  3 | Q1,00 | PCWP |         |
------------------------------------------------------------------------------------------------

PX PARTITION HASH行ソースはPLAN TABLE出力で結合行ソースの上に表示されますが、PX PARTITION RANGE行ソースはemp_compのスキャンにまたがって表示されます。各パラレル実行サーバーは、emp_compのハッシュ・パーティション全体とdept_hashのパーティション全体の結合を実行します。

INLIST ITERATORおよびEXPLAIN PLANの例

INLIST ITERATOR操作は、索引がINリスト述語を実装する場合に、EXPLAIN PLAN出力に表示されます。次に例を示します。

SELECT * FROM emp WHERE empno IN (7876, 7900, 7902);

EXPLAIN PLAN出力は次のようになります。

OPERATION          OPTIONS           OBJECT_NAME
----------------   ---------------   --------------
SELECT STATEMENT
INLIST ITERATOR
TABLE ACCESS       BY ROWID          EMP
INDEX              RANGE SCAN        EMP_EMPNO

INLIST ITERATOR操作は、INリスト述語内の各値に対して、計画内の次の操作を反復します。次の各項では、パーティション表およびパーティション索引で使用可能な3種類のINリスト列について説明します。

INリスト列が索引列である場合: 例

INリスト列empnoが索引列で、パーティション列ではない場合、計画は次のようになります(INリスト演算子は表操作の前に表示されますが、パーティションの操作よりは後に表示されます)。

OPERATION        OPTIONS              OBJECT_NAME PARTIT_START PARTITION_STOP
---------------- ------------         ----------- ------------ --------------
SELECT STATEMENT
PARTITION RANGE  ALL                               KEY(INLIST)     KEY(INLIST)
INLIST ITERATOR
TABLE ACCESS     BY LOCAL INDEX ROWID EMP          KEY(INLIST)     KEY(INLIST)
INDEX            RANGE SCAN           EMP_EMPNO    KEY(INLIST)     KEY(INLIST)

パーティションの開始キーおよび終了キーに対するKEY(INLIST)指定は、索引の開始キーおよび終了キーにINリスト述語が表示されることを指定します。

INリスト列が索引でありパーティション列である場合: 例

empnoが索引付けされている列で、それがパーティション列でもある場合、計画にはパーティション操作の前にINLIST ITERATOR操作が含まれています。

OPERATION        OPTIONS              OBJECT_NAME PARTITION_START PARTITION_STOP
---------------- ------------         ----------- --------------- --------------
SELECT STATEMENT
INLIST ITERATOR
PARTITION RANGE  ITERATOR                         KEY(INLIST)     KEY(INLIST)
TABLE ACCESS     BY LOCAL INDEX ROWID EMP         KEY(INLIST)     KEY(INLIST)
INDEX            RANGE SCAN           EMP_EMPNO   KEY(INLIST)     KEY(INLIST)

INリスト列がパーティション列である場合: 例

empnoがパーティション列で、索引が存在しない場合は、INLIST ITERATOR操作は割り当てられません。

OPERATION         OPTIONS        OBJECT_NAME   PARTITION_START   PARTITION_STOP
----------------  ------------   -----------   ---------------   --------------
SELECT STATEMENT
PARTITION RANGE   INLIST                       KEY(INLIST)       KEY(INLIST)
TABLE ACCESS      FULL           EMP           KEY(INLIST)       KEY(INLIST)

emp_empnoがビットマップ索引である場合、計画は次のとおりです。

OPERATION          OPTIONS           OBJECT_NAME
----------------   ---------------   --------------
SELECT STATEMENT
INLIST ITERATOR
TABLE ACCESS       BY INDEX ROWID    EMP
BITMAP CONVERSION  TO ROWIDS
BITMAP INDEX       SINGLE VALUE      EMP_EMPNO

ドメイン索引およびEXPLAIN PLANの例

また、EXPLAIN PLANを使用して、ドメイン索引に対するユーザー定義のCPUおよびI/Oコストを導出できます。EXPLAIN PLANは、これらの統計をPLAN_TABLEのOTHER列に表示します。

たとえば、resume列にドメイン索引emp_resumeを持つユーザー定義演算子CONTAINSが表empに存在し、emp_resumeの索引タイプが演算子CONTAINSをサポートしている場合に、次の問合せをします。次の問合せの計画をEXPLAINします。

SELECT * FROM emp WHERE CONTAINS(resume, 'Oracle') = 1

次のような計画が表示されます。

OPERATION            OPTIONS      OBJECT_NAME     OTHER
-----------------    -----------  ------------    ----------------
SELECT STATEMENT
TABLE ACCESS         BY ROWID     EMP
DOMAIN INDEX                      EMP_RESUME      CPU: 300, I/O: 4

PLAN_TABLE列

EXPLAIN PLAN文で使用されるPLAN_TABLEには、このトピックで示される列が含まれています。

表7-1 PLAN_TABLE列

列

データ型

説明

STATEMENT_ID

VARCHAR2(30)

EXPLAIN PLAN文で指定した、オプションのSTATEMENT_IDパラメータの値です。

PLAN_ID

NUMBER

データベース内の計画の一意の識別子です。

TIMESTAMP

DATE

EXPLAIN PLAN文が生成された日時です。

REMARKS

VARCHAR2(80)

実行計画の各ステップに関連付けるコメント(最大80バイト)です。この列は、問合せに使用されたのがアウトラインであるか、SQLプロファイルかを示します。

PLAN_TABLEの行に注釈を追加または変更する必要がある場合は、UPDATE文を使用してPLAN_TABLE文の行を変更する。

OPERATION

VARCHAR2(30)

このステップで実行された内部操作の名前です。文に対して生成された最初の行では、その列に次のいずれかの値が含まれる。

- DELETE STATEMENT

- INSERT STATEMENT

- SELECT STATEMENT

- UPDATE STATEMENT

この列の値の詳細は、表7-3を参照してください。

OPTIONS

VARCHAR2(225)

OPERATION列に記述されている操作に関するバリエーションです。

この列の値の詳細は、表7-3を参照してください。

OBJECT_NODE

VARCHAR2(128)

オブジェクト(表名またはビュー名)を参照するために使用されたデータベース・リンクの名前です。パラレル実行を指定したローカル問合せの場合、この列は、処理からの出力をデータベースが使用する順序を説明します。

OBJECT_OWNER

VARCHAR2(30)

表または索引を含むスキーマを所有しているユーザーの名前です。

OBJECT_NAME

VARCHAR2(30)

表または索引の名前です。

OBJECT_ALIAS

VARCHAR2(65)

SQL文に含まれる表またはビューの一意の別名。索引の場合は、基礎となる表のオブジェクトの別名。

OBJECT_INSTANCE

NUMERIC

元の文に指定されているオブジェクトの位置に対応する順番を示す数値です。番号付けは、元の文テキストの左から右へ、外側から内側へと行われます。ビューを展開した場合、この数値は予測できない。

OBJECT_TYPE

VARCHAR2(30)

たとえば、索引に対するNON-UNIQUEのような、オブジェクトに関して説明を与える修飾子です。

OPTIMIZER

VARCHAR2(255)

オプティマイザの現行モードです。

SEARCH_COLUMNS

NUMBERIC

現在は使用されていません。

ID

NUMERIC

実行計画の各ステップに割り当てられた番号です。

PARENT_ID

NUMERIC

IDのステップの出力について処理を行う次の実行ステップのIDです。

DEPTH

NUMERIC

計画が示す行ソース・ツリー内の操作の深さ。この値を使用して、PLAN TABLEレポートの行をインデントできます。

POSITION

NUMERIC

最初の出力行の場合、この列はオプティマイザが見積った、文を実行するためのコストを示します。その他の行の場合は、同じ親の他の子に対応する相対位置を示す。

COST

NUMERIC

オプティマイザの問合せアプローチによって見積られた操作コストです。表アクセス操作のコストは判断されない。この列の値には、特定の単位はなく、実行計画のコストを比較するために使用される重み値を示します。この列の値は、CPU_COST列およびIO_COST列の関数である。

CARDINALITY

NUMERIC

この操作がアクセスした行数の問合せ最適化アプローチによる見積りです。

BYTES

NUMERIC

この操作がアクセスしたバイト数の問合せ最適化アプローチによる見積りです。

OTHER_TAG

VARCHAR2(255)

OTHER列の内容を記述します。値は次のとおりです。

- SERIAL(空白): シリアル実行。この場合、SQLはOTHER列に現在ロードされていない。

- SERIAL_FROM_REMOTE (S -> R): リモート・サイトでシリアル実行されます。

- PARALLEL_FROM_SERIAL (S -> P): シリアル実行。手順の出力は、パーティション化されるか、パラレル実行サーバーにブロードキャストされる。

- PARALLEL_TO_SERIAL (P -> S): パラレル実行。ステップの出力は、シリアルQCプロセスに戻されます。

- PARALLEL_TO_PARALLEL (P -> P): パラレル実行。手順の出力は、パラレル実行サーバーの2番目のセットに再パーティション化される。

- PARALLEL_COMBINED_WITH_PARENT (PWP): パラレル実行。ステップの出力は、同じパラレル処理の次のステップに送られます。親へのプロセス間通信はなし。

- PARALLEL_COMBINED_WITH_CHILD (PWC): パラレル実行。手順の入力は、同じパラレル処理の前の手順から受け取る。子からのプロセス間通信はなし。

PARTITION_START

VARCHAR2(255)

アクセスしたパーティションの範囲のパーティションを開始します。次のいずれかの値を指定できます。

nは、開始パーティションがSQLコンパイラで識別され、そのパーティション番号がnで示されることを意味します。

KEYは、開始パーティションが実行時にパーティション・キー値から識別されることを示します。

ROW REMOVE_LOCATIONは、実行時に、取得された各レコードの位置から開始パーティション(終了パーティションと同じ)が計算されることを示します。レコードの位置は、ユーザーまたはグローバル索引によって取得される。

INVALIDは、アクセスしたパーティションの範囲が空であることを意味します。

PARTITION_STOP

VARCHAR2(255)

アクセスされるパーティションの範囲の停止パーティション。次のいずれかの値を指定できます。

nは、終了パーティションがSQLコンパイラで識別され、そのパーティション番号がnで示されることを意味します。

KEYは、終了パーティションが実行時にパーティション・キー値から識別されることを示します。

ROW REMOVE_LOCATIONは、実行時に、取得された各レコードの位置から終了パーティション(開始パーティションと同じ)が計算されることを示します。レコードの位置は、ユーザーまたはグローバル索引によって取得される。

INVALIDは、アクセスしたパーティションの範囲が空であることを意味します。

PARTITION_ID

NUMERIC

PARTITION_STARTとPARTITION_STOP列の値の対を計算したステップです。

OTHER

LONG

ユーザーにとって有効な実行ステップに関するその他の情報です。OTHER_TAG列を参照してください。

DISTRIBUTION

VARCHAR2(30)

プロデューサ問合せサーバーからコンシューマ問合せサーバーへ行を分配する方法です。

この列に使用可能な値の詳細は、表7-2を参照してください。コンシューマ問合せサーバーおよびプロデューサ問合せサーバーの詳細は、Oracle Database VLDBおよびパーティショニング・ガイドを参照してください。

CPU_COST

NUMERIC

問合せオプティマイザの方法で見積もった操作のCPUコスト。この列の値は、操作に必要なマシン・サイクル数に比例する。ルールベースのアプローチを使用する文の場合、この列はNULLです。

IO_COST

NUMERIC

問合せオプティマイザの方法で見積もった操作のI/Oコスト。この列の値は、操作で読み込まれるデータ・ブロック数に比例する。ルールベースのアプローチを使用する文の場合、この列はNULLです。

TEMP_SPACE

NUMERIC

問合せオプティマイザのアプローチで見積られた、操作で使用される一時領域をバイト単位で表したものです。ルールベース・アプローチを使用する文の場合、または一時領域を使用しない操作の場合、この列はNULLです。

ACCESS_PREDICATES

VARCHAR2(4000)

アクセス構造内の行の検索に使用する述語。たとえば、開始述語または停止述語は索引レンジ・スキャンに使用。

FILTER_PREDICATES

VARCHAR2(4000)

フィルタにかけた後で行を生成する場合に使用する述語です。

PROJECTION

VARCHAR2(4000)

操作によって生成される式です。

TIME

NUMBER(20,2)

問合せの最適化によって見積られた操作の秒単位の経過時間です。ルールベースのアプローチを使用する文の場合、この列はNULLです。DBMS_XPLAN.DISPLAY_PLANの出力で、時間はHH:MM:SSフォーマットで表示されます。

QBLOCK_NAME

VARCHAR2(30)

問合せブロックの名前です。システム生成またはQB_NAMEヒントによるユーザー定義のいずれかとなります。

表7-2では、DISTRIBUTION列に使用される値を説明します。

表7-2 PLAN_TABLEのDISTRIBUTION列の値

DISTRIBUTIONテキスト

説明

PARTITION (ROWID)

UPDATEまたはDELETEを実行する行のROWIDを使用し、表または索引のパーティション化に基づいて行を問合せサーバーにマップします。

PARTITION (KEY)

列のセットを使用し、表または索引のパーティション化に基づいて行を問合せサーバーにマップします。パーシャル・パーティション・ワイズ結合、PARALLEL INSERT、パーティション表のCREATE TABLE AS SELECTおよびCREATE PARTITIONED GLOBAL INDEXに使用します。

HASH

結合キーについて、ハッシュ関数を使用して、行を問合せサーバーにマップします。PARALLEL JOINまたはPARALLEL GROUP BYに使用します。

RANGE

ソート・キーの範囲を使用して、行を問合せサーバーにマップします。文にORDER BY句がある場合に使用します。

ROUND-ROBIN

行を問合せサーバーにランダムにマップします。

BROADCAST

表全体の行を各問合せサーバーにブロードキャストします。ある表がその他の表に比べて非常に小さい場合、パラレル結合に使用します。

QC (ORDER)

QCは、最初の問合せサーバーから最後の問合せサーバーまで順番に入力データを受け取ります。文にORDER BY句がある場合に使用します。

QC (RANDOM)

QCは、入力をランダムに受け取ります。文にORDER BY句がない場合に使用します。

表7-3に、EXPLAIN PLAN文によって生成されるOPERATIONとOPTIONSの各組合せおよびその実行計画におけるそれぞれの意味を示します。

表7-3 EXPLAIN PLANによって生成されるOPERATION値とOPTIONS値

操作

オプション

説明

AND-EQUAL

複数のROWIDのセットを受け取り、重複をなくして、そのセットの共通部分を戻す処理。この処理は単一列索引のアクセス・パスに対して使用されます。

BITMAP

CONVERSION

TO ROWIDSは、ビットマップ表現を、表にアクセスするために使用できる実際のROWIDに変換します。

FROM ROWIDSは、ROWIDをビットマップ表現に変換します。

COUNTは、実際の値を必要としない場合にROWIDの数を戻します。

BITMAP

INDEX

SINGLE VALUEは、索引内の単一のキー値のビットマップを参照します。

RANGE SCANは、ある範囲のキー値のビットマップを取り出します。

FULL SCANは、開始キーまたは終了キーがない場合にビットマップ索引の全体スキャンを実行します。

BITMAP

MERGE

レンジ・スキャンの結果の複数のビットマップを1つのビットマップにマージします。

BITMAP

MINUS

片方のビットマップのビットを、もう一方のビットマップから減算します。行ソースは否定述語に対して使用されます。このオプションは、減算が発生する可能性があるビットマップを作成する非否定述語がある場合にのみ使用します。「EXPLAIN PLANによるビットマップ索引の表示」で例を示します。

BITMAP

OR

2つのビットマップのビット単位のORを計算します。

BITMAP

AND

2つのビットマップのビット単位のANDを計算します。

BITMAP

KEY ITERATION

表の行ソースから各行を取り出し、ビットマップ索引から対応するビットマップを検索します。その後、このビットマップのセットは、次のBITMAP MERGE操作で1つのビットマップにマージされます。

CONNECT BY

CONNECT BY句を含んでいる問合せについて階層順に行を取り出します。

CONCATENATION

複数の行のセットを受け取り、そのセットのUNION-ALLを戻す処理。

COUNT

表から選択された行の数をカウントする処理。

COUNT

STOPKEY

戻される行数をWHERE句のROWNUM式によって制限するカウント処理。

CUBE SCAN

すべてのキューブ・アクセスで内部結合を使用します。

CUBE SCAN

PARTIAL OUTER

少なくとも1つのディメンションで外部結合を使用し、その他のディメンションで内部結合を使用します。

CUBE SCAN

OUTER

すべてのキューブ・アクセスで外部結合を使用します。

DOMAIN INDEX

ドメイン索引からの1つ以上のROWIDの取出し。オプション列には、ユーザー定義ドメイン・インデックス・コスト関数から与えられた情報が含まれています。

FILTER

行のセットを受け取り、そのいくつかを取り除き、残りを戻す処理。

FIRST ROW

問合せで選択される最初の行のみの取出し。

FOR UPDATE

FOR UPDATE句が含まれている問合せによって選択される行を取り出し、ロックする処理。

HASH

GROUP BY

GROUP BY句を持つ問合せで、行のセットを複数のグループにハッシュする処理。

HASH

GROUP BY PIVOT

GROUP BY句を持つ問合せで、行のセットを複数のグループにハッシュする処理。PIVOT操作は、HASH GROUP BY演算子のピボット固有の最適化を示します。

HASH JOIN

(これらは結合操作です。)

2つのセットの行を結合し、結果を戻す操作。この結合方法は、データのラージ・データ・セット(DSSやバッチなど)の結合に役立ちます。この結合条件は、第2の表にアクセスする場合に有効です。

問合せオプティマイザは、2つの表またはデータ・ソースの小さいほうを使用して、メモリー内に結合キーについてのハッシュ表を作成します。次に、大きいほうの表をスキャンし、ハッシュ表を調べて結合された行を見つけます。

HASH JOIN

ANTI

ハッシュ(左側)アンチ結合。

HASH JOIN

SEMI

ハッシュ(左側)セミ結合。

HASH JOIN

RIGHT ANTI

ハッシュ右側アンチ結合。

HASH JOIN

RIGHT SEMI

ハッシュ右側セミ結合。

HASH JOIN

OUTER

ハッシュ(左側)外部結合。

HASH JOIN

RIGHT OUTER

ハッシュ(右側)外部結合。

INDEX

(これらはアクセス方法です。)

UNIQUE SCAN

索引からの単一のROWIDの取出し。

INDEX

RANGE SCAN

索引からの1つ以上のROWIDの取出し。索引値は昇順でスキャンされます。

INDEX

RANGE SCAN DESCENDING

索引からの1つ以上のROWIDの取出し。索引値は降順でスキャンされます。

INDEX

FULL SCAN

スタート・キーおよびストップ・キーがない場合の、索引からのすべてのROWIDの取得。索引値は昇順でスキャンされます。

INDEX

FULL SCAN DESCENDING

スタート・キーおよびストップ・キーがない場合の、索引からのすべてのROWIDの取得。索引値は降順でスキャンされます。

INDEX

FAST FULL SCAN

マルチブロックREADを使用した全ROWID(および列の値)の取得。ソート順は定義できません。索引付けされた列に対してのみ、全表スキャンと比較されます。コストベース・オプティマイザでのみ使用可能です。

INDEX

SKIP SCAN

索引内の先頭列を使用しない、連結索引からのROWIDの取得。コストベース・オプティマイザでのみ使用可能です。

INLIST ITERATOR

INリスト述語内の各値に対して、計画内の次の操作を反復します。

INTERSECTION

2つの行のセットを受け取り、重複をなくして、そのセットの共通部分を戻す処理。

MERGE JOIN

(これらは結合操作です。)

2つの行のセットを受け取り、それぞれを特定の値でソートし、一方のセットの各行を他方の行と突き合せて結合し、その結果を戻す処理。

MERGE JOIN

OUTER

外部結合文を実行するマージ結合処理。

MERGE JOIN

ANTI

マージ・アンチ結合。

MERGE JOIN

SEMI

マージ・セミ結合。

MERGE JOIN

CARTESIAN

文中に他の表への結合条件を持たない1つ以上の表について発生する操作です。結合とともに発生する可能性がありますが、計画内ではCARTESIANとフラグが付かないことがあります。

CONNECT BY

CONNECT BY句を含んでいる問合せに対する、階層順での行の取出し。

MAT_VIEW REWITE ACCESS

(これらはアクセス方法です。)

FULL

マテリアライズド・ビューのすべての行の取出し。

MAT_VIEW REWITE ACCESS

SAMPLE

マテリアライズド・ビューのサンプル行の取出し。

MAT_VIEW REWITE ACCESS

CLUSTER

索引クラスタのキーの値に基づいた、マテリアライズド・ビューからの行の取出し。

MAT_VIEW REWITE ACCESS

HASH

ハッシュ・クラスタのキーの値に基づいた、マテリアライズド・ビューからの行の取出し。

MAT_VIEW REWITE ACCESS

BY ROWID RANGE

ROWID範囲に基づいたマテリアライズド・ビューからの行の取出し。

MAT_VIEW REWITE ACCESS

SAMPLE BY ROWID RANGE

ROWID範囲に基づいたマテリアライズド・ビューからのサンプル行の取出し。

MAT_VIEW REWITE ACCESS

BY USER ROWID

ユーザー指定のROWIDを使用してマテリアライズド・ビューの行が指定される場合。

MAT_VIEW REWITE ACCESS

BY INDEX ROWID

マテリアライズド・ビューがパーティション化されておらず、索引を使用して行が指定される場合。

MAT_VIEW REWITE ACCESS

BY GLOBAL INDEX ROWID

マテリアライズド・ビューがパーティション化されており、グローバル索引のみを使用して行が指定される場合。

MAT_VIEW REWITE ACCESS

BY LOCAL INDEX ROWID

マテリアライズド・ビューがパーティション化されており、1つ以上のローカル索引と、場合によってはいくつかのグローバル索引を使用して行が指定される場合。

パーティション区間:

パーティション区間は次のようにして計算されている可能性があります。

前のPARTITIONステップによって決定される場合。この場合、PARTITION_START列の値とPARTITION_STOP列の値はPARTITIONステップ内の値をレプリケートし、PARTITION_IDにはPARTITIONステップのIDが組み込まれます。PARTITION_STARTおよびPARTITION_STOPに使用できる値は、NUMBER(n)、KEY、INVALIDです。

MAT_VIEW REWRITE ACCESSまたはINDEXステップ自体で決定される場合。この場合、PARTITION_IDにはそのステップのIDが組み込まれます。PARTITION_STARTおよびPARTITION_STOPに使用できる値は、NUMBER(n)、KEY、ROW REMOVE_LOCATION(MAT_VIEW REWRITE ACCESSのみ)およびINVALIDです。

MINUS

2つの行のセットを受け取り、最初のセットにあって2番目のセットにない行を戻して、重複をなくす処理。

NESTED LOOPS

(これらは結合操作です。)

外側のセットと内側のセット、2つの行のセットを受け取る処理。Oracle Databaseは、外側のセットの各行を内側のセットの各行と比較し、条件を満たす行を戻します。この結合方法は、小さいサブセットのデータを結合する場合(OLTP)に役立ちます。この結合条件は、第2の表にアクセスする場合に有効です。

NESTED LOOPS

OUTER

外部結合文を実行するネステッド・ループ操作。

PARTITION

PARTITION_START列およびPARTITION_STOP列によって指定された範囲の各パーティションに対して、計画内の次の操作を反復します。PARTITIONは、単一のパーティション・オブジェクト(表または索引)や同一レベル・パーティション・オブジェクトのセット(パーティション表やそのローカル索引)に適用できるパーティションの区間を示します。パーティションの区間は、PARTITIONのPARTITION_STARTおよびPARTITION_STOPの値で指定されます。パーティションの開始および終了の有効な値は、表7-1を参照してください。

PARTITION

SINGLE

1つのパーティションへのアクセス。

PARTITION

ITERATOR

多数のパーティション(サブセット)へのアクセス。

PARTITION

ALL

すべてのパーティションへのアクセス。

PARTITION

INLIST

INリスト述語を基準にしたイテレータに類似するもの。

PARTITION

INVALID

アクセスするよう設定されているパーティションが空であることを示します。

PX ITERATOR

BLOCK、CHUNK

パラレル実行サーバー・セット間でのブロックまたはチャンク範囲へのオブジェクトの分割を実装します。

PX COORDINATOR

パラレル実行サーバーを使用して下位のパラレル計画を制御、スケジュールおよび実行する問合せコーディネータを実装します。また、パラレルに実行され、常に下位にPX SEND QC操作を持つ計画部分の終わりとして、シリアライズ・ポイントを表します。

PX PARTITION

セマンティクスは通常のPARTITION操作と同じですが、パラレル計画に表示されます。

PX RECEIVE

PX SENDノード上で実行される送信側/プロデューサ(QCまたはパラレル実行サーバー)から再パーティション化されたデータを読み取る、コンシューマ/受信側パラレル実行ノードを示します。以前は、この情報はDISTRIBUTION列に表示されていました。表7-2を参照してください。

PX SEND

QC (RANDOM)、HASH、RANGE

スレーブの2つのパラレル実行サーバーの間における配分方法を実装します。2つのセット間の境界と、送信側/プロデューサ側でのデータのパーティション化方法を示します。以前は、この情報はDISTRIBUTION列に表示されていました。表7-2を参照してください。

REMOTE

リモート・データベースからのデータの取出し。

SEQUENCE

順序値のアクセスを伴う処理。

SORT

AGGREGATE

選択した行のグループにグループ関数を適用した結果として取得される単一行の取出し。

SORT

UNIQUE

行のセットをソートし、重複をなくす処理。

SORT

GROUP BY

GROUP BY句を持つ問合せで、行のセットを複数のグループにソートする処理。

SORT

GROUP BY PIVOT

GROUP BY句を持つ問合せで、行のセットを複数のグループにソートする処理。PIVOT操作は、SORT GROUP BY演算子のピボット固有の最適化を示します。

SORT

JOIN

マージ結合の前に、一連の行をソートする操作。

SORT

ORDER BY

ORDER BY句を持つ問合せに対して行のセットをソートする処理。

TABLE ACCESS

(これらはアクセス方法です。)

FULL

表のすべての行の取出し。

TABLE ACCESS

SAMPLE

表のサンプル取得された行の取出し。

TABLE ACCESS

CLUSTER

索引クラスタのキーの値に基づいた、表からの行の取出し。

TABLE ACCESS

HASH

ハッシュ・クラスタのキーの値に基づいた、表からの行の取出し。

TABLE ACCESS

BY ROWID RANGE

ROWID範囲に基づいた表からの行の取出し。

TABLE ACCESS

SAMPLE BY ROWID RANGE

ROWID範囲に基づいた表からのサンプル行の取出し。

TABLE ACCESS

BY USER ROWID

ユーザー指定のROWIDを使用して表の行が指定される場合。

TABLE ACCESS

BY INDEX ROWID

表がパーティション化されておらず、索引を使用して行が指定される場合。

TABLE ACCESS

BY GLOBAL INDEX ROWID

表がパーティション化されており、グローバル索引のみを使用して行が指定される場合。

TABLE ACCESS

BY LOCAL INDEX ROWID

表がパーティション化されており、1つ以上のローカル索引と場合によってはいくつかのグローバル索引を使用して、行が指定される場合。

パーティション区間:

パーティション区間は次のようにして計算されている可能性があります。

前のPARTITIONステップによって決定される場合。この場合、PARTITION_START列の値とPARTITION_STOP列の値はPARTITIONステップ内の値をレプリケートし、PARTITION_IDにはPARTITIONステップのIDが組み込まれます。PARTITION_STARTおよびPARTITION_STOPに使用できる値は、NUMBER(n)、KEY、INVALIDです。

TABLE ACCESSまたはINDEXステップ自体で決定される場合。この場合、PARTITION_IDにはそのステップのIDが組み込まれます。PARTITION_STARTおよびPARTITION_STOPに使用できる値は、NUMBER(n)、KEY、ROW REMOVE_LOCATION(TABLE ACCESSのみ)およびINVALIDです。

TRANSPOSE

GROUP BYの結果を入れ換えて最終的にピボットされたデータを生成するPIVOT操作を評価する操作。

UNION

2つの行のセットを受け取り、重複をなくして、そのセットの連結結果を戻す処理。

UNPIVOT

列から行にデータを回転させる操作。

VIEW

ビューの問合せを実行し、結果の行を別の処理に戻す処理。

関連項目:

PLAN_TABLEの詳細は、Oracle Databaseリファレンスを参照してください。

実行計画のリファレンス

この項の内容は次のとおりです。

- 実行計画のビュー

- PLAN_TABLE列

- DBMS_XPLANプログラム・ユニット

実行計画のビュー

次の動的パフォーマンス・ビューおよびデータ・ディクショナリ・ビューでは、実行計画の情報が提供されます。

表7-4 実行計画のビュー

ビュー

説明

V$SQL_SHARED_CURSOR

特定の子カーソルが既存の子カーソルと共有されない理由を示します。それぞれの列は、カーソルが共有されない具体的な理由を示します。

USE_FEEDBACK_STATS列には、再最適化のために子カーソルが一致していないかどうかが示されます。

V$SQL_PLAN

すべての最終計画で使用されているすべての行のスーパーセットが含まれます。PLAN_LINE_IDには連番が振られますが、単一の最終計画では、IDが連番にならない場合もあります。

V$SQL_PLAN_STATISTICS_ALL

(ソートまたはハッシュ結合に)SQLメモリーを使用する行ソースのメモリー使用量統計が含まれます。このビューは、V$SQL_PLAN内の情報をV$SQL_PLAN_STATISTICSおよびV$SQL_WORKAREAからの実行統計と連結します。

PLAN_TABLE列

PLAN_TABLEはEXPLAIN PLAN文で使用されます。

PLAN_TABLEに含まれる列を表7-5に示します。

表7-5 PLAN_TABLE列

列

データ型

説明

STATEMENT_ID

VARCHAR2(30)

EXPLAIN PLAN文で指定した、オプションのSTATEMENT_IDパラメータの値です。

PLAN_ID

NUMBER

データベース内の計画の一意の識別子です。

TIMESTAMP

DATE

EXPLAIN PLAN文が生成された日時です。

REMARKS

VARCHAR2(80)

実行計画の各ステップに関連付けるコメント(最大80バイト)です。この列は、問合せに使用されたのがアウトラインであるか、SQLプロファイルかを示します。

PLAN_TABLEの行に注釈を追加または変更する必要がある場合は、UPDATE文を使用してPLAN_TABLE文の行を変更する。

OPERATION

VARCHAR2(30)

このステップで実行された内部操作の名前です。文に対して生成された最初の行では、その列に次のいずれかの値が含まれる。

- DELETE STATEMENT

- INSERT STATEMENT

- SELECT STATEMENT

- UPDATE STATEMENT

この列の値の詳細は、表7-6を参照してください。

OPTIONS

VARCHAR2(225)

OPERATION列に記述されている操作に関するバリエーションです。

この列の値の詳細は、表7-6を参照してください。

OBJECT_NODE

VARCHAR2(128)

オブジェクト(表名またはビュー名)を参照するために使用されたデータベース・リンクの名前です。パラレル実行を指定したローカル問合せの場合、この列は、処理からの出力をデータベースが使用する順序を説明します。

OBJECT_OWNER

VARCHAR2(30)

表または索引を含むスキーマを所有しているユーザーの名前です。

OBJECT_NAME

VARCHAR2(30)

表または索引の名前です。

OBJECT_ALIAS

VARCHAR2(65)

SQL文に含まれる表またはビューの一意の別名。索引の場合は、基礎となる表のオブジェクトの別名。

OBJECT_INSTANCE

NUMERIC

元の文に指定されているオブジェクトの位置に対応する順番を示す数値です。番号付けは、元の文テキストの左から右へ、外側から内側へと行われます。ビューを展開した場合、この数値は予測できない。

OBJECT_TYPE

VARCHAR2(30)

オブジェクトに関する情報を示す修飾子(索引に対するNONUNIQUEなど)

OPTIMIZER

VARCHAR2(255)

オプティマイザの現行モードです。

SEARCH_COLUMNS

NUMBERIC

現在は使用されていません。

ID

NUMERIC

実行計画の各ステップに割り当てられた番号です。

PARENT_ID

NUMERIC

IDのステップの出力について処理を行う次の実行ステップのIDです。

DEPTH

NUMERIC

計画が示す行ソース・ツリー内の操作の深さ。この値を使用して、PLAN TABLEレポートの行をインデントできます。

POSITION

NUMERIC

最初の出力行の場合、この列はオプティマイザが見積った、文を実行するためのコストを示します。その他の行の場合は、同じ親の他の子に対応する相対位置を示す。

COST

NUMERIC

オプティマイザの問合せアプローチによって見積られた操作コストです。表アクセス操作のコストは判断されない。この列の値には、特定の単位はなく、実行計画のコストを比較するために使用される重み値を示します。この列の値は、CPU_COST列およびIO_COST列の関数である。

CARDINALITY

NUMERIC

この操作がアクセスした行数の問合せ最適化アプローチによる見積りです。

BYTES

NUMERIC

この操作がアクセスしたバイト数の問合せ最適化アプローチによる見積りです。

OTHER_TAG

VARCHAR2(255)

OTHER列の内容を記述します。値は次のとおりです。

- SERIAL(空白): シリアル実行。この場合、SQLはOTHER列に現在ロードされていない。

- SERIAL_FROM_REMOTE (S -> R): リモート・サイトでシリアル実行されます。

- PARALLEL_FROM_SERIAL (S -> P): シリアル実行。手順の出力は、パーティション化されるか、パラレル実行サーバーにブロードキャストされる。

- PARALLEL_TO_SERIAL (P -> S): パラレル実行。ステップの出力は、シリアルQCプロセスに戻されます。

- PARALLEL_TO_PARALLEL (P -> P): パラレル実行。手順の出力は、パラレル実行サーバーの2番目のセットに再パーティション化される。

- PARALLEL_COMBINED_WITH_PARENT (PWP): パラレル実行。ステップの出力は、同じパラレル処理の次のステップに送られます。親へのプロセス間通信はなし。

- PARALLEL_COMBINED_WITH_CHILD (PWC): パラレル実行。手順の入力は、同じパラレル処理の前の手順から受け取る。子からのプロセス間通信はなし。

PARTITION_START

VARCHAR2(255)

アクセスしたパーティションの範囲のパーティションを開始します。次のいずれかの値を指定できます。

nは、開始パーティションがSQLコンパイラで識別され、そのパーティション番号がnで示されることを意味します。

KEYは、開始パーティションが実行時にパーティション・キー値から識別されることを示します。

ROW REMOVE_LOCATIONは、実行時に、取得された各レコードの位置から開始パーティション(終了パーティションと同じ)が計算されることを示します。レコードの位置は、ユーザーまたはグローバル索引によって取得される。

INVALIDは、アクセスしたパーティションの範囲が空であることを意味します。

PARTITION_STOP

VARCHAR2(255)

アクセスされるパーティションの範囲の停止パーティション。次のいずれかの値を指定できます。

nは、終了パーティションがSQLコンパイラで識別され、そのパーティション番号がnで示されることを意味します。

KEYは、終了パーティションが実行時にパーティション・キー値から識別されることを示します。

ROW REMOVE_LOCATIONは、実行時に、取得された各レコードの位置から終了パーティション(開始パーティションと同じ)が計算されることを示します。レコードの位置は、ユーザーまたはグローバル索引によって取得される。

INVALIDは、アクセスしたパーティションの範囲が空であることを意味します。

PARTITION_ID

NUMERIC

PARTITION_STARTとPARTITION_STOP列の値の対を計算したステップです。

OTHER

LONG

ユーザーにとって有効な実行ステップに関するその他の情報です。OTHER_TAG列を参照してください。

DISTRIBUTION

VARCHAR2(30)

プロデューサ問合せサーバーからコンシューマ問合せサーバーへ行を分配する方法です。

この列に使用可能な値の詳細は、表7-6を参照してください。コンシューマ問合せサーバーおよびプロデューサ問合せサーバーの詳細は、Oracle Database VLDBおよびパーティショニング・ガイドを参照してください。

CPU_COST

NUMERIC

問合せオプティマイザの方法で見積もった操作のCPUコスト。この列の値は、操作に必要なマシン・サイクル数に比例する。ルールベースのアプローチを使用する文の場合、この列はNULLです。

IO_COST

NUMERIC

問合せオプティマイザの方法で見積もった操作のI/Oコスト。この列の値は、操作で読み込まれるデータ・ブロック数に比例する。ルールベースのアプローチを使用する文の場合、この列はNULLです。

TEMP_SPACE

NUMERIC

問合せオプティマイザのアプローチで見積られた、操作で使用される一時領域をバイト単位で表したものです。ルールベース・アプローチを使用する文の場合、または一時領域を使用しない操作の場合、この列はNULLです。

ACCESS_PREDICATES

VARCHAR2(4000)

アクセス構造内の行の検索に使用する述語。たとえば、開始述語または停止述語は索引レンジ・スキャンに使用。

FILTER_PREDICATES

VARCHAR2(4000)

フィルタにかけた後で行を生成する場合に使用する述語です。

PROJECTION

VARCHAR2(4000)

操作によって生成される式です。

TIME

NUMBER(20,2)

問合せの最適化によって見積られた操作の秒単位の経過時間です。ルールベースのアプローチを使用する文の場合、この列はNULLです。

QBLOCK_NAME

VARCHAR2(30)

問合せブロックの名前です。システム生成またはQB_NAMEヒントによるユーザー定義のいずれかとなります。

表7-6 PLAN_TABLEのDISTRIBUTION列の値

DISTRIBUTIONテキスト

説明

PARTITION (ROWID)

UPDATEまたはDELETEを実行する行のROWIDを使用し、表または索引のパーティション化に基づいて行を問合せサーバーにマップします。

PARTITION (KEY)

列のセットを使用し、表または索引のパーティション化に基づいて行を問合せサーバーにマップします。パーシャル・パーティション・ワイズ結合、PARALLEL INSERT、パーティション表のCREATE TABLE AS SELECTおよびCREATE PARTITIONED GLOBAL INDEXに使用します。

HASH

結合キーについて、ハッシュ関数を使用して、行を問合せサーバーにマップします。PARALLEL JOINまたはPARALLEL GROUP BYに使用します。

RANGE

ソート・キーの範囲を使用して、行を問合せサーバーにマップします。文にORDER BY句がある場合に使用します。

ROUND-ROBIN

行を問合せサーバーにランダムにマップします。

BROADCAST

表全体の行を各問合せサーバーにブロードキャストします。ある表がその他の表に比べて非常に小さい場合、パラレル結合に使用します。

QC (ORDER)

QCは、最初の問合せサーバーから最後の問合せサーバーまで順番に入力データを受け取ります。文にORDER BY句がある場合に使用します。

QC (RANDOM)

QCは、入力をランダムに受け取ります。文にORDER BY句がない場合に使用します。

表7-7に、EXPLAIN PLAN文によって生成されるOPERATIONとOPTIONSの各組合せおよびその実行計画におけるそれぞれの意味を示します。

表7-7 EXPLAIN PLANによって生成されるOPERATION値とOPTIONS値

操作

オプション

説明

AND-EQUAL

複数のROWIDのセットを受け取り、重複をなくして、そのセットの共通部分を戻す処理。この処理は単一列索引のアクセス・パスに対して使用されます。

BITMAP

CONVERSION

TO ROWIDSは、ビットマップ表現を、表にアクセスするために使用できる実際のROWIDに変換します。

FROM ROWIDSは、ROWIDをビットマップ表現に変換します。

COUNTは、実際の値を必要としない場合にROWIDの数を戻します。

BITMAP

INDEX

SINGLE VALUEは、索引内の単一のキー値のビットマップを参照します。

RANGE SCANは、ある範囲のキー値のビットマップを取り出します。

FULL SCANは、開始キーまたは終了キーがない場合にビットマップ索引の全体スキャンを実行します。

BITMAP

MERGE

レンジ・スキャンの結果の複数のビットマップを1つのビットマップにマージします。

BITMAP

MINUS

片方のビットマップのビットを、もう一方のビットマップから減算します。行ソースは否定述語に対して使用されます。このオプションは、減算が発生する可能性があるビットマップを作成する非否定述語がある場合にのみ使用できます。

BITMAP

OR

2つのビットマップのビット単位のORを計算します。

BITMAP

AND

2つのビットマップのビット単位のANDを計算します。

BITMAP

KEY ITERATION

表の行ソースから各行を取り出し、ビットマップ索引から対応するビットマップを検索します。その後、このビットマップのセットは、次のBITMAP MERGE操作で1つのビットマップにマージされます。

CONNECT BY

CONNECT BY句を含んでいる問合せについて階層順に行を取り出します。

CONCATENATION

複数の行のセットを受け取り、そのセットのUNION-ALLを戻す処理。

COUNT

表から選択された行の数をカウントする処理。

COUNT

STOPKEY

戻される行数をWHERE句のROWNUM式によって制限するカウント処理。

CUBE JOIN

左側の表またはビューおよび右側のキューブを結合します。

NO_USE_CUBEおよびUSE_CUBEヒントの詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

CUBE JOIN

ANTI

左側の表またはビューおよび右側のキューブに対してアンチ結合を使用します。

CUBE JOIN

ANTI SNA

左側の表またはビューおよび右側のキューブに対してアンチ結合(片面NULL対応)を使用します。右側の結合列(キューブ側)はNOT NULLです。

CUBE JOIN

OUTER

左側の表またはビューおよび右側のキューブに対して外部結合を使用します。

CUBE JOIN

RIGHT SEMI

左側の表またはビューおよび右側のキューブに対して右側セミ結合を使用します。

CUBE SCAN

すべてのキューブ・アクセスで内部結合を使用します。

CUBE SCAN

PARTIAL OUTER

少なくとも1つのディメンションで外部結合を使用し、その他のディメンションで内部結合を使用します。

CUBE SCAN

OUTER

すべてのキューブ・アクセスで外部結合を使用します。

DOMAIN INDEX

ドメイン索引からの1つ以上のROWIDの取出し。オプション列には、ユーザー定義ドメイン・インデックス・コスト関数から与えられた情報が含まれています。

FILTER

行のセットを受け取り、そのいくつかを取り除き、残りを戻す処理。

FIRST ROW

問合せで選択される最初の行のみの取出し。

FOR UPDATE

FOR UPDATE句が含まれている問合せによって選択される行を取り出し、ロックする処理。

HASH

GROUP BY

GROUP BY句を持つ問合せで、行のセットを複数のグループにハッシュする処理。

HASH

GROUP BY PIVOT

GROUP BY句を持つ問合せで、行のセットを複数のグループにハッシュする処理。PIVOT操作は、HASH GROUP BY演算子のピボット固有の最適化を示します。

HASH JOIN

(これらは結合操作です。)

2つのセットの行を結合し、結果を戻す操作。この結合方法は、データのラージ・データ・セット(DSSやバッチなど)の結合に役立ちます。この結合条件は、第2の表にアクセスする場合に有効です。

問合せオプティマイザは、2つの表またはデータ・ソースの小さいほうを使用して、メモリー内に結合キーについてのハッシュ表を作成します。次に、大きいほうの表をスキャンし、ハッシュ表を調べて結合された行を見つけます。

HASH JOIN

ANTI

ハッシュ(左側)アンチ結合。

HASH JOIN

SEMI

ハッシュ(左側)セミ結合。

HASH JOIN

RIGHT ANTI

ハッシュ右側アンチ結合。

HASH JOIN

RIGHT SEMI

ハッシュ右側セミ結合。

HASH JOIN

OUTER

ハッシュ(左側)外部結合。

HASH JOIN

RIGHT OUTER

ハッシュ(右側)外部結合。

INDEX

(これらはアクセス方法です。)

UNIQUE SCAN

索引からの単一のROWIDの取出し。

INDEX

RANGE SCAN

索引からの1つ以上のROWIDの取出し。索引値は昇順でスキャンされます。

INDEX

RANGE SCAN DESCENDING

索引からの1つ以上のROWIDの取出し。索引値は降順でスキャンされます。

INDEX

FULL SCAN

スタート・キーおよびストップ・キーがない場合の、索引からのすべてのROWIDの取得。索引値は昇順でスキャンされます。

INDEX

FULL SCAN DESCENDING

スタート・キーおよびストップ・キーがない場合の、索引からのすべてのROWIDの取得。索引値は降順でスキャンされます。

INDEX

FAST FULL SCAN

マルチブロックREADを使用した全ROWID(および列の値)の取得。ソート順は定義できません。索引付けされた列に対してのみ、全表スキャンと比較されます。コストベース・オプティマイザでのみ使用可能です。

INDEX

SKIP SCAN

索引内の先頭列を使用しない、連結索引からのROWIDの取得。コストベース・オプティマイザでのみ使用可能です。

INLIST ITERATOR

INリスト述語内の各値に対して、計画内の次の操作を反復します。

INTERSECTION

2つの行のセットを受け取り、重複をなくして、そのセットの共通部分を戻す処理。

MERGE JOIN

(これらは結合操作です。)

2つの行のセットを受け取り、それぞれを特定の値でソートし、一方のセットの各行を他方の行と突き合せて結合し、その結果を戻す処理。

MERGE JOIN

OUTER

外部結合文を実行するマージ結合処理。

MERGE JOIN

ANTI

マージ・アンチ結合。

MERGE JOIN

SEMI

マージ・セミ結合。

MERGE JOIN

CARTESIAN

文中に他の表への結合条件を持たない1つ以上の表について発生する操作です。結合とともに発生する可能性がありますが、計画内ではCARTESIANとフラグが付かないことがあります。

CONNECT BY

CONNECT BY句を含んでいる問合せに対する、階層順での行の取出し。

MAT_VIEW REWITE ACCESS

(これらはアクセス方法です。)

FULL

マテリアライズド・ビューのすべての行の取出し。

MAT_VIEW REWITE ACCESS

SAMPLE

マテリアライズド・ビューのサンプル行の取出し。

MAT_VIEW REWITE ACCESS

CLUSTER

索引クラスタのキーの値に基づいた、マテリアライズド・ビューからの行の取出し。

MAT_VIEW REWITE ACCESS

HASH

ハッシュ・クラスタのキーの値に基づいた、マテリアライズド・ビューからの行の取出し。

MAT_VIEW REWITE ACCESS

BY ROWID RANGE

ROWID範囲に基づいたマテリアライズド・ビューからの行の取出し。

MAT_VIEW REWITE ACCESS

SAMPLE BY ROWID RANGE

ROWID範囲に基づいたマテリアライズド・ビューからのサンプル行の取出し。

MAT_VIEW REWITE ACCESS

BY USER ROWID

ユーザー指定のROWIDを使用してマテリアライズド・ビューの行が指定される場合。

MAT_VIEW REWITE ACCESS

BY INDEX ROWID

マテリアライズド・ビューがパーティション化されておらず、索引を使用して行が指定される場合。

MAT_VIEW REWITE ACCESS

BY GLOBAL INDEX ROWID

マテリアライズド・ビューがパーティション化されており、グローバル索引のみを使用して行が指定される場合。

MAT_VIEW REWITE ACCESS

BY LOCAL INDEX ROWID

マテリアライズド・ビューがパーティション化されており、1つ以上のローカル索引と、場合によってはいくつかのグローバル索引を使用して行が指定される場合。

パーティション区間:

パーティション区間は次のようにして計算されている可能性があります。

前のPARTITIONステップによって決定される場合。この場合、PARTITION_START列の値とPARTITION_STOP列の値はPARTITIONステップ内の値をレプリケートし、PARTITION_IDにはPARTITIONステップのIDが組み込まれます。PARTITION_STARTおよびPARTITION_STOPに使用できる値は、NUMBER(n)、KEYおよびINVALIDです。

MAT_VIEW REWRITE ACCESSまたはINDEXステップ自体で決定される場合。この場合、PARTITION_IDにはそのステップのIDが組み込まれます。PARTITION_STARTおよびPARTITION_STOPに使用できる値は、NUMBER(n)、KEY、ROW REMOVE_LOCATION(MAT_VIEW REWRITE ACCESSのみ)およびINVALIDです。

MINUS

2つの行のセットを受け取り、最初のセットにあって2番目のセットにない行を戻して、重複をなくす処理。

NESTED LOOPS

(これらは結合操作です。)

外側のセットと内側のセット、2つの行のセットを受け取る処理。Oracle Databaseは、外側のセットの各行を内側のセットの各行と比較し、条件を満たす行を戻します。この結合方法は、小さいサブセットのデータを結合する場合(OLTP)に役立ちます。この結合条件は、第2の表にアクセスする場合に有効です。

NESTED LOOPS

OUTER

外部結合文を実行するネステッド・ループ操作。

PARTITION

PARTITION_START列およびPARTITION_STOP列によって指定された範囲の各パーティションに対して、計画内の次の操作を反復します。PARTITIONは、単一のパーティション・オブジェクト(表または索引)や同一レベル・パーティション・オブジェクトのセット(パーティション表やそのローカル索引)に適用できるパーティションの区間を示します。パーティションの区間は、PARTITIONのPARTITION_STARTおよびPARTITION_STOPの値で指定されます。パーティションの開始および終了の有効な値は、表7-4を参照してください。

PARTITION

SINGLE

1つのパーティションへのアクセス。

PARTITION

ITERATOR

多数のパーティション(サブセット)へのアクセス。

PARTITION

ALL

すべてのパーティションへのアクセス。

PARTITION

INLIST

INリスト述語を基準にしたイテレータに類似するもの。

PARTITION

INVALID

アクセスするよう設定されているパーティションが空であることを示します。

PX ITERATOR

BLOCK、CHUNK

パラレル実行サーバー・セット間でのブロックまたはチャンク範囲へのオブジェクトの分割を実装します。

PX COORDINATOR

パラレル実行サーバーを使用して下位のパラレル計画を制御、スケジュールおよび実行する問合せコーディネータを実装します。また、パラレルに実行され、常に下位にPX SEND QC操作を持つ計画部分の終わりとして、シリアライズ・ポイントを表します。

PX PARTITION

セマンティクスは通常のPARTITION操作と同じですが、パラレル計画に表示されます。

PX RECEIVE

PX SENDノード上で実行される送信側/プロデューサ(QCまたはパラレル実行サーバー)から再パーティション化されたデータを読み取る、コンシューマ/受信側パラレル実行ノードを示します。以前は、この情報はDISTRIBUTION列に表示されていました。詳細は、表7-5を参照してください。

PX SEND

QC (RANDOM)、HASH、RANGE

スレーブの2つのパラレル実行サーバー・セットの間における配分方法を実装します。2つのセット間の境界と、送信側/プロデューサ側(QCまたはスレーブ)でのデータのパーティション化方法を示します。以前は、この情報はDISTRIBUTION列に表示されていました。詳細は、表7-5を参照してください。

REMOTE

リモート・データベースからのデータの取出し。

SEQUENCE

順序値のアクセスを伴う処理。

SORT

AGGREGATE

選択した行のグループにグループ関数を適用した結果として取得される単一行の取出し。

SORT

UNIQUE

行のセットをソートし、重複をなくす処理。

SORT

GROUP BY

GROUP BY句を持つ問合せで、行のセットを複数のグループにソートする処理。

SORT

GROUP BY PIVOT

GROUP BY句を持つ問合せで、行のセットを複数のグループにソートする処理。PIVOT操作は、SORT GROUP BY演算子のピボット固有の最適化を示します。

SORT

JOIN

マージ結合の前に、一連の行をソートする操作。

SORT

ORDER BY

ORDER BY句を持つ問合せに対して行のセットをソートする処理。

TABLE ACCESS

(これらはアクセス方法です。)

FULL

表のすべての行の取出し。

TABLE ACCESS

SAMPLE

表のサンプル取得された行の取出し。

TABLE ACCESS

CLUSTER

索引クラスタのキーの値に基づいた、表からの行の取出し。

TABLE ACCESS

HASH

ハッシュ・クラスタのキーの値に基づいた、表からの行の取出し。

TABLE ACCESS

BY ROWID RANGE

ROWID範囲に基づいた表からの行の取出し。

TABLE ACCESS

SAMPLE BY ROWID RANGE

ROWID範囲に基づいた表からのサンプル行の取出し。

TABLE ACCESS

BY USER ROWID

ユーザー指定のROWIDを使用して表の行が指定される場合。

TABLE ACCESS

BY INDEX ROWID

表がパーティション化されておらず、索引を使用して行が指定される場合。

TABLE ACCESS

BY GLOBAL INDEX ROWID

表がパーティション化されており、グローバル索引のみを使用して行が指定される場合。

TABLE ACCESS

BY LOCAL INDEX ROWID

表がパーティション化されており、1つ以上のローカル索引と場合によってはいくつかのグローバル索引を使用して、行が指定される場合。

パーティション区間:

パーティション区間は次のようにして計算されている可能性があります。

前のPARTITIONステップによって決定される場合。この場合、PARTITION_START列の値とPARTITION_STOP列の値はPARTITIONステップ内の値をレプリケートし、PARTITION_IDにはPARTITIONステップのIDが組み込まれます。PARTITION_STARTおよびPARTITION_STOPに使用できる値は、NUMBER(n)、KEYおよびINVALIDです。

TABLE ACCESSまたはINDEXステップ自体で決定される場合。この場合、PARTITION_IDにはそのステップのIDが組み込まれます。PARTITION_STARTおよびPARTITION_STOPに使用できる値は、NUMBER(n)、KEY、ROW REMOVE_LOCATION(TABLE ACCESSのみ)およびINVALIDです。

TRANSPOSE

GROUP BYの結果を入れ換えて最終的にピボットされたデータを生成するPIVOT操作を評価する操作。

UNION

2つの行のセットを受け取り、重複をなくして、そのセットの連結結果を戻す処理。

UNPIVOT

列から行にデータを回転させる操作。

VIEW

ビューの問合せを実行し、結果の行を別の処理に戻す処理。

関連項目:

PLAN_TABLEの詳細は、Oracle Databaseリファレンスを参照してください。

DBMS_XPLANプログラム・ユニット

DBMS_XPLANのファンクションDISPLAY_PLANおよびDISPLAY_CURSORは、適応計画のアクセスに関連します。

表7-8 適応問合せに関連するDBMS_XPLAN関数およびパラメータ

関数

注意

DISPLAY_PLAN

FORMAT引数は、修飾子ADAPTIVEをサポートしています。

ADAPTIVEを指定すると、出力にはデフォルトの計画が含まれます。動的なサブプランそれぞれについて、計画では、置き換えられる可能性のある元の行ソースおよびそれらを置き換える行ソースのリストが示されます。

フォーマット引数にアウトライン表示が指定されると、関数では、動的サブプラン内の各オプションに対するヒントが表示されます。計画が適応問合せ計画でない場合、関数ではデフォルトの計画が表示されます。ADAPTIVEを指定しないと、計画はそのまま表示されますが、動的な行ソースがあれば、Noteセクション内の追加のコメントに示されます。

DISPLAY_CURSOR

FORMAT引数は、修飾子ADAPTIVEをサポートしています。

ADAPTIVEを指定すると、出力には次のものが含まれます。

- 最終計画。実行が完了していない場合、出力には現在の計画が示されます。このセクションには、計画に影響を及ぼす実行時の最適化に関する注意事項も含まれます。

- 推奨計画。レポート作成モードでは、出力には、実行統計に基づいて選択される計画が含まれます。

- 動的計画。出力には、オプティマイザによって選択されたデフォルトの計画とは異なる計画の部分がまとめられます。

- 再最適化。出力には再最適化により以降の実行で選択される予定の計画が表示されます。

関連項目:

DBMS_XPLANの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください

第IV部 SQL演算子: アクセス・パスおよび結合

行ソースは、実行計画のステップによって戻される行のセットです。SQL演算子は行ソースに対して機能します。

単項演算子は、アクセス・パスのように1つの入力に対して機能します。バイナリ演算子は、結合のように2つの入力に対して機能します。

この部には次の章が含まれます:

- オプティマイザのアクセス・パス

- 結合

8 オプティマイザのアクセス・パス

アクセス・パスは、問合せで行ソースから行を取り出すために使用される手法です。

この章の内容は次のとおりです。

- 「アクセス・パスの概要」

- 表アクセス・パス

- Bツリー索引アクセス・パス

- ビットマップ索引アクセス・パス

- 表クラスタ・アクセス・パス

「アクセス・パスの概要」

行ソースは、実行計画のステップによって戻される行のセットです。表、ビュー、または結合処理あるいはグループ化処理の結果が行ソースになる可能性があります。

アクセス・パスなどの単項演算は、行ソースから行を取得するために問合せで使用される手法であり、単一の行ソースを入力として受け入れます。たとえば、全表スキャンは、単一行ソースの行の取得です。対照的に、結合操作はバイナリで、2つの行ソースから入力を受け取ります。

データベースでは、リレーショナル・データ構造ごとに異なるアクセス・パスを使用します。次の表は、主なデータ構造に対する一般的なアクセス・パスについてまとめたものです。

表8-1 データ構造とアクセス・パス

アクセス・パス

ヒープ構成表

Bツリー索引およびIOT

ビットマップ索引

表クラスタ

全表スキャン

×

ROWIDによる表アクセス

×

サンプル表スキャン

×

索引一意スキャン

×

索引レンジ・スキャン

×

全索引スキャン

×

高速全索引スキャン

×

索引スキップ・スキャン

×

索引結合スキャン

×

ビットマップ索引単一値

×

ビットマップ索引レンジ・スキャン

×

ビットマップ・マージ

×

ビットマップ索引レンジ・スキャン

×

クラスタ・スキャン

×

ハッシュ・スキャン

×

オプティマイザは、使用可能な様々な実行計画を検討し、各計画にコストを割り当てます。オプティマイザは、コストが最も低い計画を選択します。一般に、表の行の小さいサブセットを取得する文には索引アクセス・パスのほうが効率的ですが、表の大きな部分にアクセスする場合は全表スキャンのほうが効率的です。

関連項目:

- 結合

- コストベースの最適化

- これらの構造の概要は、『Oracle Database概要』を参照してください。

表アクセス・パス

表は、Oracle Databaseにおけるデータ編成の基本単位です。

リレーショナル表は、最も一般的な表タイプです。リレーショナル表には次のような構成上の特徴があります。

- ヒープ構成表では、行は特定の順序で格納されません。

- 索引構成表では、主キー値に従って行が整列されます。

- 外部表は読取り専用の表であり、これらのメタデータはデータベースに格納されますが、データはデータベースの外部に格納されます。

この項には、ヒープ構成表へのオプティマイザのアクセス・パスについて説明する次のトピックがあります。

- ヒープ構成表アクセスについて

- 全表スキャン

- ROWIDによる表アクセス

- サンプル表スキャン

- インメモリー表スキャン

関連項目:

- 表の概要は、『Oracle Database概要』を参照してください。

- 表の管理方法の詳細は、『Oracle Database管理者ガイド』を参照してください。

ヒープ構成表アクセスについて

デフォルトでは、表はヒープとして編成されます。つまり、データベースでは、ユーザーが指定する順序ではなく、最も収まりすいように行が配置されます。

ユーザーが行を追加すると、データベースではデータ・セグメントの最初の使用可能な空き領域に行が格納されます。挿入された順序どおりに行が取得されることは保証されていません。

データ・ブロックとセグメントでの行の格納: 入門編

データベースでは、行がデータ・ブロックに格納されます。表では、ブロックの下部の任意の行へ書込みが行われます。Oracle Databaseは、ブロック自体を管理するために、行ディレクトリと表ディレクトリが含まれているブロック・オーバーヘッドを使用します。

エクステントは論理的に連続するデータ・ブロックから構成されます。ブロックはディスク上で物理的に連続していない可能性もあります。セグメントは、表領域内の特定の論理記憶域構造のデータがすべて入っている、エクステントの集合です。たとえば、Oracle Databaseでは、1つ以上のエクステントを割り当てることによって、表のデータ・セグメントを形成します。また、データベースは、表の索引セグメントを作成するためにも、1つ以上のエクステントを割り当てます。

デフォルトでは、データベースは永続的なローカル管理表領域に対して、自動セグメント領域管理(ASSM)を使用します。セッションが最初にデータを表に挿入すると、データベースはビットマップ・ブロックをフォーマットします。ビットマップはセグメントのブロックを追跡します。データベースでは、ビットマップを使用して空きブロックが検索され、各ブロックは書き込み前にフォーマットされます。ASSMを使用すると、挿入処理が各ブロックに分散されるため、同時実行性の問題を回避できます。

最高水位標(HWM)は、セグメント内の位置を指し示し、その位置を超えると、データ・ブロックは未フォーマットであり、使用されていません。HWMより下のブロックは、フォーマット済で書き込まれている、フォーマット済で空である、あるいは未フォーマットである場合があります。低い最高水位標(低いHWM)は、この位置より下のすべてのブロックは、データが格納されているか、以前にデータが格納されていたため、フォーマット済であることを示しています。

全表スキャン時は、データベースはフォーマット済であることが既知である低いHWMまでのブロックをすべて読み取り、次に、セグメント・ビットマップを読み取って、HWMと低いHWMの間にあるどのブロックがフォーマット済で安全に読み取れるのかを判別します。データベースは、ブロックが未フォーマットであるため、HWMを超えて読み取ることはありません。

関連項目:

データ・ブロックの記憶域の詳細は、『Oracle Database概要』を参照してください。

行アクセスにおけるROWIDの重要性

ヒープ構成表のすべての行にはその表で一意のROWIDがあり、これは行断片の物理アドレスに相当します。ROWIDは行の10バイトの物理アドレスです。

ROWIDは特定のファイル、ブロックおよび行番号を指します。たとえば、ROWID AAAPecAAFAAAABSAAAでは、最後のAAAは行番号を表します。行番号は行ディレクトリ・エントリの索引です。行ディレクトリ・エントリにはブロックにおける行の位置へのポインタが含まれます。

データベースはブロックの下部で行を移動することがあります。たとえば、行の移動が可能な場合、行は、パーティション・キーの更新、フラッシュバック表の操作、表の縮小操作などのために移動できます。データベースがブロック内で行を移動する場合、データベースは行ディレクトリ・エントリを更新してポインタを修正します。ROWIDは変わりません。

Oracle Databaseでは、ROWIDを内部的に使用して索引が構築されます。たとえば、Bツリー索引のそれぞれのキーは、対応する行のアドレスを指すROWIDに関連付けられています。物理ROWIDを使用すると、表の1つの行に最速でアクセスでき、データベースではわずか1回のI/Oで行を取得できます。

関連項目:

ROWIDの詳細は、『Oracle Database概要』を参照してください。

ダイレクト・パス読取り

ダイレクト・パス読取りでは、データベースは、SGA全体を回避しながら、ディスクからPGAに直接バッファを読み込みます。

次の図は、SGAにバッファを格納する散布読取りおよび順次読取りと、ダイレクト・パス読取りの違いを示しています。

図8-1 ダイレクト・パス読取り

Oracle Databaseがダイレクト・パス読取りを実行する可能性のある状況には、次のようなものがあります。

- CREATE TABLE AS SELECT文の実行

- ALTER REBUILD文またはALTER MOVE文の実行

- 一時表領域からの読取り

- パラレル問合せ

- LOBセグメントからの読取り

関連項目:

ダイレクト・パス読取りの待機イベントの詳細は、『Oracle Databaseパフォーマンス・チューニング・ガイド』を参照してください。

全表スキャン

全表スキャンでは、表のすべての行が読み取られ、選択基準を満たしていない行がフィルタ処理されます。

オプティマイザが全表スキャンを考慮する場合

一般に、オプティマイザは、別のアクセス・パスを使用できない場合、または使用可能な別のアクセス・パスのコストが高い場合は、全表スキャンを選択します。

次の表では、全表スキャンを選択する一般的な理由を示します。

表8-2 全表スキャンの一般的な理由

理由

説明

詳細情報

索引が存在しない。

索引が存在しない場合、オプティマイザは、全表スキャンを使用します。

『Oracle Database概要』

問合せ述語が、索引付けされた列に関数を適用する。

索引がファンクション索引でない場合、関数が適用された列の値ではなく、その列の値が索引付けされます。典型的なアプリケーション・レベルの誤りは、char_colなどの文字の列を索引付けし、WHERE char_col=1などの構文を使用して列を問い合せることです。データベースでは、暗黙的にTO_NUMBER関数に定数1(索引を使用することはできません)が適用されます。

「パフォーマンスを考慮したファンクション索引の使用方法に関するガイドライン」

SELECT COUNT(*)問合せが発行され、索引が存在するが、索引付けされた列にNULLが含まれている。

索引にはNULLエントリを含めることはできないため、オプティマイザは、索引を使用して、表の行数をカウントすることができません。

「Bツリー索引およびNULL」

問合せ述語では、最先端のBツリー索引を使用することができない。

たとえば、employees(first_name,last_name)に索引が存在するとします。ユーザーが述語WHERE last_name='KING'を使用して問合せを発行する場合、列first_nameが述語に含まれていないため、オプティマイザは、索引を選択しない可能性があります。ただし、このような場合、オプティマイザが索引スキップ・スキャンの使用を選択することがあります。

「索引スキップ・スキャン」

問合せは非選択性である。

表のほとんどのブロックを必要とする問合せの場合、オプティマイザは、索引が使用可能であっても、全表スキャンを使用します。全表スキャンではより大きなI/Oコールを使用できます。大きなI/Oコールを少なくすることにより、小さなコールを何度も行うよりもコストが低くなります。

選択性

表統計が失効している。

たとえば、以前は小さかった表が大きくなったとします。表統計が失効しており、表の現在のサイズを反映していない場合、オプティマイザは、現在では全表スキャンではなく索引が最も効率的であることを認識できません。

「オプティマイザ統計の概要」

表が小さい。

表に含まれているブロックがn個よりも少なく、最高水位標を下回っている場合(ここで、nは、DB_FILE_MULTIBLOCK_READ_COUNT初期化パラメータの設定と同じです)、全表スキャンのほうが索引レンジ・スキャンよりもコストが低いことがあります。このスキャンは、アクセス先の表の部分や索引の存在に関係なく、よりコストが低くなる可能性があります。

『Oracle Databaseリファレンス』

表の並列度が高い。

表の並列度が高いと、レンジ・スキャンよりも全表スキャンの方向にオプティマイザを偏らせます。並列度を判断するには、ALL_TABLES.DEGREE列の値を問い合せます。

『Oracle Databaseリファレンス』

問合せで全表スキャンのヒントが使用される。

ヒントFULL(table alias)は、オプティマイザに全表スキャンの使用を指示するものです。

『Oracle Database SQL言語リファレンス』

全表スキャンの仕組み

全表スキャンでは、データベースは、最高水位標を下回るすべてのフォーマット済ブロックを順に読み取ります。データベースは、各ブロックを1回のみ読み取ります。

次の図は、表セグメントのスキャンで、最高水位標を下回る未フォーマットのブロックがどのようにスキップされるかを示しています。

図8-2 最高水位標

ブロックは隣接しているため、データベースでは、I/Oコールを単一ブロックより大きくすることでスキャンを高速化できます。これは、マルチブロック読取りと呼ばれています。読取りコールのサイズは、1ブロックからDB_FILE_MULTIBLOCK_READ_COUNT初期化パラメータで指定されているブロック数までの範囲になります。たとえば、このパラメータを4に設定すると、データベースは単一コールで最大4ブロックを読み取ります。

全表スキャン中の、ブロックのキャッシングのアルゴリズムは複雑です。たとえば、表が小さいか大きいかによって、ブロックがキャッシュされる方法は異なります。

関連項目:

- 表14-1

- デフォルトのキャッシュ・モードの概要は、『Oracle Database概要』を参照してください。

- DB_FILE_MULTIBLOCK_READ_COUNT初期化パラメータの詳細は、『Oracle Databaseリファレンス』を参照してください。

全表スキャン: 例

次の文は、hr.employees表で4000を超える給与を問い合せます。

SELECT salary
FROM   hr.employees
WHERE  salary > 4000;

例8-1 全表スキャン

次の計画は、DBMS_XPLAN.DISPLAY_CURSOR関数を使用して取得されました。salary列には索引が存在しないため、オプティマイザは、索引レンジ・スキャンを使用できず、全表スキャンを使用します。

SQL_ID  54c20f3udfnws, child number 0
-------------------------------------
select salary from hr.employees where salary > 4000

Plan hash value: 3476115102

-------------------------------------------------------------------------------
| Id  | Operation         | Name      | Rows  | Bytes | Cost (%CPU)| Time     |
-------------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |           |       |       |     3 (100)|          |
|*  1 |  TABLE ACCESS FULL| EMPLOYEES |    98 |  6762 |     3   (0)| 00:00:01 |
-------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

1 - filter("SALARY">4000)

ROWIDによる表アクセス

ROWIDは、データの格納場所の内部表現です。

行のROWIDは、行が含まれるデータファイルとデータ・ブロック、およびブロック内での行の位置を指定します。ROWIDの指定による行の位置特定は、単一行を取得する最も高速な方法です。これは、取得する行のデータベース内での正確な位置が指定されるためです。

注意:

ROWIDは、バージョン間で変わってしまう場合があります。行は移動する可能性があるため、位置に基づくアクセスはお薦めしません。

関連項目:

ROWIDの詳細は、『Oracle Database開発ガイド』を参照してください。

オプティマイザがROWIDによる表アクセスを選択する場合

ほとんどの場合、データベースは1つ以上の索引のスキャン後にROWIDによって表にアクセスします。しかし、ROWIDによる表アクセスでは、すべての索引スキャンに従う必要はありません。必要な列がすべて索引に含まれていると、ROWIDによるアクセスは行われない場合があります(「高速全索引スキャン」を参照)。

ROWIDによる表アクセスの仕組み

ROWIDによって表にアクセスするには、データベースで次の手順を実行します。

1. 文のWHERE句または1つ以上の索引の索引スキャンのいずれかを使用して、選択した行のROWIDを取得します。
索引内に存在しない文の中の列には、表アクセスが必要になる場合があります。

2. ROWIDに基づいて、表内で選択された各行の位置を特定します。

ROWIDによる表アクセス: 例

次の問合せを実行するとします。

SELECT *
FROM   employees
WHERE  employee_id > 190;

次の計画の手順2は、hr.employees表にあるemp_emp_id_pk索引のレンジ・スキャンを示しています。データベースは索引から取得したROWIDを使用して、employees表から対応する行を検索し、取得します。手順1に示されているBATCHEDアクセスは、データベースが索引からいくつかのROWIDを取得してからブロック順に行へのアクセスを試行することで、クラスタリングが改善され、データベースがブロックにアクセスしなければならない回数が減ることを意味します。

--------------------------------------------------------------------------------
|Id| Operation                           | Name     |Rows|Bytes|Cost(%CPU)|Time|
--------------------------------------------------------------------------------
| 0| SELECT STATEMENT                    |             |  |    |2(100)|        |
| 1|  TABLE ACCESS BY INDEX ROWID BATCHED|EMPLOYEES    |16|1104|2  (0)|00:00:01|
|*2|   INDEX RANGE SCAN                  |EMP_EMP_ID_PK|16|    |1  (0)|00:00:01|
--------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

2 - access("EMPLOYEE_ID">190)

サンプル表スキャン

サンプル表スキャンでは、単純な表、または結合およびビューを含む文などの複合SELECT文からデータのランダムなサンプルが取り出されます。

オプティマイザがサンプル表スキャンを選択する場合

文のFROM句にSAMPLEキーワードが含まれている場合、データベースでは、サンプル表スキャンが使用されます。

SAMPLE句には次の形式があります。

- SAMPLE (sample_percent)
データベースは、表内の行を指定の割合だけ読み取って、サンプル表スキャンを実行します。

- SAMPLE BLOCK (sample_percent)
データベースは、表ブロックを指定の割合だけ読み取って、サンプル表スキャンを実行します。

sample_percentには、行またはブロックの合計数の何パーセントがサンプルに含まれるかを指定します。.000001以上100未満の範囲の値を指定します。この割合は、各行(ブロック・サンプリングでは行の各クラスタ)が、サンプル用に選択される可能性を示します。データベースがsample_percent分の行を厳密に取り出すということではありません。

注意:

ブロック・サンプリングは、全表スキャン中または高速全索引スキャン中にのみ使用可能です。より効率的な実行パスが存在する場合、ブロック・サンプリングは実行されません。特定の表または索引に対するブロック・サンプリングを確実に実行する場合は、FULLまたはINDEX_FFSのヒントを使用します。

関連項目:

- 「ヒントによるオプティマイザへの影響」

- SAMPLE句の詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

サンプル表スキャン: 例

例8-2は、サンプル表スキャンを使用して、行ではなくブロックによるサンプリングを行ってemployees表の1%にアクセスします。

例8-2 サンプル表スキャン

SELECT * FROM hr.employees SAMPLE BLOCK (1);

この文のEXPLAIN PLAN出力は、次のような形式になります。

-------------------------------------------------------------------------
| Id  | Operation            |  Name       | Rows  | Bytes | Cost (%CPU)|
-------------------------------------------------------------------------
|   0 | SELECT STATEMENT     |             |     1 |    68 |     3  (34)|
|   1 |  TABLE ACCESS SAMPLE | EMPLOYEES   |     1 |    68 |     3  (34)|
-------------------------------------------------------------------------

インメモリー表スキャン

Oracle Database 12c リリース1 (12.1.0.2)以降、インメモリー・スキャンはインメモリー列ストア(IM列ストア)から一部またはすべての行を取得します。IM列ストアは任意に入力できるSGA領域です。ここには、迅速にスキャンできるように最適化された特殊な列形式で、表のコピーおよびパーティションが格納されています。

関連項目:

- IM列ストアの概要は、Oracle Database概要を参照

- IM列ストアの有効化の詳細は、『Oracle Database管理者ガイド』を参照

オプティマイザがインメモリー表スキャンを選択する場合

Oracle Database 12cリリース1 (12.1.0.2)以降、オプティマイザ・コスト・モデルはIM列ストアの内容を完全に認識します。ユーザーがIM列ストア内の表を参照する問合せを実行すると、オプティマイザによって、インメモリー表スキャンなどのすべての考えられるアクセス方法のコストが計算され、コストが最小のアクセス方法が選択されます。

インメモリー問合せの制御

次のデータベース初期化パラメータは、インメモリー機能に影響します。

- INMEMORY_QUERY
このパラメータでは、セッションまたはシステム・レベルでデータベースのインメモリー問合せを有効または無効にします。このパラメータは、IM列ストアを使用する場合と使用しない場合でワークロードをテストする際に役立ちます。

- OPTIMIZER_INMEMORY_AWARE
このパラメータでは、オプティマイザ・コスト・モデル、表拡張、ブルーム・フィルタなどに対して行われたすべてのインメモリー拡張を有効(TRUE)または無効(FALSE)にします。パラメータをFALSEに設定すると、オプティマイザはSQL文の最適化中に表のインメモリー・プロパティを無視します。

- OPTIMIZER_FEATURES_ENABLE
12.1.0.2より小さい値に設定した場合、このパラメータの効果はOPTIMIZER_INMEMORY_AWAREをFALSEに設定した場合と同じです。

インメモリー問合せを有効または無効にするには、INMEMORYまたはNO_INMEMORYヒントを指定できます。これは、問合せごとのINMEMORY_QUERY初期化パラメータと同じです。SQL文でINMEMORYヒントを使用し、それが参照するオブジェクトがIM列ストアにまだロードされていない場合、データベースは文を実行する前にIM列ストアにオブジェクトが移入されるのを待機しません。ただし、オブジェクトの初期アクセスにより、IM列ストア内のオブジェクトの移入がトリガーされます。

関連項目:

- INMEMORY_QUERY、OPTIMIZER_INMEMORY_AWAREおよびOPTIMIZER_FEATURES_ENABLE初期化パラメータの詳細は、『Oracle Databaseリファレンス』を参照してください。

- INMEMORYヒントの詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

インメモリー表スキャン: 例

次の例に、INMEMORY HIGHオプションで変更されたoe.product_information表の問合せを示します。

例8-3 インメモリー表スキャン

SELECT *
FROM   oe.product_information
WHERE  list_price > 10
ORDER BY product_id

この文の計画は次のようになり、ステップ2のINMEMORYキーワードはオブジェクトの一部またはすべてがIM列ストアからアクセスされたことを示します。

SQL> SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR);

SQL_ID  2mb4h57x8pabw, child number 0
-------------------------------------
select * from oe.product_information where list_price > 10 order byproduct_id

Plan hash value: 2256295385
--------------------------------------------------------------------------------------------
|Id| Operation                   | Name                |Rows|Bytes |TempSpc|Cost(%CPU)|Time|
--------------------------------------------------------------------------------------------
| 0| SELECT STATEMENT            |                     |    |      |     |21 (100)|        |
| 1|  SORT ORDER BY              |                     | 285| 62415|82000|21   (5)|00:00:01|
|*2|   TABLE ACCESS INMEMORY FULL| PRODUCT_INFORMATION | 285| 62415|     | 5   (0)|00:00:01|
--------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------
2 - inmemory("LIST_PRICE">10)
filter("LIST_PRICE">10)

Bツリー索引アクセス・パス

索引は、表または表クラスタに関連するオプションの構造であり、索引によってデータ・アクセスを高速化できる場合があります。表の1つ以上の列に索引を作成することによって、場合によって、ランダムに分散している行の小さなセットを表から取得できるようになります。索引は、ディスクI/Oを削減するための様々な手段のうちの1つです。

この項の内容は次のとおりです。

- Bツリー索引アクセスについて

- 索引一意スキャン

- 索引レンジ・スキャン

- 全索引スキャン

- 高速全索引スキャン

- 索引スキップ・スキャン

- 索引結合スキャン

関連項目:

- 索引の概要については、『Oracle Database概要』を参照してください。

- 索引の管理方法の詳細は、『Oracle Database管理者ガイド』を参照してください。

Bツリー索引アクセスについて

Bツリー(バランス・ツリーの略)は、最も一般的なタイプのデータベース索引です。

Bツリー索引は、複数の範囲に分割された順序付きの値リストです。Bツリーは、キーを行または行の範囲と関連付けることによって、完全一致や範囲検索など、広範囲の問合せに対して優れた検索パフォーマンスを提供します。

この項の内容は次のとおりです。

- Bツリー索引構造

- 索引記憶が索引スキャンに与える影響

- 一意索引と非一意索引

- Bツリー索引およびNULL

Bツリー索引構造

Bツリー索引には、検索用のブランチ・ブロックと、値を格納するリーフ・ブロックの2種類のブロックがあります。

次の図に、Bツリー索引の論理構造を示します。ブランチ・ブロックには、2つのキーの分岐を決定する際に必要な、最小のキー接頭辞が格納されます。リーフ・ブロックには、すべての索引付きデータ値と、実際の行を検索するための対応するROWIDが含まれています。各索引エントリは(キー、ROWID)によってソートされます。リーフ・ブロックは二重にリンクされます。

図8-3 Bツリー索引構造

索引記憶が索引スキャンに与える影響

ビットマップ索引ブロックは、索引セグメントのどこにでも出現することができます。

図8-3は、互いに隣接するリーフ・ブロックを示しています。たとえば、1-10のブロックは、11-19のブロックの前であり、隣り合っています。この順序は、索引エントリを接続するリンクされたリストを示しています。ただし、索引ブロックは、索引セグメント内で順番に格納される必要はありません。たとえば、246から250ブロックは、1から10ブロックの直前を含め、セグメント内のどこにでも出現することができます。このため、順序付き索引スキャンは単一ブロックI/Oを実行する必要があります。データベースは、索引ブロックを読み取ることでどの索引ブロックを次に読み取るかを判断する必要があります。

索引ブロック本体は、表の行と同様に、索引エントリをヒープに格納します。たとえば、値10が最初に表に挿入された場合、キーが10の索引エントリは索引ブロックの最下部に挿入される可能性があります。0が次に表に挿入された場合、キー0の索引エントリは10のエントリの上に挿入される可能性があります。したがって、ブロック本体の索引エントリは、キーの順には格納されません。ただし、索引ブロック内では、行ヘッダーはレコードをキーの順に格納します。たとえば、ヘッダーの最初のレコードはキー0を含む索引エントリを指し、以下同様に、キー10の索引エントリを指すレコードまで順に続きます。したがって、索引スキャンは行ヘッダーを読み取ることで、レンジ・スキャンをどこで開始し終了するかを判断できます。それにより、ブロックのすべてのエントリを読み取る必要性が回避されます。

関連項目:

索引ブロックの詳細は、『Oracle Database概要』を参照してください。

一意索引と非一意索引

非一意索引では、データベースはROWIDを格納するために、追加列としてROWIDをキーに付加したものを格納します。このエントリによって、キーが一意になる長さのバイト数が追加されます。

たとえば、図8-3に示された非一意の索引の最初の索引キーは、ペアの0,rowidであり、単なる0ではありません。データは索引キーの値でソートされてから、ROWIDの昇順でソートされます。たとえば、エントリは次のように並べ替えられます。

0,AAAPvCAAFAAAAFaAAa
0,AAAPvCAAFAAAAFaAAg
0,AAAPvCAAFAAAAFaAAl
2,AAAPvCAAFAAAAFaAAm

一意の索引では、索引キーにROWIDは含まれません。データは、0、1、2といった索引キーの値のみでソートされます。

関連項目:

一意および非一意の索引の概要は、『Oracle Database概要』を参照してください。

Bツリー索引およびNULL

Bツリー索引では、NULLキーはオプティマイザのアクセス・パスの選択方法として重要であるため、まったく格納されないというわけではありません。このルールの結果として、単一列Bツリー索引ではNULLは格納されません。

例を使って説明します。hr.employees表にはemployee_idに主キー索引があり、department_idに一意索引があります。department_id列はNULLを含むことができるNULL値可能列ですが、employee_id列はNULLを含むことはできません。

SQL> SELECT COUNT(*) FROM employees WHERE department_id IS NULL;

COUNT(*)
----------
1

SQL> SELECT COUNT(*) FROM employees WHERE employee_id IS NULL;

COUNT(*)
----------
0

次の例は、hr.employeesのすべての部門IDの問合せのためにオプティマイザが全表スキャンを選択することを示しています。オプティマイザは、表のすべての行にエントリがあるとは保証されていないため、employees.department_idで索引を使用することができません。

SQL> EXPLAIN PLAN FOR SELECT department_id FROM employees;

Explained.

SQL> SELECT PLAN_TABLE_OUTPUT FROM TABLE(DBMS_XPLAN.DISPLAY());

PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
Plan hash value: 3476115102

-------------------------------------------------------------------------------
| Id  | Operation         | Name      | Rows  | Bytes | Cost (%CPU)| Time     |
-------------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |           |   107 |   321 |     2   (0)| 00:00:01 |
|   1 |  TABLE ACCESS FULL| EMPLOYEES |   107 |   321 |     2   (0)| 00:00:01 |
-------------------------------------------------------------------------------

8 rows selected.

次の例は、NULL以外の列はすべて索引付けされるため、オプティマイザは特定の部門IDの問合せのためにdepartment_idの索引を使用できることを示しています。

SQL> EXPLAIN PLAN FOR SELECT department_id FROM employees WHERE department_id=10;

Explained.

SQL> SELECT PLAN_TABLE_OUTPUT FROM TABLE(DBMS_XPLAN.DISPLAY());

PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
Plan hash value: 67425611

--------------------------------------------------------------------------------
| Id| Operation        | Name              | Rows |Bytes| Cost (%CPU)| Time    |
--------------------------------------------------------------------------------

PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
| 0 | SELECT STATEMENT |                   |   1 |   3 |     1   (0)| 00:0 0:01|
|*1 |  INDEX RANGE SCAN| EMP_DEPARTMENT_IX |   1 |   3 |     1   (0)| 00:0 0:01|
--------------------------------------------------------------------------------

Predicate Information (identified by operation id):

PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
1 - access("DEPARTMENT_ID"=10)

次の例は、述語によってNULL値が除外される場合にオプティマイザは索引スキャンを選択することを示しています。

SQL> EXPLAIN PLAN FOR SELECT department_id FROM employees
WHERE department_id IS NOT NULL;

Explained.

SQL> SELECT PLAN_TABLE_OUTPUT FROM TABLE(DBMS_XPLAN.DISPLAY());

PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
Plan hash value: 1590637672

--------------------------------------------------------------------------------
| Id| Operation        | Name              | Rows|Bytes| Cost (%CPU)| Time     |
--------------------------------------------------------------------------------
| 0 | SELECT STATEMENT |                   | 106 | 318 |    1   (0)| 00:0 0:01 |
|*1 |  INDEX FULL SCAN | EMP_DEPARTMENT_IX | 106 | 318 |    1   (0)| 00:0 0:01 |
--------------------------------------------------------------------------------

Predicate Information (identified by operation id):

PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------

1 - filter("DEPARTMENT_ID" IS NOT NULL)

索引一意スキャン

索引一意スキャンはROWID 1までを返します。

オプティマイザが索引一意スキャンを考慮する場合

索引一意スキャンには、等価述語が必要です。

具体的には、次の条件が当てはまる場合にのみ、データベースは一意スキャンを実行します。

- 問合せ述語が、等価演算子を使用して一意索引キーのすべての列を参照する(WHERE prod_id=10など)。

- CREATE UNIQUE INDEX文で作成された索引によって参照される列に等価述語を含むSQL文がある。

一意キー制約または主キー制約のみでは、索引一意スキャンを作成するのに不十分です。非一意索引付きの列に主キー制約を作成し、結果として索引一意スキャンではなく索引レンジ・スキャンとなる例を考えてみます。

CREATE TABLE t_table(numcol INT);
CREATE INDEX t_table_idx ON t_table(numcol);
ALTER TABLE t_table ADD CONSTRAINT t_table_pk PRIMARY KEY(numcol);
SET AUTOTRACE TRACEONLY EXPLAIN
SELECT * FROM t_table WHERE numcol = 1;

Execution Plan
----------------------------------------------------------
Plan hash value: 868081059

--------------------------------------------------------------------------------
| Id  | Operation        | Name        | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------------
|   0 | SELECT STATEMENT |             |     1 |    13 |     1   (0)| 00:00:01 |
|*  1 |  INDEX RANGE SCAN| T_TABLE_IDX |     1 |    13 |     1   (0)| 00:00:01 |
--------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------
1 - access("NUMCOL"=1)

INDEX(alias index_name)ヒントを使用して使用する索引を指定できますが、特定の索引アクセス・パスは指定できません。

関連項目:

- 索引構造の詳細とBツリーの検索方法の詳細は、『Oracle Database概要』を参照してください。

- INDEXヒントの詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

索引一意スキャンの仕組み

このスキャンでは、指定したキーの索引を順番に検索します。索引の一意スキャンでは、2つ目のレコードがないことがわかっているため、最初のレコードが見つかるとただちに処理が停止します。データベースは索引エントリからROWIDを取得し、ROWIDで指定される行を取得します。

次の図は、索引一意スキャンを示しています。文は、主キー索引があるprod_id列の製品IDが19のレコードをリクエストします。

図8-4 索引一意スキャン

索引一意スキャン: 例

この例では、一意スキャンを使用してproducts表から行を取得します。

次の文は、sh.products表の製品19のレコードを問い合せます。

SELECT *
FROM   sh.products
WHERE  prod_id = 19;

products.prod_id列に主キー索引が存在し、WHERE句が等価演算子を使用してすべての列を参照するため、オプティマイザは一意スキャンを選択します。

SQL_ID  3ptq5tsd5vb3d, child number 0
-------------------------------------
select * from sh.products where prod_id = 19

Plan hash value: 4047888317

--------------------------------------------------------------------------------
| Id| Operation                   | Name        |Rows|Bytes|Cost (%CPU)|Time   |
--------------------------------------------------------------------------------
|  0| SELECT STATEMENT            |             |    |     |  1 (100)|         |
|  1|  TABLE ACCESS BY INDEX ROWID| PRODUCTS    |  1 | 173 |  1   (0)| 00:00:01|
|* 2|   INDEX UNIQUE SCAN         | PRODUCTS_PK |  1 |     |  0   (0)|         |
--------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

2 - access("PROD_ID"=19)

索引レンジ・スキャン

索引レンジ・スキャンは、値の順序付きスキャンです。

スキャンの範囲は、両側での境界スキャン、あるいは片側または両側での非有界スキャンとすることができます。オプティマイザは、通常、選択性の問合せにはレンジ・スキャンを選択します。

デフォルトでは、データベースは索引を昇順に格納し、それらのスキャンも同じ順序で行います。たとえば、述語department_id >= 20を含む問合せにはレンジ・スキャンが使用され、20、30、40といった索引キーでソートされた行が返されます。複数の索引エントリに同一のキーがある場合は、データベースはそれらをROWIDの昇順で返します。すなわち、0,AAAPvCAAFAAAAFaAAaの次に0,AAAPvCAAFAAAAFaAAgなどとなります。

索引レンジ・スキャン降順は、行が降順で戻されること以外、索引レンジ・スキャンと同じです。通常、降順スキャンが使用されるのは、データを降順に並べる場合か、指定された値より小さい値を検索する場合です。

関連項目:

選択性

オプティマイザが索引レンジ・スキャンを考慮する場合

索引レンジ・スキャンでは、複数の値を索引キーにできることが必要です。

具体的には、オプティマイザは次の状況で索引レンジ・スキャンを考慮します。

- 索引の1つ以上の先頭列を条件に指定します。
条件は、1つ以上の式および論理(ブール)演算子の組合せを指定し、TRUE、FALSEまたはUNKNOWNの値を戻します。次に、条件の例を示します。

- department_id = :id

- department_id < :id

- department_id > :id

- 索引の先頭列用の前述の条件のAND 組合せ(department_id > :low AND department_id < :hiなど)。

注意:

オプティマイザがレンジ・スキャンを考慮するために、col1 LIKE '%ASD'の形式のワイルド・カード検索は先頭に指定しないでください。

- 0個、1個、または複数の値を索引キーにできます。

ヒント:

ソートされたデータが必要な場合は、索引には依存せず、ORDER BY句を使用します。索引でORDER BY句を満たすことが可能な場合、オプティマイザはこのオプションを使用して、ソートを回避します。

索引でORDER BY DESCENDING句を満たすことが可能な場合、オプティマイザは索引レンジ・スキャン降順を考慮します。

オプティマイザが全表スキャンまたは別の索引を選択する場合、このアクセス・パスを強制するためにヒントが必要になる可能性があります。INDEX(tbl_alias ix_name)ヒントおよびINDEX_DESC(tbl_alias ix_name)ヒントは、特定の索引を使用するようにオプティマイザに指示します。

関連項目:

INDEXおよびINDEX_DESCヒントの詳細は、『Oracle Database SQL言語リファレンス』を参照してください

索引レンジ・スキャンの仕組み

索引レンジ・スキャン中、Oracle Databaseはルートからブランチに進みます。

一般に、スキャン・アルゴリズムは次のとおりです。

1. ルート・ブロックを読み取ります。

2. ブランチ・ブロックを読み取ります。

3. すべてのデータが取り出されるまで、次の手順を交互に行います。

a. リーフ・ブロックを読み取って、ROWIDを取得します。

b. 表ブロックを読み取って、行を取得します。

注意:

場合によっては、索引スキャンは索引ブロックのセットを読み取り、ROWIDをソートしてから、表ブロックのセットを読み取ります。

そのため、索引をスキャンするには、データベースではリーフ・ブロックを後方または前方に移動します。たとえば、20から40のIDを求めるスキャンでは、最小キー値20以上を含む最初のリーフ・ブロックが検索されます。40より大きい値が見つかるまで、スキャンはリンクされたリーフ・ノード・リストを水平に進み、その後停止します。

次の図は、昇順を使用した索引レンジ・スキャンを示しています。文は、department_id列(非一意索引を含む)の値が20のemployeesレコードをリクエストします。この例では、部門20には2つの索引エントリが存在します。

例8-5 索引レンジ・スキャン

索引レンジ・スキャン: 例

この例では、索引レンジ・スキャンを使用してemployees表から値のセットを取得します。

次の文は、給与が1000より多い、部門20の従業員のレコードを問い合せます。

SELECT *
FROM   employees
WHERE  department_id = 20
AND    salary > 1000;

この問合せはカーディナリティが低い(戻される行が少ない)ため、department_id列の索引が使用されます。データベースは索引をスキャンし、employees表からレコードをフェッチした後、salary > 1000フィルタをフェッチしたレコードに適用して結果を生成します。

SQL_ID  brt5abvbxw9tq, child number 0
-------------------------------------
SELECT * FROM   employees WHERE  department_id = 20 AND    salary > 1000

Plan hash value: 2799965532

-------------------------------------------------------------------------------------------
|Id | Operation                           | Name             |Rows|Bytes|Cost(%CPU)| Time |
-------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT                    |                  |    |     | 2 (100)|        |
|*1 |  TABLE ACCESS BY INDEX ROWID BATCHED| EMPLOYEES        |  2 | 138 | 2   (0)|00:00:01|
|*2 |   INDEX RANGE SCAN                  | EMP_DEPARTMENT_IX|  2 |     | 1   (0)|00:00:01|
-------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

1 - filter("SALARY">1000)
2 - access("DEPARTMENT_ID"=20)

索引レンジ・スキャン降順: 例

この例では、索引を使用して、employees表からソートされた順序で行を取得します。

次の文は、部門20の従業員のレコードを降順で問い合せます。

SELECT *
FROM   employees
WHERE  department_id < 20
ORDER BY department_id DESC;

この問合せはカーディナリティが低いため、department_id列の索引が使用されます。

SQL_ID  8182ndfj1ttj6, child number 0
-------------------------------------
SELECT * FROM   employees WHERE  department_id < 20 ORDER BY department_id DESC

Plan hash value: 1681890450
--------------------------------------------------------------------------------
|Id| Operation                    | Name           |Rows|Bytes|Cost(%CPU)|Time |
--------------------------------------------------------------------------------
| 0| SELECT STATEMENT             |                   |  |   | 2 (100)|        |
| 1|  TABLE ACCESS BY INDEX ROWID | EMPLOYEES         | 2|138| 2   (0)|00:00:01|
|*2|   INDEX RANGE SCAN DESCENDING| EMP_DEPARTMENT_IX | 2|   | 1   (0)|00:00:01|
--------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

2 - access("DEPARTMENT_ID"<20)

データベースは、20以下の最大キー値を含む、最初の索引リーフ・ブロックの位置を特定します。次に、スキャンはリンクされたリーフ・ノード・リストを左方向に水平に進みます。データベースは各索引エントリからROWIDを取得し、ROWIDで指定される行を取得します。

全索引スキャン

全索引スキャンは、索引全体を順に読み取ります。索引のデータは索引キー順に並んでいるため、全索引スキャンで個別のソート操作を排除できます。

オプティマイザが全索引スキャンを考慮する場合

オプティマイザは様々な状況で全索引スキャンを考慮します。

状況には、次のようなものがあります。

- 述語が索引の列を参照している。この列は先頭列である必要はありません。

- 述語は指定されていないが、次のすべての条件は満たしている。

- 表および問合せのすべての列は索引にある。

- 少なくとも1つの索引付き列がNULLではない。

- 問合せに、索引付きのNULL不可能列に対するORDER BYが含まれる。

全索引スキャンの仕組み

データベースはルート・ブロックを読み取り、リーフ・ブロックに到達するまで索引の左方向(または、降順全スキャンを行っている場合は右)に移動します。

データベースがリーフ・ブロックに到達すると、スキャンは一度に1ブロックずつ、ソートされた順序で下位の索引に進みます。データベースは、マルチブロックI/Oではなく単一ブロックI/Oを使用します。

次の図は、全索引スキャンを示しています。文は、department_idで並べられているdepartmentsレコードをリクエストします。

図8-6 全索引スキャン

全索引スキャン: 例

この例では、全索引スキャンを使用してORDER BY句で問合せを満たします。

次の文は、部門のIDと名前を部門ID順に問い合せます。

SELECT department_id, department_name
FROM   departments
ORDER BY department_id;

次の計画は、オプティマイザが全索引スキャンを選択することを示しています。

SQL_ID  94t4a20h8what, child number 0
-------------------------------------
select department_id, department_name from departments order by department_id

Plan hash value: 4179022242

--------------------------------------------------------------------------------
|Id | Operation                   | Name        |Rows|Bytes|Cost(%CPU)|Time    |
--------------------------------------------------------------------------------
| 0 | SELECT STATEMENT            |             |    |     | 2 (100)|          |
| 1 |  TABLE ACCESS BY INDEX ROWID| DEPARTMENTS | 27 | 432 | 2   (0)| 00:00:01 |
| 2 |   INDEX FULL SCAN           | DEPT_ID_PK  | 27 |     | 1   (0)| 00:00:01 |
--------------------------------------------------------------------------------

データベースは最初の索引リーフ・ブロックを特定し、リンクされたリーフ・ノード・リストを右方向に水平に進みます。各索引エントリについて、データベースはエントリからROWIDを取得し、ROWIDで指定される表の行を取得します。索引はdepartment_idでソートされるため、データベースは取得した行の個別のソート操作を回避します。

高速全索引スキャン

高速全索引スキャンは、ソートされていない索引ブロックをディスク上に存在しているとおりに読み取ります。このスキャンは表を調べるために索引を使用しませんが、基本的には索引自体を表のように使用しながら、表ではなく索引を読み取ります。

オプティマイザが高速全索引スキャンを考慮する場合

問合せが索引の属性のみにアクセスする場合、オプティマイザはこのスキャンを考慮します。

注意:

全スキャンとは異なり、高速全スキャンではソート操作を排除できません。これは索引を順番に読み取らないためです。

INDEX_FFS(table_name index_name)ヒントにより高速全索引スキャンが強制されます。

関連項目:

INDEXヒントの詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

高速全索引スキャンの仕組み

データベースは、マルチブロックI/Oを使用して、ルート・ブロックと、すべてのリーフ・ブロックおよびブランチ・ブロックを読み取ります。データベースは、ブランチ・ブロックとルート・ブロックを無視して、リーフ・ブロックの索引エントリを読み取ります。

高速全索引スキャン: 例

この例では、オプティマイザ・ヒントの結果として高速全索引スキャンを使用します。

次の文は、部門のIDと名前を部門ID順に問い合せます。

SELECT /*+ INDEX_FFS(departments dept_id_pk) */ COUNT(*)
FROM   departments;

次の計画は、オプティマイザが高速全索引スキャンを選択することを示しています。

SQL_ID  fu0k5nvx7sftm, child number 0
-------------------------------------
select /*+ index_ffs(departments dept_id_pk) */ count(*) from departments

Plan hash value: 3940160378
--------------------------------------------------------------------------
| Id | Operation             | Name       | Rows  |Cost (%CPU)| Time     |
--------------------------------------------------------------------------
|  0 | SELECT STATEMENT      |            |       |    2 (100)|          |
|  1 |  SORT AGGREGATE       |            |     1 |           |          |
|  2 |   INDEX FAST FULL SCAN| DEPT_ID_PK |    27 |    2   (0)| 00:00:01 |
--------------------------------------------------------------------------

索引スキップ・スキャン

索引スキップ・スキャンは、コンポジット索引の初期列が問合せでスキップされる(指定されない)場合に行われます。

関連項目:

『Oracle Database概要』

オプティマイザが索引スキップ・スキャンを考慮する場合

多くの場合、索引ブロックをスキャンするほうが、表データ・ブロックをスキャンしたり全索引スキャンを実行するより高速です。

次の基準が当てはまる場合、オプティマイザはスキップ・スキャンを考慮します。

- コンポジット索引の先頭列が問合せ述語で指定されていない。
たとえば、問合せ述語がcust_gender列を参照せず、コンポジット索引キーが(cust_gender,cust_email)の場合です。

- コンポジット索引の先頭列に個別値がほとんどなく、索引の非先頭キーに個別値が多数存在する。
たとえば、コンポジット索引キーが(cust_gender,cust_email)である場合、cust_gender列には個別値が2つしか存在しませんが、cust_emailには数千存在します。

索引スキップ・スキャンの仕組み

索引スキップ・スキャンは、コンポジット索引をさらに小さい副索引に論理的に分割します。

論理副索引の個数は、索引の先頭列にある個別値の数によって判断されます。個別値の数が少ないほど、オプティマイザが作成しなければならない論理副索引の数が少なくなり、スキャンはより効率的になります。スキャンは各論理索引を個別に読み取り、非先頭列に対するフィルタ条件に一致しない索引ブロックをスキップします。

索引スキップ・スキャン: 例

この例では、索引スキップ・スキャンを使用してcustomers表の問合せを満たします。

customers表にはcust_genderという列があり、この列の値はMまたはFです。次のとおり、列(cust_gender、cust_email)にコンポジット索引を作成します。

CREATE INDEX cust_gender_email_ix
ON sh.customers (cust_gender, cust_email);

概念上、索引の一部は、索引の先頭として性別の値にFまたはMを持つ次のような形式になります。

F,Wolf@company.example.com,rowid
F,Wolsey@company.example.com,rowid
F,Wood@company.example.com,rowid
F,Woodman@company.example.com,rowid
F,Yang@company.example.com,rowid
F,Zimmerman@company.example.com,rowid
M,Abbassi@company.example.com,rowid
M,Abbey@company.example.com,rowid

sh.customers表の顧客に対して次の問合せを実行します。

SELECT *
FROM   sh.customers
WHERE  cust_email = 'Abbey@company.example.com';

cust_genderはWHERE句で指定されていませんが、データベースでは、customers_gender_email索引のスキップ・スキャンを使用できます。サンプルの索引では、先頭列cust_genderに可能な値は2つ(FおよびM)あります。データベースは索引を論理的に2つに分割します。1つ目の副索引は、次の形式のエントリで、キーFを持ちます。

F,Wolf@company.example.com,rowid
F,Wolsey@company.example.com,rowid
F,Wood@company.example.com,rowid
F,Woodman@company.example.com,rowid
F,Yang@company.example.com,rowid
F,Zimmerman@company.example.com,rowid

2つ目の副索引は、次の形式のエントリで、キーMを持ちます。

M,Abbassi@company.example.com,rowid
M,Abbey@company.example.com,rowid

電子メールがAbbey@company.comの顧客のレコードを検索する場合、最初に先頭値Fを持つ副索引が検索され、次に先頭値Mを持つ副索引が検索されます。概念上、データベースで問合せが次のように処理されます。

( SELECT *
FROM   sh.customers
WHERE  cust_gender = 'F'
AND    cust_email = 'Abbey@company.com' )
UNION ALL
( SELECT *
FROM   sh.customers
WHERE  cust_gender = 'M'
AND    cust_email = 'Abbey@company.com' )

問合せの計画は次のようになります。

SQL_ID  d7a6xurcnx2dj, child number 0
-------------------------------------
SELECT * FROM   sh.customers WHERE  cust_email = 'Abbey@company.example.com'

Plan hash value: 797907791

-----------------------------------------------------------------------------------------
|Id| Operation                          | Name               |Rows|Bytes|Cost(%CPU)|Time|
-----------------------------------------------------------------------------------------
| 0|SELECT STATEMENT                    |                      |  |    |10(100)|        |
| 1| TABLE ACCESS BY INDEX ROWID BATCHED| CUSTOMERS            |33|6237|  10(0)|00:00:01|
|*2|  INDEX SKIP SCAN                   | CUST_GENDER_EMAIL_IX |33|    |   4(0)|00:00:01|
-----------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

2 - access("CUST_EMAIL"='Abbey@company.example.com')
filter("CUST_EMAIL"='Abbey@company.example.com')

関連項目:

スキップ・スキャンの詳細は、『Oracle Database概要』を参照してください。

索引結合スキャン

索引結合スキャンは、問合せによってリクエストされたすべての列をまとめて返す、複数の索引のハッシュ結合です。すべてのデータは索引から取得されるため、データベースは表にアクセスする必要がありません。

オプティマイザが索引結合スキャンを考慮する場合

場合によっては、表アクセスの回避は最もコスト効率がよいオプションとなります。

オプティマイザは、次の状況で索引結合を考慮します。

- 表アクセスの必要なしに、問合せでリクエストされたすべてのデータを複数索引のハッシュ結合によって取得する。

- 表から行を取得するコストは、表から行を取得せずに索引を読み込む場合よりも高い。索引結合はコストが高くなることがよくあります。たとえば、2つの索引をスキャンして結合する場合、最も選択的な索引を選択し、表を調べるほうがコストがかかりません。

INDEX_JOIN(table_name)ヒントを使用して索引結合を指定できます。

関連項目:

『Oracle Database SQL言語リファレンス』

索引結合スキャンの仕組み

索引結合では複数の索引がスキャンされ、そのスキャンから取得したROWIDでのハッシュ結合を使用して行を返します。

索引結合スキャンでは、表アクセスは常に回避されます。たとえば、1つの表の2つの索引を結合する処理は次のとおりです。

1. 最初の索引をスキャンしてROWIDを取得します。

2. 2番目の索引をスキャンしてROWIDを取得します。

3. ROWIDでのハッシュ結合を実行し、行を取得します。

索引結合スキャン: 例

次の文では、索引結合を指定して、姓がAで始まる従業員の姓、電子メールを問合せます。

SELECT /*+ INDEX_JOIN(employees) */ last_name, email
FROM   employees
WHERE  last_name like 'A%';

個別の索引が、(last_name,first_name)列およびemail列に存在します。emp_name_ix索引の一部は次のような形式です。

Banda,Amit,AAAVgdAALAAAABSABD
Bates,Elizabeth,AAAVgdAALAAAABSABI
Bell,Sarah,AAAVgdAALAAAABSABc
Bernstein,David,AAAVgdAALAAAABSAAz
Bissot,Laura,AAAVgdAALAAAABSAAd
Bloom,Harrison,AAAVgdAALAAAABSABF
Bull,Alexis,AAAVgdAALAAAABSABV

emp_email_uk索引の最初の部分は次のような形式です。

ABANDA,AAAVgdAALAAAABSABD
ABULL,AAAVgdAALAAAABSABV
ACABRIO,AAAVgdAALAAAABSABX
AERRAZUR,AAAVgdAALAAAABSAAv
AFRIPP,AAAVgdAALAAAABSAAV
AHUNOLD,AAAVgdAALAAAABSAAD
AHUTTON,AAAVgdAALAAAABSABL

例8-4では、DBMS_XPLAN.DISPLAY_CURSOR関数を使用して計画を取得します。データベースはemp_email_uk索引のすべてのROWIDを取得し、Aで始まる姓のemp_name_ixのROWIDを取得します。データベースはハッシュ結合を使用して、ROWIDの両方のセットから一致するものを探します。たとえば、ROWID AAAVgdAALAAAABSABDは両方のセットのROWIDに発生するので、データベースはこのROWIDに対応するレコードをemployees表から探します。

例8-4 索引結合スキャン

SQL_ID  d2djchyc9hmrz, child number 0
-------------------------------------
SELECT /*+ INDEX_JOIN(employees) */ last_name, email FROM   employees
WHERE  last_name like 'A%'

Plan hash value: 3719800892
-------------------------------------------------------------------------------------------
| Id  | Operation              | Name             | Rows  | Bytes | Cost (%CPU)| Time     |
-------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT       |                  |       |       |     3 (100)|          |
|*  1 |  VIEW                  | index$_join$_001 |     3 |    48 |     3  (34)| 00:00:01 |
|*  2 |   HASH JOIN            |                  |       |       |            |          |
|*  3 |    INDEX RANGE SCAN    | EMP_NAME_IX      |     3 |    48 |     1   (0)| 00:00:01 |
|   4 |    INDEX FAST FULL SCAN| EMP_EMAIL_UK     |     3 |    48 |     1   (0)| 00:00:01 |
-------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("LAST_NAME" LIKE 'A%')
2 - access(ROWID=ROWID)
3 - access("LAST_NAME" LIKE 'A%')

ビットマップ索引アクセス・パス

ビットマップ索引では、索引付けられたデータをROWID範囲と組み合せます。

この項では、ビットマップ索引、およびより頻繁に使われるビットマップ索引アクセス・パスについて説明します。

- ビットマップ索引アクセスについて

- ビットマップのROWIDへの変換

- ビットマップ索引単一値

- ビットマップ索引レンジ・スキャン

- ビットマップ・マージ

ビットマップ索引アクセスについて

従来型のBツリー索引では、1つの索引エントリは単一の行を指します。ビットマップ索引では、キーは索引付けられたデータとROWID範囲の組合せです。

データベースでは、索引キーごとに1つ以上のビットマップが格納されます。1および0 が連続するビットマップの各値は、ROWID範囲内の行を指します。したがって、ビットマップ索引では、索引エントリは単一の行ではなく行のセットを指します。

ビットマップ索引とBツリー索引の違い

ビットマップ索引はBツリー索引とは異なるキーを使用しますが、Bツリー構造で格納されます。

次の表では、索引エントリの種類における違いを示します。

表8-3 Bツリーおよびビットマップの索引エントリ

索引エントリ

キー

データ

例

一意のBツリー

索引付けられたデータのみ

ROWID

employees.employee_id列の索引エントリでは、社員ID 101がキーで、ROWID AAAPvCAAFAAAAFaAAaがデータです。

101,AAAPvCAAFAAAAFaAAa

一意ではないBツリー

ROWIDと組み合せた索引付けられたデータ

なし

employees.last_name列の索引エントリでは、名前とROWIDの組合せSmith,AAAPvCAAFAAAAFaAAaがキーで、データはありません。

Smith,AAAPvCAAFAAAAFaAAa

ビットマップ

ROWID範囲と組み合せた索引付けられたデータ

ビットマップ

customers.cust_gender列の索引エントリでは、M,low-rowid,high-rowidの部分がキーで、1および0の連続値がデータです。

M,low-rowid,high-rowid,1000101010101010

データベースでは、ビットマップ索引をBツリー構造に格納します。データベースでは、索引が定義される属性のセットであるキーの最初の部分のBツリーが即座に検索され、対応するROWID範囲とビットマップが取得されます。

関連項目:

- ビットマップ・ストレージ

- ビットマップ索引の概要は、『Oracle Database概要』を参照してください。

- ビットマップ索引の詳細は、『Oracle Databaseデータ・ウェアハウス・ガイド』を参照してください。

ビットマップ索引の目的

ビットマップ索引は、頻繁に変更されない個別のカーディナリティが低いデータに適しています。行の総数に対して列の個別値の数が少ない場合は、データのカーディナリティは低くなります。

一般に、Bツリー索引はカーディナリティが高いデータに適しています。オプティマイザは、ほとんど行を返さない問合せにBツリー索引を選択します。対照的に、ビットマップ索引は個別のカーディナリティが低いデータに適しています。customers.cust_gender列は、2つの個別値(MおよびF)とnullのみのため、ビットマップ索引の候補です。表に1億行が含まれる場合、全女性顧客に対する問合せは非選択性の問合せであるため、ビットマップ索引アクセスの候補です。ビットマップ索引は、圧縮技法によって最小限のI/Oで多数のROWIDを生成できます。

ビットマップ索引は、データ・ウェアハウス内の非定型問合せを高速化するために有用な方法です。特に、ビットマップ索引は次に該当する問合せで有用なアクセス・パスです。

- WHERE句に複数の条件がある
すべての条件ではなく一部の条件のみを満たす行は、表自体がアクセスされる前にデータベースによって除外されます。

- カーディナリティが低い列でAND、ORおよびNOT演算がある
カーディナリティの低い列でビットマップ索引を組み合せると、これらの演算の効率が高くなります。データベースでは、ビットマップ索引から即座にビットマップをマージできます。たとえば、ビットマップ索引がcustomersのcust_gender列およびcust_marital_status列にある場合、これらの索引により次の問合せのパフォーマンスが大幅に向上します。

SELECT *
FROM   customers
WHERE  cust_gender = 'M'
AND    cust_marital_status = 'single'

データベースでは、マージされたビットマップ内の1の値を効率的にROWIDに変換できます。

- COUNT関数
データベースでは、表をスキャンすることなくビットマップ索引をスキャンできます。

- NULL値を選択する述語
Bツリー索引と異なり、ビットマップ索引にNULLを含めることができます。列のnull数をカウントする問合せでは、表をスキャンせずにビットマップ索引を使用できます。

ビットマップ索引は、DMLが頻繁に使用される表には有用ではありません。理由は、1つの索引キーが多数の行を指しているためです。索引付けられたデータがセッションで変更される場合、データベースはビットマップ内の単一ビットをロックできず、索引エントリ全体をロックします。これにより、実際にはビットマップによりポイントされた行をロックします。たとえば、特定の顧客の婚姻ステータスがsingleからmarriedに変化した場合、データベースはビットマップ内のsingle索引エントリおよびmarried索引エントリに対する排他的アクセスを取得する必要があります。これらの2つの値を含む行は、COMMITまで変更できません。

関連項目:

COUNT関数の詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

ビットマップおよびROWID

ビットマップの各値は、行の値がビットマップ条件に一致する場合は1、一致しない場合は0になります。この値に基づいて、データベースの内部アルゴリズムによってビットマップがROWIDにマップされます。

ビットマップ・エントリには、索引付けられた値、ROWID範囲(開始ROWIDと終了ROWID)、およびビットマップが含まれます。ビットマップの0または1の各値は、ROWID範囲内のオフセットであり、行が存在しない場合でも、表の潜在行にマップされます。ブロック内の潜在行数は定義済のため、データベースでは、範囲のエンドポイントを使用して、範囲内の任意の行のROWIDを決定できます。

注意:

HAKAN要素は、Oracle Databaseによって単一ブロックに保存可能と見なされる行数を制限するために、ビットマップ索引アルゴリズムによって使用される最適化です。人為的に行数を制限することで、データベースでビットマップのサイズが削減されます。

表8-4は、NULL値可能なsh.customers.cust_marital_status列のサンプル・ビットマップの一部を示しています。実際の索引には12個の個別値があります。このサンプルでは、NULL、married、およびsingleの3つのみを示します。

表8-4 ビットマップ索引エントリ

cust_marital_statusの列値

範囲の開始ROWID

範囲の終了ROWID

範囲の最初の行

範囲の2番目の行

範囲の3番目の行

範囲の4番目の行

範囲の5番目の行

範囲の6番目の行

(null)

AAA ...

CCC ...

0

0

0

0

0

1

married

AAA ...

CCC ...

1

0

1

1

1

0

single

AAA ...

CCC ...

0

1

0

0

0

0

single

DDD ...

EEE ...

1

0

1

0

1

1

表8-4のように、Bツリー索引とは異なり、ビットマップ索引は、完全にNULL値からなるキーを含む場合があります。表8-4では、NULLにおいて範囲内の6番目の行の値が1です。これは、範囲内の6番目の行は、cust_marital_status値がNULLであることを意味します。NULLの索引作成は、集計関数COUNTによる問合せなど、一部のSQL文に使用できます。

関連項目:

『Oracle Database概要』には、ROWID形式が説明されています。

ビットマップ結合索引

ビットマップ結合索引は、2つ以上の表を結合するためのビットマップ索引です。

オプティマイザでビットマップ結合索引が使用され、計画実行中に結合する必要のあるデータの量が削減されるか、なくなります。ビットマップ結合索引は、保存時にマテリアライズド結合ビューよりも効率が大幅に向上します。

次の例では、sh.sales表およびsh.customers表にビットマップ索引が作成されます。

CREATE BITMAP INDEX cust_sales_bji ON sales(c.cust_city)
FROM sales s, customers c
WHERE c.cust_id = s.cust_id LOCAL;

先行のCREATE文のFROM句およびWHERE句は、表間の結合条件を示しています。customers.cust_city列が索引キーです。

索引の各キー値は、customers表に存在する可能性のある市を示しています。概念的には、索引のキー値は、1つのビットマップが各キー値に関連付けられ、次のようになります。

San Francisco   0 0 0 1 0 1 0 0 0 1 0 0 0 0 0 . . .
San Mateo       0 1 0 0 0 0 0 0 1 0 0 0 0 0 1 . . .
Smithville      1 0 0 0 1 0 0 1 0 0 1 0 1 0 0 . . .
.
.
.

ビットマップの各ビットは、sales表の1つの行に対応します。Smithvilleキーでは、値が1であると、sales表の最初の行がSmithvilleの顧客に販売された製品に対応します。値が0であると、2番目の行がSmithvilleの顧客に販売された製品に対応します。

Smithvilleの顧客への個別販売数に関する次の問合せを考慮します。

SELECT COUNT (*)
FROM   sales s, customers c
WHERE  c.cust_id = s.cust_id
AND    c.cust_city = 'Smithville';

次の計画では、データベースでSmithvilleビットマップが読み取られ、Smithvilleの販売数が抽出されます(手順4)。これにより、customersとsales表の結合はなくなります。

SQL_ID  57s100mh142wy, child number 0
-------------------------------------
SELECT COUNT (*) FROM sales s, customers c WHERE c.cust_id = s.cust_id
AND c.cust_city = 'Smithville'

Plan hash value: 3663491772

------------------------------------------------------------------------------------
|Id| Operation                    | Name |Rows|Bytes|Cost (%CPU)| Time|Pstart|Pstop|
------------------------------------------------------------------------------------
| 0| SELECT STATEMENT             |              |     |    |29 (100)|        | |  |
| 1|  SORT AGGREGATE              |              |   1 |   5|        |        | |  |
| 2|   PARTITION RANGE ALL        |              | 1708|8540|29   (0)|00:00:01|1|28|
| 3|    BITMAP CONVERSION COUNT   |              | 1708|8540|29   (0)|00:00:01| |  |
|*4|     BITMAP INDEX SINGLE VALUE|CUST_SALES_BJI|     |    |        |        |1|28|
------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

4 - access("S"."SYS_NC00008$"='Smithville')

関連項目:

CREATE INDEX文の詳細は、『Oracle Database概要』を参照してください。

ビットマップ・ストレージ

ビットマップ索引はBツリー構造で存在し、Bツリーと同じようにブランチ・ブロックおよびリーフ・ブロックを使用します。

たとえば、customers.cust_marital_status列に12の個別値がある場合、1つのブランチ・ブロックがmarried,rowid-rangeキーおよびsingle,rowid-rangeキーを指し、別のブランチ・ブロックがwidowed,rowid-rangeキーを指すといった状況があります。または、単一のブランチ・ブロックが12の個別キーすべてを含むリーフ・ブロックを指す場合もあります。

索引付けられた列値には、それぞれ1つ以上のビットマップ・ピースがあり、それぞれに1つ以上のエクステントの一連の近接行を占める独自のROWID範囲があります。データベースはビットマップ・ピースを使用し、ブロックのサイズに比べて大きい索引エントリを分割できます。たとえば、データベースは単一の索引エントリが3つのピースに分割し、最初の2ピースが同じエクステントの個別ブロック、最後のピースが別のエクステントの個別ブロックに分割できます。

領域を節約するために、Oracle Databaseでは連続した範囲の0値を圧縮できます。

ビットマップのROWIDへの変換

ビットマップ変換は、ビットマップのエントリと表の行の間で変換されます。この変換は、エントリから行(TO ROWID)、または行からエントリ(FROM ROWID)へと変換できます。

オプティマイザがビットマップのROWIDへの変換を選択する場合

オプティマイザでは、ビットマップ索引エントリを使用する表の行を取得時に必ず変換が使用されます。

ビットマップのROWIDへの変換の仕組み

概念上、ビットマップは表として表せます。

たとえば、表8-4は、customers行番号が列、cust_marital_status値が行の表として、ビットマップを表しています。表8-4の各フィールドには1または0の値があり、行の列値を表します。概念的には、ビットマップ変換では、「ビットマップのFフィールドが表のM番目のブロックのN番目の行に対応する」または「表のM番目のブロックのN番目の行がビットマップのFフィールドに対応する」という内部アルゴリズムが使用されます。

ビットマップのROWIDへの変換: 例

この例では、オプティマイザは範囲述語を使用した問合せを満たすためにビットマップの変換操作を選択します。

sh.customers表の問合せは、1918年より前に生まれたすべての顧客の名前を選択します。

SELECT cust_last_name, cust_first_name
FROM   customers
WHERE  cust_year_of_birth < 1918;

次の計画では、データベースがレンジ・スキャンを使用して1918より小さいすべてのキー値を検索し(手順3)、ビットマップの1の値をROWIDに変換し(手順2)、次に、ROWIDを使用してcustomers表から行を取得します(手順1)。

---------------------------------------------------------------------------------------------
|Id| Operation                           | Name             |Rows|Bytes|Cost(%CPU)| Time    |
---------------------------------------------------------------------------------------------
| 0| SELECT STATEMENT                    |                  |    |     |421 (100)|          |
| 1|  TABLE ACCESS BY INDEX ROWID BATCHED| CUSTOMERS        |3604|68476|421   (1)| 00:00:01 |
| 2|   BITMAP CONVERSION TO ROWIDS       |                  |    |     |         |          |
|*3|    BITMAP INDEX RANGE SCAN          | CUSTOMERS_YOB_BIX|    |     |         |          |
---------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------
3 - access("CUST_YEAR_OF_BIRTH"<1918)
filter("CUST_YEAR_OF_BIRTH"<1918)

ビットマップ索引単一値

この種類のアクセス・パスは、ビットマップ索引を使用して単一のキー値を検索します。

オプティマイザがビットマップ索引単一値を考慮する場合

述語に等価演算子が含まれる場合に、オプティマイザはこの種類のアクセス・パスを考慮します。

ビットマップ索引単一値の仕組み

問合せは単一ビットマップをスキャンして1の値を含む位置を調べます。データベースは1の値をROWIDに変換し、そのROWIDを使用して行を検索します。

データベースは単一のビットマップを処理することのみが必要です。たとえば、次の表はsh.customers.cust_marital_status列内の値widowedに対するビットマップ索引(2つのビットマップ・ピース)を表しています。ステータスがwidowedの顧客の問合せを満たすために、データベースはwidowedビットマップ内の1の値をそれぞれ検索し、対応する行のROWIDを見つけることができます。

表8-5 ビットマップ索引エントリ

列値

範囲の開始ROWID

範囲の終了ROWID

範囲の最初の行

範囲の2番目の行

範囲の3番目の行

範囲の4番目の行

範囲の5番目の行

範囲の6番目の行

widowed

AAA ...

CCC ...

0

1

0

0

0

0

widowed

DDD ...

EEE ...

1

0

1

0

1

1

ビットマップ索引単一値: 例

この例では、オプティマイザは等価述語を使用した問合せを満たすためにビットマップ索引の単一値演算を選択します。

sh.customers表の問合せは、すべてのwidowed顧客を選択します。

SELECT *
FROM   customers
WHERE  cust_marital_status = 'Widowed';

次の計画では、データベースがcustomersビットマップ索引のWidowedキーのエントリを読み取り(手順3)、ビットマップの1の値をROWIDに変換し(手順2)、次に、ROWIDを使用してcustomers表から行を取得します(手順1)。

SQL_ID  ff5an2xsn086h, child number 0
-------------------------------------
SELECT * FROM customers WHERE cust_marital_status = 'Widowed'

Plan hash value: 2579015045
---------------------------------------------------------------------------------------------
|Id| Operation                           | Name                |Rows|Bytes|Cost (%CPU)| Time|
---------------------------------------------------------------------------------------------
| 0| SELECT STATEMENT                    |                     |    |    |412 (100)|        |
| 1|  TABLE ACCESS BY INDEX ROWID BATCHED|CUSTOMERS            |3461|638K|412   (2)|00:00:01|
| 2|   BITMAP CONVERSION TO ROWIDS       |                     |    |    |         |        |
|*3|    BITMAP INDEX SINGLE VALUE        |CUSTOMERS_MARITAL_BIX|    |    |         |        |
---------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

3 - access("CUST_MARITAL_STATUS"='Widowed')

ビットマップ索引レンジ・スキャン

この種類のアクセス・パスは、ビットマップ索引を使用して値の範囲を検索します。

オプティマイザがビットマップ索引レンジ・スキャンを考慮する場合

述語で値の範囲が選択される場合に、オプティマイザはこの種類のアクセス・パスを検討します。

スキャンの範囲は、両側での境界スキャン、あるいは片側または両側での非有界スキャンとすることができます。オプティマイザは、通常、選択性の問合せにはレンジ・スキャンを選択します。

関連項目:

索引レンジ・スキャン

ビットマップ索引レンジ・スキャンの仕組み

このスキャンは、Bツリーのレンジ・スキャンと同じように機能します。

たとえば、次の表はsh.customers.cust_year_of_birth列に対するビットマップ索引の3つの値を表しています。問合せで1917年より前に生まれたすべての顧客をリクエストしている場合、データベースはこの索引で1917より低い値をスキャンして、1を持つ行のROWIDを取得します。

表8-6 ビットマップ索引エントリ

列値

範囲の開始ROWID

範囲の終了ROWID

範囲の最初の行

範囲の2番目の行

範囲の3番目の行

範囲の4番目の行

範囲の5番目の行

範囲の6番目の行

1913

AAA ...

CCC ...

0

0

0

0

0

1

1917

AAA ...

CCC ...

1

0

1

1

1

0

1918

AAA ...

CCC ...

0

1

0

0

0

0

1918

DDD ...

EEE ...

1

0

1

0

1

1

関連項目:

索引レンジ・スキャン

ビットマップ索引レンジ・スキャン: 例

この例では、レンジ・スキャンを使用して単一の年より前に生まれた顧客を選択します。

sh.customers表の問合せは、1918年より前に生まれた顧客の名前を選択します。

SELECT cust_last_name, cust_first_name
FROM   customers
WHERE  cust_year_of_birth < 1918

次の計画では、1918より小さいcust_year_of_birthキーのビットマップをすべて取得し(手順3)、ビットマップをROWIDに変換し(手順2)次に行を取得します(手順1)。

SQL_ID  672z2h9rawyjg, child number 0
-------------------------------------
SELECT cust_last_name, cust_first_name FROM   customers WHERE
cust_year_of_birth < 1918

Plan hash value: 4198466611
---------------------------------------------------------------------------------------------
|Id| Operation                           | Name              |Rows|Bytes|Cost(%CPU)|Time    |
---------------------------------------------------------------------------------------------
| 0| SELECT STATEMENT                    |                   |    |     |421 (100)|         |
| 1|  TABLE ACCESS BY INDEX ROWID BATCHED| CUSTOMERS         |3604|68476|421   (1)|00:00:01 |
| 2|   BITMAP CONVERSION TO ROWIDS       |                   |    |     |         |         |
|*3|    BITMAP INDEX RANGE SCAN          | CUSTOMERS_YOB_BIX |    |     |         |         |
---------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------
3 - access("CUST_YEAR_OF_BIRTH"<1918)
filter("CUST_YEAR_OF_BIRTH"<1918)

ビットマップ・マージ

このアクセス・パスは複数のビットマップを結合し、単一のビットマップを結果として返します。

ビットマップ・マージが、実行計画のBITMAP MERGE操作により示されています。

オプティマイザがビットマップ・マージを考慮する場合

通常、オプティマイザはビットマップ・マージを使用して、ビットマップ索引レンジ・スキャンにより生成されたビットマップを結合します。

ビットマップ・マージの仕組み

結合では、2つのビットマップ間でブールOR演算が使用されます。結果のビットマップでは、最初のビットマップのすべての行が選択され、さらに後続のすべてのビットマップのすべての行も選択されます。

問合せが1918年より前に生まれたすべての顧客を選択する場合があります。次の例では、3つのcustomers.cust_year_of_birthキー1917、1916、および1915のサンプル・ビットマップを示します。ビットマップのいずれかの位置に1があれば、結合ビットマップの同じ位置が1になります。それ以外の場合は、結合ビットマップは0になります。

1917     1 0 1 0 0 0 0 0 0 0 0 0 0 1
1916     0 1 0 0 0 0 0 0 0 0 0 0 0 0
1915     0 0 0 0 0 0 0 0 1 0 0 0 0 0
------------------------------------
merged:  1 1 1 0 0 0 0 0 1 0 0 0 0 1

結果のビットマップにある1の値が、1915、1916または1917の値を含む行に対応します。

ビットマップ・マージ: 例

この例は、範囲述語を使用した問合せを最適化するためにデータベースがビットマップをマージする方法を示しています。

sh.customers表の問合せは、1918年より前に生まれた女性の顧客の名前を選択します。

SELECT cust_last_name, cust_first_name
FROM   customers
WHERE  cust_gender = 'F'
AND    cust_year_of_birth < 1918

次の計画では、1918より小さいcust_year_of_birthキーのビットマップをすべて取得し(手順6)、これらのビットマップをORロジックを使用してマージして単一のビットマップを作成します(手順5)。データベースは、Fのcust_genderキーに対する単一のビットマップを取得し(手順4)、これらの2つのビットマップにAND演算を実行します。結果は、リクエストされた行に対して1の値を含む単一のビットマップです(手順3)。

SQL_ID  1xf59h179zdg2, child number 0
-------------------------------------
select cust_last_name, cust_first_name from customers where cust_gender
= 'F' and cust_year_of_birth < 1918

Plan hash value: 49820847
---------------------------------------------------------------------------------------------
|Id| Operation                           | Name               |Rows|Bytes|Cost(%CPU)| Time  |
---------------------------------------------------------------------------------------------
| 0| SELECT STATEMENT                    |                    |    |     |288 (100)|        |
| 1|  TABLE ACCESS BY INDEX ROWID BATCHED|CUSTOMERS           |1802|37842|288   (1)|00:00:01|
| 2|   BITMAP CONVERSION TO ROWIDS       |                    |    |     |         |        |
| 3|    BITMAP AND                       |                    |    |     |         |        |
|*4|     BITMAP INDEX SINGLE VALUE       |CUSTOMERS_GENDER_BIX|    |     |         |        |
| 5|     BITMAP MERGE                    |                    |    |     |         |        |
|*6|      BITMAP INDEX RANGE SCAN        |CUSTOMERS_YOB_BIX   |    |     |         |        |
---------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------
4 - access("CUST_GENDER"='F')
6 - access("CUST_YEAR_OF_BIRTH"<1918)
filter("CUST_YEAR_OF_BIRTH"<1918)

表クラスタ・アクセス・パス

表クラスタとは、共通の列を共有し、関連するデータを同じブロックに格納する表のグループのことです。表がクラスタ化されると、1つのデータ・ブロックに複数の表の行を含めることができます。

この項の内容は次のとおりです。

- クラスタ・スキャン

- ハッシュ・スキャン

関連項目:

表クラスタの概要は、『Oracle Database概要』を参照してください。

クラスタ・スキャン

索引クラスタとは、索引を使用してデータを検索する表クラスタのことです。

クラスタ索引とは、クラスタ・キーのBツリー索引のことです。クラスタ・スキャンでは、索引クラスタに格納された表から、同じクラスタ・キー値を持つすべての行が取得されます。

オプティマイザがクラスタ・スキャンを考慮する場合

索引付きクラスタの表に問合せがアクセスする場合に、クラスタ・スキャンが考慮されます。

クラスタ・スキャンの仕組み

索引クラスタでは、同じクラスタ・キー値を持つすべての行が同じデータ・ブロックに格納されます。

たとえば、hr.employees2表およびhr.departments2表がemp_dept_clusterでクラスタ化され、クラスタ・キーがdepartment_idの場合、データベースに格納されるのは、同じブロックの部門10のすべての従業員、同じブロックの部門20のすべての従業員などになります。

Bツリー・クラスタ索引は、データを含むブロックのデータベース・ブロック・アドレス(DBA)にクラスタ・キー値を関連付けます。たとえば、キー30の索引エントリには、部門30の従業員の行を含むブロックのアドレスが表示されます。

30,AADAAAA9d

ユーザーがクラスタの行を要求すると、データベースは索引をスキャンしてその行を含むブロックのDBAを取得します。次に、このDBAに基づいて行の位置を特定します。

クラスタ・スキャン: 例

この例では、department_id列でemployees表とdepartments表をクラスタ化し、単一部門のクラスタを問い合せます。

ユーザーhrとして、表クラスタ、クラスタ索引、およびクラスタの表を次のように作成します。

CREATE CLUSTER employees_departments_cluster
(department_id NUMBER(4)) SIZE 512;

CREATE INDEX idx_emp_dept_cluster
ON CLUSTER employees_departments_cluster;

CREATE TABLE employees2
CLUSTER employees_departments_cluster (department_id)
AS SELECT * FROM employees;
CREATE TABLE departments2
CLUSTER employees_departments_cluster (department_id)
AS SELECT * FROM departments;

部門30の従業員を次のように問い合せます。

SELECT *
FROM   employees2
WHERE  department_id = 30;

このスキャンでは、Oracle Databaseは最初にクラスタ索引をスキャンし、部門30を示す行のROWIDを取得します(手順2)。次に、このROWIDを使用してemployees2の行の位置を特定します(手順1)。

SQL_ID  b7xk1jzuwdc6t, child number 0
-------------------------------------
SELECT * FROM employees2 WHERE department_id = 30

Plan hash value: 49826199

--------------------------------------------------------------------------------
|Id| Operation            | Name               |Rows|Bytes|Cost(%CPU)| Time    |
--------------------------------------------------------------------------------
| 0| SELECT STATEMENT     |                    |    |     |   2 (100)|         |
| 1|  TABLE ACCESS CLUSTER| EMPLOYEES2         |  6 | 798 |   2   (0)| 00:00:01|
|*2|   INDEX UNIQUE SCAN  |IDX_EMP_DEPT_CLUSTER|  1 |     |   1   (0)| 00:00:01|
--------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

2 - access("DEPARTMENT_ID"=30)

関連項目:

索引付きクラスタの詳細は、『Oracle Database概要』を参照してください。

ハッシュ・スキャン

ハッシュ・クラスタは、索引キーがハッシュ関数に置き換わることを除いて、索引付きクラスタと似ています。別個のクラスタ索引は存在しません。

ハッシュ・クラスタでは、データが索引になります。ハッシュ・スキャンでは、ハッシュ値に基づいてハッシュ・クラスタ内の行の位置を特定します。

オプティマイザがハッシュ・スキャンを考慮する場合

ハッシュ・クラスタの表に問合せがアクセスする場合に、ハッシュ・スキャンが考慮されます。

ハッシュ・スキャンの仕組み

ハッシュ・クラスタ内においては、同一のハッシュ値を持つすべての行が同じデータ・ブロックに格納されています。

クラスタのハッシュ・スキャンを実行するには、最初に、文で指定されたクラスタ・キー値にハッシュ関数を適用することによって、ハッシュ値を取得します。次に、Oracle Databaseはこのハッシュ値の行を含むデータ・ブロックをスキャンします。

ハッシュ・スキャン: 例

この例では、department_id列でemployees表とdepartments表をハッシュし、単一部門のクラスタを問い合せます。

ハッシュ・クラスタおよびクラスタの表を次のように作成します。

CREATE CLUSTER employees_departments_cluster
(department_id NUMBER(4)) SIZE 8192 HASHKEYS 100;

CREATE TABLE employees2
CLUSTER employees_departments_cluster (department_id)
AS SELECT * FROM employees;

CREATE TABLE departments2
CLUSTER employees_departments_cluster (department_id)
AS SELECT * FROM departments;

部門30の従業員を次のように問い合せます。

SELECT *
FROM   employees2
WHERE  department_id = 30

ハッシュ・スキャンを実行するには、最初に、キー値30にハッシュ関数を適用することによって、ハッシュ値を取得し、次に、そのハッシュ値を使用してデータ・ブロックをスキャンし、行を取得します(手順1)。

SQL_ID  919x7hyyxr6p4, child number 0
-------------------------------------
SELECT * FROM employees2 WHERE department_id = 30

Plan hash value: 2399378016

----------------------------------------------------------------
| Id  | Operation         | Name       | Rows  | Bytes | Cost  |
----------------------------------------------------------------
|   0 | SELECT STATEMENT  |            |       |       |     1 |
|*  1 |  TABLE ACCESS HASH| EMPLOYEES2 |    10 |  1330 |       |
----------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

1 - access("DEPARTMENT_ID"=30)

関連項目:

ハッシュ・クラスタの詳細は、『Oracle Database概要』を参照してください。

9 結合

Oracle Databaseでは、行セットの結合の最適化が提供されます。

この章の内容は次のとおりです。

- 結合について

- 結合方法

- 結合タイプ

- 結合の最適化

結合について

結合によって、表やビューなどの2つの行ソースの出力が結合され、1つの行ソースが返されます。返される行ソースはデータ・セットです。

結合の特徴は、SQL文のWHERE (非ANSI)句内またはFROM ... JOIN (ANSI)句内に複数の表が並んでいる点です。FROM句に複数の表が指定されている場合は、必ず結合が実行されます。

結合条件によって、式を使用して2つの行ソースが比較されます。結合条件で、表間の関係が定義されます。文に結合条件が指定されていない場合は、デカルト結合が実行され、一方の表のすべての行が他方の表のすべての行と照合されます。

関連項目:

- デカルト結合

- Oracle SQLにおける結合の簡潔な説明は、『Oracle Database SQL言語リファレンス』を参照してください。

結合ツリー

通常、結合ツリーは上下逆のツリー構造で表されます。

次の図に示すように、table1が左表、table2が右表です。オプティマイザによって、結合は左から右に処理されます。たとえば、この図がネステッド・ループ結合を示しているならば、table1が外部ループでtable2が内部ループです。

図9-1 結合ツリー

結合の入力は、以前の結合の結果セットの場合もあります。結合ツリーの各内部ノードの右の子が表の場合、次の例に示すように、ツリーは左側の深い結合ツリーとなります。ほとんどの結合ツリーは、左側の深い結合です。

図9-2 左側の深い結合ツリー

結合ツリーの各内部ノードの左の子が表の場合、次の図に示すように、ツリーは右側の深い結合ツリーと呼ばれます。

図9-3 右側の深い結合ツリー

結合ツリーの内部ノードの左または右の子を結合ノードにできる場合、そのツリーはブッシュ型結合ツリーと呼ばれます。次の例で、table4は結合ノードの右の子、table1は結合ノードの左の子、table2は結合ノードの左の子です。

図9-4 ブッシュ型結合ツリー

さらにもう1つのバリエーションでは、結合の両側の入力が以前の結合の結果になります。

オプティマイザによる結合文の実行方法

データベースでは、行ソースのペアが結合されます。FROM句に複数の表が指定されている場合は、各ペアにとってどの結合操作が最も効率的かが、オプティマイザによって決定されます。

オプティマイザによって、次の相関的な決定が下される必要があります。

- アクセス・パス
単純な文では、オプティマイザは、結合文の各表からデータを取り出すアクセス・パスを選択する必要があります。たとえば、全表スキャンが選択される場合や索引スキャンが選択される場合があります。「オプティマイザのアクセス・パス」を参照してください。

- 結合方法
行ソースの各ペアを結合するためには、いかに結合するかが決定される必要があります。いかに、とは結合方法のことです。有効な結合方法には、ネステッド・ループ結合、ソート/マージ結合およびハッシュ結合があります。デカルト結合には前述の結合方法のいずれかが必要です。それぞれの結合方法は、特定の状況において他の結合方法より優れています。「結合方法」を参照してください。

- 結合タイプ
結合条件によって結合タイプが決定されます。たとえば、内部結合では結合条件に一致した行のみが取得されます。外部結合では結合条件に一致しない行も取得されます。「結合タイプ」を参照してください。

- 結合順序
Oracle Databaseでは、3つ以上の表を結合する文を実行する場合、2つの表を結合し、その結果作成された行ソースを次の表に結合します。このプロセスは、すべての表が結合されて結果が生成されるまで続きます。たとえば、2つの表が結合され、その結果が3つ目の表に結合され、その結果が4つ目の表に結合され、これが繰り返されます。

オプティマイザによる結合の実行計画の選択方法

結合順序および結合方法を決定する際、オプティマイザの目標は、SQL文の実行全体で行われる作業が少なくなるように、早期に行数を減らすことです。

オプティマイザは、適用可能な結合順序、結合方法および使用可能なアクセス・パスに従って実行計画のセットを生成します。次に、オプティマイザは各計画のコストを見積り、コストが最も小さいものを選択します。オプティマイザによって実行計画が選択される場合、次の要素が考慮されます。

- 2つ以上の表を結合した結果が、最大1行の行ソースになるかどうかが最初に判断されます。
オプティマイザは、このような状況を表のUNIQUE制約およびPRIMARY KEY制約に基づいて認識します。このような状況が存在する場合、オプティマイザはこれらの表を結合順序の最初に並べます。その後で、残りの表の結合を最適化します。

- 外部結合条件を持つ結合文では、外部結合演算子のある表の結合順序は、通常、条件内のその他の表の後になります。
一般には、このガイドラインに違反する結合順序が考慮されることはありませんが、特定の状況では、この順序付け条件がオーバーライドされます。同様に、副問合せがアンチ結合またはセミ結合に変換されたときは、その副問合せからの表は、それらが接続または相互に関連付けされた外部問合せブロック内の表の後に置きます。ただし、ある環境では、ハッシュ・アンチ結合およびセミ結合はこの順序条件を上書きできます。

オプティマイザは、推定のI/OおよびCPUを計算することによって、問合せ計画のコストを見積ります。これらのI/Oには、付随する固有のコストがあり、単一ブロックI/OのコストとマルチブロックI/Oのコストは違います。また、異なる関数と式には、それぞれに付随するCPUコストがあります。これらのメトリックが使用されて、問合せ計画の合計コストが決定されます。これらのメトリックは、多くの初期化パラメータやセッション設定(DB_FILE_MULTI_BLOCK_READ_COUNT設定やシステム統計など)からコンパイル時に影響を受ける可能性があります。

たとえば、オプティマイザによるコストの推定は次のように行われます。

- ネステッド・ループ結合のコストは、外部表で選択されている各行およびその行に対する内部表の一致行をメモリーに読み取るコストによって決まります。オプティマイザは、データ・ディクショナリ内の統計を使用してこれらのコストを見積ります。

- ソート/マージ結合のコストは、主に、すべてのソースをメモリーに読み取ってソートするコストによって決まります。

- ハッシュ結合のコストは、主に、結合への入力側の1つ上にハッシュ表を作成するコストと、それを調べるために結合のもう一方の側からの行を使用するコストによって決まります。

例9-1 結合順序および結合方法のコストの見積り

概念上、オプティマイザは、結合順序および結合方法と、それぞれに関連するコストのマトリックスを構成します。たとえば、オプティマイザは、表date_dimとlineorderを問合せで結合するための最良の方法を決定する必要があります。次の表は、方法および順序の可能なバリエーションと、それぞれのコストを示しています。この例では、date_dim、lineorderの順序のネステッド・ループ結合は、最もコストが低くなります。

Table 9-1 表date_dimおよびlineorderの結合のコストの例

結合方法

date_dim、lineorderのコスト

lineorder、date_dimのコスト

ネステッド・ループ

39,480

6,187,540

ハッシュ結合

187,528

194,909

ソート/マージ

217,129

217,129

関連項目:

- 「オプティマイザ統計の概要」

- オプティマイザ・ヒントの詳細は、「オプティマイザへの影響」を参照してください。

- DB_FILE_MULTIBLOCK_READ_COUNTの詳細は、『Oracle Databaseリファレンス』を参照してください。

結合方法

結合方法は、2つの行ソースを結合するメカニズムです。統計に従って、推定コストの最も低い方法がオプティマイザによって選択されます。

図9-5に示すように、各結合方法には2つの子があります: 駆動(外部とも呼ばれる)行ソースおよび被駆動(内部とも呼ばれる)行ソースです。

図9-5 結合方法

この項の内容は次のとおりです。

- ネステッド・ループ結合

- ハッシュ結合

- ソート/マージ結合

- デカルト結合

ネステッド・ループ結合

ネステッド・ループは、外部データ・セットを内部データ・セットに結合します。単一表述語に一致する外部データ・セットの各行に対して、結合述語を満たす内部データ・セットのすべての行が取得されます。索引が使用可能な場合は、索引を使用して行IDで内部データ・セットにアクセス可能です。

この項の内容は次のとおりです。

- オプティマイザがネステッド・ループ結合を考慮する場合

- ネステッド・ループ結合の仕組み

- ネステッド・ループのネスト

- ネステッド・ループ結合の現在の実装

- ネステッド・ループ結合の従来の実装

- ネステッド・ループの制御

オプティマイザがネステッド・ループ結合を考慮する場合

ネステッド・ループ結合は、データの小さなサブセットが結合されるか、オプティマイザ・モードがFIRST_ROWSに設定されて大きなデータ・セットが結合されるか、結合条件が内部表にアクセスする効率的な方法である場合に便利です。

注意:

オプティマイザの判断要因は、元になる表のサイズではなく、結合から予想される行数です。たとえば、それぞれが10億行を持つ2つの表を結合する問合せにおいても、フィルタのために、オプティマイザで予想されているデータ・セット数は各表で5行の場合があります。

一般に、ネステッド・ループ結合は、結合条件の索引を持つ小さな表で最適に動作します。主キー値による等価検索(たとえば、WHERE employee_id=101など)と同様に、行ソースに1行しかない場合、この結合は単純な検索です。オプティマイザでは、常に最小の行ソースを駆動表として、その処理が最初に試みられます。

オプティマイザでネステッド・ループの使用が決定されるには、様々な要素が関係します。たとえば、1つのバッチで外部行ソースから複数行が読み取られるとします。オプティマイザで、内部行ソースに対してネステッド・ループ結合が選択されるかハッシュ結合が選択されるかは、取得される行数に基づいて決定される可能性があります。たとえば、問合せでdepartmentsを駆動表employeesに結合し、述語にemployees.last_nameの値を指定する場合、last_nameの索引から、内部しきい値を超えたかどうかを判断するのに十分なエントリが読み取られることがあります。しきい値を超えていない場合は、departmentsに対してネステッド・ループ結合が選択され、しきい値を超えている場合は、ハッシュ結合が実行されます(つまり、employeesの残りが読み取られてメモリーにハッシュされてからdepartmentsに結合されます)。

内部ループのアクセス・パスが外部ループに依存していない場合は、結果はデカルト積になる可能性があり、外部ループの反復ごとに、内部ループで同じ行セットが生成されます。この問題を回避するには、2つの独立した行ソースの結合には、他の結合方法を使用することをお薦めします。

関連項目:

- 表14-1

- 「適応問合せ計画」

ネステッド・ループ結合の仕組み

概念上、ネステッド・ループは、ネストされた2つのforループと同等です。

たとえば、問合せでemployeesとdepartmentsが結合される場合、擬似コードでネステッド・ループを表すと次のようになります。

FOR erow IN (select * from employees where X=Y) LOOP
FOR drow IN (select * from departments where erow is matched) LOOP
output values from erow and drow
END LOOP
END LOOP

内部ループは、外部ループの各行ごとに実行されます。employees表が外部データ・セットと呼ばれるのは、それが外側のforループであるためです。外部表は、駆動表と呼ばれることもあります。departments表が内部データ・セットと呼ばれるのは、それが内側のforループであるためです。

ネステッド・ループ結合には、次の基本手順が含まれます。

1. オプティマイザによって駆動行ソースが決定され、これが外部ループに指定されます。
外部ループによって、結合条件を駆動するための行のセットが生成されます。行ソースは、索引スキャン、全表スキャン、または行を生成するその他の操作を使用してアクセスされる表の可能性があります。

内部ループの反復の数は、外部ループで取得された行の数に依存します。たとえば、外部表から10行が取得された場合、データベースは内部表で10回の検索を実行する必要があります。外部表から10,000,000行が取得された場合、データベースは内部表で10,000,000回の検索を実行する必要があります。

2. オプティマイザによって、他方の行ソースが内部ループに指定されます。
次のように、外部ループは実行計画の内部ループの前に表示されます。

NESTED LOOPS
outer_loop
inner_loop

3. クライアントからのフェッチ・リクエストごとの基本的なプロセスは次のとおりです。

a. 外部行ソースから行がフェッチされます。

b. 内部行ソースがプローブされ、述語基準に一致する行が検索されます。

c. フェッチ・リクエストによってすべての行が取得されるまで、この手順が繰り返されます。

より効率的なバッファ・アクセス・パターンを取得するために、行IDがソートされる場合もあります。

ネステッド・ループのネスト

ネステッド・ループの外部ループ自体を、別のネステッド・ループから生成される行ソースにすることが可能です。2つ以上の外部ループをネストして、必要なだけ表を結合できます。各ループはデータ・アクセス方法です。

次のテンプレートで、3つのネステッド・ループが反復処理される方法を示します。

SELECT STATEMENT
NESTED LOOPS 3
NESTED LOOPS 2          - Row source becomes OUTER LOOP 3.1
NESTED LOOPS 1        - Row source becomes OUTER LOOP 2.1
OUTER LOOP 1.1
INNER LOOP 1.2
INNER LOOP 2.2
INNER LOOP 3.2

次の順序でループが行われます。

1. NESTED LOOPS 1が反復されます。

NESTED LOOPS 1
OUTER LOOP 1.1
INNER LOOP 1.2

NESTED LOOP 1の出力は行ソースです。

2. NESTED LOOPS 1で生成された行ソースを外部ループに使用して、NESTED LOOPS 2が反復されます。

NESTED LOOPS 2
OUTER LOOP 2.1         - Row source generated by NESTED LOOPS 1
INNER LOOP 2.2

NESTED LOOP 2の出力は別の行ソースです。

3. NESTED LOOPS 2で生成された行ソースを外部ループに使用して、NESTED LOOPS 3が反復されます。

NESTED LOOPS 3
OUTER LOOP 3.1         - Row source generated by NESTED LOOPS 2
INNER LOOP 3.2

例9-2 ネステッド・ループ結合のネスト

次のようにemployees表とdepartments表を結合するとします。

SELECT /*+ ORDERED USE_NL(d) */ e.last_name, e.first_name, d.department_name
FROM   employees e, departments d
WHERE  e.department_id=d.department_id
AND    e.last_name like 'A%';

計画からは、オプティマイザによって2つのネステッド・ループ(手順1および手順2)が、データへのアクセスに選択されることがわかります。

SQL_ID  ahuavfcv4tnz4, child number 0
-------------------------------------
SELECT /*+ ORDERED USE_NL(d) */ e.last_name, d.department_name FROM
employees e, departments d WHERE  e.department_id=d.department_id AND
e.last_name like 'A%'

Plan hash value: 1667998133

----------------------------------------------------------------------------------
|Id| Operation                             |Name      |Rows|Bytes|Cost(%CPU)|Time|
----------------------------------------------------------------------------------
| 0| SELECT STATEMENT                      |             |  |   |5 (100)|        |
| 1|  NESTED LOOPS                         |             |  |   |       |        |
| 2|   NESTED LOOPS                        |             | 3|102|5   (0)|00:00:01|
| 3|    TABLE ACCESS BY INDEX ROWID BATCHED| EMPLOYEES   | 3| 54|2   (0)|00:00:01|
|*4|     INDEX RANGE SCAN                  | EMP_NAME_IX | 3|   |1   (0)|00:00:01|
|*5|    INDEX UNIQUE SCAN                  | DEPT_ID_PK  | 1|   |0   (0)|        |
| 6|   TABLE ACCESS BY INDEX ROWID         | DEPARTMENTS | 1| 16|1   (0)|00:00:01|
----------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

4 - access("E"."LAST_NAME" LIKE 'A%')
filter("E"."LAST_NAME" LIKE 'A%')
5 - access("E"."DEPARTMENT_ID"="D"."DEPARTMENT_ID")

この例では、基本的なプロセスは次のとおりです。

1. 内部ネステッド・ループの反復処理(手順2)が、次のように開始されます。

a. Aで始まるすべての姓の行IDが、emp_name_ixで検索されます(手順4)。
次に例を示します。

Abel,employees_rowid
Ande,employees_rowid
Atkinson,employees_rowid
Austin,employees_rowid

b. 前の手順で検索された行IDを使用して、employees表から行バッチが取得されます(手順3)。次に例を示します。

Abel,Ellen,80
Abel,John,50

これらの行が、最も内部のネステッド・ループの外部行ソースになります。

バッチ手順は、通常、適応実行計画に含まれます。ネステッド・ループがハッシュ結合より適しているかどうかを判断するには、行ソースから多くの行が返されるかどうかを判断する必要があります。返される行が多すぎる場合は、オプティマイザによって別の結合方法に切り替えられます。

c. 外部行ソースの各行について、一致する部門IDのdepartmentsにおける行IDを取得するためにdept_id_pk索引がスキャンされ(手順5)、それがemployees行に結合されます。次に例を示します。

Abel,Ellen,80,departments_rowid
Ande,Sundar,80,departments_rowid
Atkinson,Mozhe,50,departments_rowid
Austin,David,60,departments_rowid

これらの行が、外部ネステッド・ループの外部行ソースになります(手順1)。

2. 外部ネステッド・ループは、次のように反復処理されます。

a. 外部行ソースの最初の行が読み取られます。
次に例を示します。

Abel,Ellen,80,departments_rowid

b. departments行IDが使用されてdepartmentsから該当する行が取得され(手順6)、その結果が結合されてリクエストされた値が取得されます(手順1)。
次に例を示します。

Abel,Ellen,80,Sales

c. 外部行ソースから次の行が読み取られ、departments行IDが使用されてdepartmentsから該当する行が取得され(手順6)、すべての行が取得されるまでこのループが反復されます。
結果セットは次の形式になります。

Abel,Ellen,80,Sales
Ande,Sundar,80,Sales
Atkinson,Mozhe,50,Shipping
Austin,David,60,IT

ネステッド・ループ結合の現在の実装

Oracle Database 11gでは、新しいネステッド・ループ結合の実装が導入され、物理I/Oの全体の待機時間が短縮されました。バッファ・キャッシュに索引または表ブロックが存在せず、結合の処理に必要な場合、物理I/Oが必要となります。一度に1つのリクエストではなく、ベクターI/O(配列)を使用して複数の物理I/Oリクエストをまとめて処理できます。データベースは行IDの配列をオペレーティング・システムに送信し、読取りを実行します。

新規の実装の一環として、NESTED LOOPS結合の2つの行ソースが実行計画に表示されます(以前のリリースでは1行のみが表示されていました)。この場合、Oracle Databaseでは結合の外部側の表の値と内部側の索引とを結合するためにNESTED LOOPS結合の1つの行ソースを割り当てます。もう1つの行ソースは、最初の結合の結果を結合するために割り当てられます。これにより、索引に格納されている行IDが含まれ、結合の内部側に表が存在します。

「ネステッド・ループ結合の従来の実装」の問合せについて考えます。現在の実装では、この問合せの実行計画は次のようになります。

-------------------------------------------------------------------------------------
| Id | Operation                    | Name              |Rows|Bytes|Cost%CPU| Time  |
-------------------------------------------------------------------------------------
|  0 | SELECT STATEMENT             |                   | 19 | 722 |  3 (0)|00:00:01|
|  1 |  NESTED LOOPS                |                   |    |     |       |        |
|  2 |   NESTED LOOPS               |                   | 19 | 722 |  3 (0)|00:00:01|
|* 3 |    TABLE ACCESS FULL         | DEPARTMENTS       |  2 |  32 |  2 (0)|00:00:01|
|* 4 |    INDEX RANGE SCAN          | EMP_DEPARTMENT_IX | 10 |     |  0 (0)|00:00:01|
|  5 |   TABLE ACCESS BY INDEX ROWID| EMPLOYEES         | 10 | 220 |  1 (0)|00:00:01|
-------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------
3 - filter("D"."DEPARTMENT_NAME"='Marketing' OR "D"."DEPARTMENT_NAME"='Sales')
4 - access("E"."DEPARTMENT_ID"="D"."DEPARTMENT_ID")

この場合は、hr.departments表の行が内部ネステッド・ループ(手順2)の外部行ソース(手順3)を形成します。索引emp_department_ixは、内部ネステッド・ループの内部行ソース(手順4)です。内部ネステッド・ループの結果が、外部ネステッド・ループ(Row 1)の外部行ソース(Row 2)を形成します。hr.employees表は、外部ネステッド・ループの外部行ソース(Row 5)です。

フェッチ・リクエストごとの基本的なプロセスは次のとおりです。

1. フェッチでリクエストされた行を取得するために、内部ネステッド・ループが反復処理されます(手順2)。

a. departmentsの最初の行が読み取られ、MarketingまたはSalesという部門の部門IDが取得されます(手順3)。次に例を示します。

Marketing,20

この行セットは、外部ループです。データはPGAにキャッシュされます。

b. emp_department_ix(employees表の索引)のスキャンによって、この部門IDに該当するemployees行IDが検索され(手順4)、その結果が結合されます(手順2)。
結果セットは次の形式になります。

Marketing,20,employees_rowid
Marketing,20,employees_rowid
Marketing,20,employees_rowid

c. departmentsの次の行が読み取られ、emp_department_ixのスキャンによって、この部門IDに該当するemployees行IDが検索され(手順4)、クライアント・リクエストが満たされるまでこのループが反復されます。
この例では、departmentsで述語フィルタに一致するのは2行のみのため、外部ループは2回のみ反復されます。概念上、結果セットは次の形式をとります。

Marketing,20,employees_rowid
Marketing,20,employees_rowid
Marketing,20,employees_rowid
.
.
.
Sales,80,employees_rowid
Sales,80,employees_rowid
Sales,80,employees_rowid
.
.
.

これらの行が、外部ネステッド・ループの外部行ソースになります(手順1)。この行セットはPGAにキャッシュされます。

2. 前の手順で取得された行IDは、キャッシュでより効率的にアクセスできるように整理されます。

3. 外部ネステッド・ループの反復処理が、次のように開始されます。

a. 前の手順で取得された行セットの最初の行が、次の例のように取得されます。

Marketing,20,employees_rowid

b. リクエストされた値を取得するために、行IDを使用してemployeesの行が、次の例のように取得されます(手順1)。

Michael,Hartstein,13000,Marketing

c. 行セットから次の行が取得され、行IDを使用してemployeesで一致する行がプローブされ、すべての行が取得されるまでこのループが反復されます。
結果セットは次の形式になります。

Michael,Hartstein,13000,Marketing
Pat,Fay,6000,Marketing
John,Russell,14000,Sales
Karen,Partners,13500,Sales
Alberto,Errazuriz,12000,Sales
.
.
.

場合によっては、2番目の結合の行ソースが割り当てられないことがあります。この場合、実行計画はOracle Database 11g以前と同様に表示されます。次にこのような状況について説明します。

- 結合の内部側で必要なすべての列が索引に存在するため、表にアクセスする必要がない。この場合、Oracle Databaseでは結合の1つの行ソースのみが割り当てられます。

- 返される行の順序は、Oracle Database 12cより前のリリースで返される順序とは異なる場合があります。したがって、Oracle Databaseで行の特定の順序を予約しようとする場合(たとえばORDER BYソートを行う必要がない場合など)、Oracle Databaseではネステッド・ループ結合の従来の実装が使用されます。

- OPTIMIZER_FEATURES_ENABLE初期化パラメータが、Oracle Database 11gより前のリリースに設定されている。この場合、Oracle Databaseではネステッド・ループ結合の従来の実装が使用されます。

ネステッド・ループ結合の従来の実装

現在のリリースでは、ネステッド・ループの新しい実装と従来の実装のいずれも使用可能です。

従来の実装の例として、次にhr.employees表とhr.departments表の結合を検討してみます。

SELECT e.first_name, e.last_name, e.salary, d.department_name
FROM   hr.employees e, hr.departments d
WHERE  d.department_name IN ('Marketing', 'Sales')
AND    e.department_id = d.department_id;

Oracle Database 11gより前のリリースでは、この問合せの実行計画は次のようになります。

------------------------------------------------------------------------------------------------
| Id  | Operation                   | Name              | Rows  | Bytes | Cost (%CPU)| Time    |
------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT            |                   |    19 |   722 |     3  (0)| 00:00:01 |
|   1 |  TABLE ACCESS BY INDEX ROWID| EMPLOYEES         |    10 |   220 |     1  (0)| 00:00:01 |
|   2 |   NESTED LOOPS              |                   |    19 |   722 |     3  (0)| 00:00:01 |
|*  3 |    TABLE ACCESS FULL        | DEPARTMENTS       |     2 |    32 |     2  (0)| 00:00:01 |
|*  4 |    INDEX RANGE SCAN         | EMP_DEPARTMENT_IX |    10 |       |     0  (0)| 00:00:01 |
------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------
3 - filter("D"."DEPARTMENT_NAME"='Marketing' OR "D"."DEPARTMENT_NAME"='Sales')
4 - access("E"."DEPARTMENT_ID"="D"."DEPARTMENT_ID")

フェッチ・リクエストごとの基本的なプロセスは次のとおりです。

1. フェッチでリクエストされた行を取得するために、ループが反復処理されます。

a. departmentsの最初の行が読み取られ、MarketingまたはSalesという部門の部門IDが取得されます(手順3)。次に例を示します。

Marketing,20

この行セットは、外部ループです。行はPGAにキャッシュされます。

b. emp_department_ix(employees.department_id列の索引)のスキャンによって、この部門IDに該当するemployees行IDが検索され(手順4)、その結果が結合されます(手順2)。
概念上、結果セットは次の形式をとります。

Marketing,20,employees_rowid
Marketing,20,employees_rowid
Marketing,20,employees_rowid

c. departmentsの次の行が読み取られ、emp_department_ixのスキャンによって、この部門IDに該当するemployees行IDが検索され(手順4)、クライアント・リクエストが満たされるまでこのループが反復されます。
この例では、departmentsで述語フィルタに一致するのは2行のみのため、外部ループは2回のみ反復されます。概念上、結果セットは次の形式をとります。

Marketing,20,employees_rowid
Marketing,20,employees_rowid
Marketing,20,employees_rowid
.
.
.
Sales,80,employees_rowid
Sales,80,employees_rowid
Sales,80,employees_rowid
.
.
.

2. 状況に応じ、前の手順で取得されたキャッシングされた行IDは、より効率的にアクセスできるように整理されます。

3. ネステッド・ループで生成された結果セットの各employees行IDについて、リクエストされた値を取得するためにemployeesから行が取得されます(手順1)。
このように、基本的なプロセスでは、行IDが読み取られて一致するemployees行が取得され、次の行IDが読み取られて一致するemployees行が取得され、これが繰り返されます。概念上、結果セットは次の形式をとります。

Michael,Hartstein,13000,Marketing
Pat,Fay,6000,Marketing
John,Russell,14000,Sales
Karen,Partners,13500,Sales
Alberto,Errazuriz,12000,Sales
.
.
.

ネステッド・ループの制御

データが十分に小さいSQL例の場合は、オプティマイザは全表スキャンとハッシュ結合を優先します。ただし、内部表として指定された表を使用してネステッド・ループ結合で指定された各表を別の行ソースに結合するようオプティマイザに指示するために、USE_NLを追加できます。

関連するヒントUSE_NL_WITH_INDEX(表索引)ヒントによって、指定された表を内部表に使用して、ネステッド・ループループ結合で別の行のソースに結合するよう、オプティマイザに指示されます。索引はオプションです。索引を指定しない場合、ネステッド・ループ結合では、結合述語を1つ以上含む索引が索引キーとして使用されます。

例9-3 ネステッド・ループのヒント

次の問合せにおいて、オプティマイザでハッシュ結合が選択されたとします。

SELECT e.last_name, d.department_name
FROM   employees e, departments d
WHERE  e.department_id=d.department_id;

計画は次のようになります。

------------------------------------------------------------------------------
|Id | Operation          | Name        | Rows  | Bytes |Cost(%CPU)| Time     |
------------------------------------------------------------------------------
| 0 | SELECT STATEMENT   |             |       |       |   5 (100)|          |
|*1 |  HASH JOIN         |             |   106 |  2862 |   5  (20)| 00:00:01 |
| 2 |   TABLE ACCESS FULL| DEPARTMENTS |    27 |   432 |   2   (0)| 00:00:01 |
| 3 |   TABLE ACCESS FULL| EMPLOYEES   |   107 |  1177 |   2   (0)| 00:00:01 |
------------------------------------------------------------------------------

departmentsを内部表として使用して強制的にネステッド・ループを行うには、次の問合せのようにUSE_NLヒントを追加します。

SELECT /*+ ORDERED USE_NL(d) */ e.last_name, d.department_name
FROM   employees e, departments d
WHERE  e.department_id=d.department_id;

計画は次のようになります。

--------------------------------------------------------------------------------
| Id | Operation          | Name        | Rows  | Bytes |Cost (%CPU)| Time     |
--------------------------------------------------------------------------------
|  0 | SELECT STATEMENT   |             |       |       |   34 (100)|          |
|  1 |  NESTED LOOPS      |             |   106 |  2862 |   34   (3)| 00:00:01 |
|  2 |   TABLE ACCESS FULL| EMPLOYEES   |   107 |  1177 |    2   (0)| 00:00:01 |
|* 3 |   TABLE ACCESS FULL| DEPARTMENTS |     1 |    16 |    0   (0)|          |
--------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

3 - filter("E"."DEPARTMENT_ID"="D"."DEPARTMENT_ID")

結果セットは次のように取得されます。

1. ネステッド・ループで、従業員の姓および部門IDを取得するために、employeesが読み取られます(手順2)。次に例を示します。

De Haan,90

2. 前の手順で取得された各行について、departmentsのスキャンによってemployees部門IDに一致する部門名が検索されて(手順3)、その結果が結合されます(手順1)。次に例を示します。

De Haan,Executive

3. employeesの次の行が取得され、departmentsから一致する行が取得され、すべての行が取得されるまでこのプロセスが反復されます。
結果セットは次の形式になります。

De Haan,Executive
Kochnar,Executive
Baer,Public Relations
King,Executive
.
.
.

関連項目:

- USE_NLヒントの詳細は、「結合順序のヒントのガイドライン」を参照してください

- USE_NLヒントの詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

ハッシュ結合

ハッシュ結合は、大きなデータ・セットの結合に使用されます。

オプティマイザによって、2つのデータ・セットの小さい方が使用されてメモリー内に結合キーのハッシュ表が作成され、決定的ハッシュ関数によって、ハッシュ表内で各行を格納する場所が指定されます。次に、大きい方のデータ・セットがスキャンされ、ハッシュ表を調べて結合条件を満たす行が検索されます。

この項の内容は次のとおりです。

- オプティマイザがハッシュ結合を考慮する場合

- ハッシュ結合の仕組み

- ハッシュ表がPGAに収まらない場合のハッシュ結合の仕組み

- ハッシュ結合の制御

オプティマイザがハッシュ結合を考慮する場合

通常、比較的大量のデータを結合する必要がある(または小規模な表の大部分を結合する必要がある)場合、オプティマイザはハッシュ結合を考慮し、結合は等価結合となります。

ハッシュ結合は、小さい方のデータ・セットがメモリーに収まる場合に、コスト効率が非常に高くなります。この場合、コストは2つのデータ・セットに対する1回のリード・パスに限定されます。

ハッシュ表がPGA内に存在するため、行をラッチすることなく、アクセスが可能です。この手法によって、データベース・バッファ・キャッシュでブロックのラッチと読取りを繰り返す必要性が回避されて、論理I/Oが低減されます。

データ・セットがメモリーに収まらない場合は、行ソースがパーティション分割されて、パーティションごとに結合が行われます。この場合は、ソート領域メモリー、および一時表領域へのI/Oが、大量に使用される可能性があります。この手法でも、特にデータベースでパラレル問合せサーバーが使用される場合には、非常にコスト効率が高い場合があります。

ハッシュ結合の仕組み

ハッシュ・アルゴリズムでは、入力のセットに決定的ハッシュ関数を適用して、1とn間のハッシュ値を生成します(nはハッシュ表のサイズです)。

ハッシュ結合において、入力値は結合キーです。出力値は配列形式の索引(スロット)であり、これがハッシュ表です。

ハッシュ表

ハッシュ表について説明するために、departmentsとemployeesの結合において、hr.departmentsがハッシュされると想定します。結合キー列は、department_idです。

departmentsの最初の5行は、次のとおりです。

SQL> select * from departments where rownum < 6;

DEPARTMENT_ID DEPARTMENT_NAME                MANAGER_ID LOCATION_ID
------------- ------------------------------ ---------- -----------
10 Administration                        200        1700
20 Marketing                             201        1800
30 Purchasing                            114        1700
40 Human Resources                       203        2400
50 Shipping                              121        1500

表の各department_idに対してハッシュ関数が適用され、それぞれのハッシュ値が生成されます。この説明では、ハッシュ表には5つのスロットがあります(これより多い可能性も少ない可能性もあります)。nが5であるため、可能なハッシュ値は、1から5の範囲です。ハッシュ関数によって、部門IDに対して次の値が生成されるとします。

f(10) = 4
f(20) = 1
f(30) = 4
f(40) = 2
f(50) = 5

ハッシュ関数によって、たまたま部門10と部門30に対して同じハッシュ値4が生成されています。これは、ハッシュ衝突と呼ばれます。この場合、部門10と部門30のレコードは、リンク済リストを使用して同じスロットに格納されます。概念上、ハッシュ表は次のようになります。

1    20,Marketing,201,1800
2    40,Human Resources,203,2400
3
4    10,Administration,200,1700 -> 30,Purchasing,114,1700
5    50,Shipping,121,1500

ハッシュ結合: 基本手順

オプティマイザは、小さい方のデータ・ソースを使用してメモリー内の結合キーにハッシュ表を構築してから、大きい方の表をスキャンして結合された行を見つけます。

基本手順は次のとおりです。

1. ビルド表と呼ばれる小さい方のデータ・セットの全体スキャンが実行された後、各行の結合キーに対してハッシュ関数が適用されて、PGAにハッシュ表が作成されます。
擬似コードでは、アルゴリズムは次のようになります。

FOR small_table_row IN (SELECT * FROM small_table)
LOOP
slot_number := HASH(small_table_row.join_key);
INSERT_HASH_TABLE(slot_number,small_table_row);
END LOOP;

2. 最少コストのアクセス・メカニズムを使用して、プローブ表と呼ばれる2番目のデータ・セットがプローブされます。
通常は、小さい方と大きい方の両データ・セットの全体スキャンが実行されます。擬似コードによるアルゴリズムは次のようになります。

FOR large_table_row IN (SELECT * FROM large_table)
LOOP
slot_number := HASH(large_table_row.join_key);
small_table_row = LOOKUP_HASH_TABLE(slot_number,large_table_row.join_key);
IF small_table_row FOUND
THEN
output small_table_row + large_table_row;
END IF;
END LOOP;

大きい方のデータ・セットから取得した各行に対して、次の手順が実行されます。

a. 結合列に対して同じハッシュ関数が適用され、ハッシュ表で該当するスロット番号が計算されます。
たとえば、ハッシュ表で部門ID 30がプローブされる場合、ハッシュ関数が30に適用され、ハッシュ値4が生成されます。

b. ハッシュ表がプローブされ、行がスロットに存在するかどうかが判定されます。
行が存在しない場合は、大きい方のデータ・セットの次の行が処理されます。行が存在する場合は、次の手順に進みます。

c. 結合列で一致がチェックされます。一致が検出された場合は、行が報告されるか、計画の次の手順に渡された後、大きい方のデータ・セットの次の行が処理されます。
ハッシュ表のスロットに複数の行が存在する場合は、行のリンク済リストの各行が順にチェックされます。たとえば、部門30がスロット4にハッシュされた場合、30が見つかるまで各行がチェックされます。

例9-4 ハッシュ結合

アプリケーションでoe.orders表とoe.order_items表に対してorder_id列を結合する問合せが行われるとします。

SELECT o.customer_id, l.unit_price * l.quantity
FROM   orders o, order_items l
WHERE  l.order_id = o.order_id;

実行計画は次のようになります。

--------------------------------------------------------------------------
| Id  | Operation            |  Name        | Rows  | Bytes | Cost (%CPU)|
--------------------------------------------------------------------------
|   0 | SELECT STATEMENT     |              |   665 | 13300 |     8  (25)|
|*  1 |  HASH JOIN           |              |   665 | 13300 |     8  (25)|
|   2 |   TABLE ACCESS FULL  | ORDERS       |   105 |   840 |     4  (25)|
|   3 |   TABLE ACCESS FULL  | ORDER_ITEMS  |   665 |  7980 |     4  (25)|
--------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------
1 - access("L"."ORDER_ID"="O"."ORDER_ID")

orders表はorder_items表に比べて小さいため(6倍の大きさ)、ordersがハッシュされます。ハッシュ結合では、ビルド表のデータ・セットは常に操作リストの最初に表示されます(手順2)。手順3で、大きい方のorder_itemsの全体スキャンが後で行われ、各行についてハッシュ表がプローブされます。

ハッシュ表がPGAに収まらない場合のハッシュ結合の仕組み

ハッシュ表全体がPGAに収まらない場合は、別の手法が使用される必要があります。この場合は、一時領域にハッシュ表の一部(パーティションと呼ばれる)が保持され、そこにハッシュ表をプローブする大きい方の表の一部が保持される場合もあります。

基本的なプロセスは次のとおりです。

1. 小さい方のデータ・セットの全体スキャンが実行された後、PGAとディスクの両方にハッシュ・バケットの配列が作成されます。
PGAのハッシュ領域が一杯になると、ハッシュ表内で最も大きなパーティションが検索され、それがディスク上の一時領域に書き込まれます。このオンディスク・パーティションに属するあらゆる新規の行はディスク上に格納され、他のすべての行はPGAに格納されます。このため、ハッシュ表の一部はメモリーに、一部はディスク上に保持されます。

2. まず、もう一方のデータ・セットが読み取られます。
各行に対して、次の処理が行われます。

a. 結合列に対して同じハッシュ関数が適用され、該当するハッシュ・バケットの番号が計算されます。

b. ハッシュ表がプローブされ、メモリー内のバケットに行が存在するかどうかが判定されます。
ハッシュ値がメモリー内の行を指している場合は、結合が行われて、その行が返されます。ただし、値がディスク上のハッシュ・パーティションを指している場合、この行は、元のデータ・セットで使用されたものと同じパーティション・スキームを使用して一時表領域に格納されます。

3. 各オンディスク一時パーティションが1つずつ読み取られます。

4. 各パーティション行が、対応するオンディスク一時パーティション内の行に結合されます。

ハッシュ結合の制御

USE_HASHヒントによって、2つの表を結合するときにハッシュ結合を使用するよう、オプティマイザに指示します。

関連項目:

結合順序のヒントのガイドライン

ソート/マージ結合

ソート/マージ結合は、ネステッド・ループ結合のバリエーションです。

結合の2つのデータ・セットがまだソートされていない場合、データベースでソートされます。これはSORT JOIN操作です。1つ目のデータ・セットの各行ごとに、2つ目のデータ・セットが、前回の反復処理で得られた一致を基準とした開始位置からプローブされ、一致した行が結合されます。これはMERGE JOIN操作です。

図9-6 ソート/マージ結合

オプティマイザがソート/マージ結合を考慮する場合

ハッシュ結合には、1つのハッシュ表とこの表の1回のプローブが必要ですが、ソート/マージ結合には2回のソートが必要です。

オプティマイザでは、次の条件に該当する場合に、大量のデータの結合にハッシュ結合よりソート/マージ結合が選択されます。

- 2つの表の結合条件が等価結合ではありません、つまり、非等価条件(<、<=、>、>=など)が使用されます。
ソート/マージと異なり、ハッシュ結合には等価条件が必要です。

- 他の操作でソートが必要なため、オプティマイザによってソート/マージを使用する方がコストが低いと判断されました。
索引が存在する場合は、1つ目のデータ・セットのソートが回避されます。ただし、2つ目のデータ・セットは索引に関係なく常にソートされます。

ソート/マージには、ハッシュ結合と同じくネステッド・ループ結合に勝る利点があります。行はSGAよりもPGAでアクセスされるため、データベース・バッファ・キャッシュでブロックのラッチと読取りを繰り返す必要性が回避されて、論理I/Oが低減されます。ソートはコストが高いため、一般に、ハッシュ結合はソート/マージ結合よりもパフォーマンスが優れています。ただし、ソート/マージ結合にはハッシュ結合より優れた次のような利点があります。

- 初期ソートの後、マージ・フェーズが最適化されて、出力行の生成速度が上がります。

- ハッシュ表がメモリー内に完全に収まらない場合、ソート/マージはハッシュ結合よりもコスト効率が上がります。
ハッシュ結合においてメモリーが不十分な場合は、ハッシュ表ともう一方のデータ・セットがディスクにコピーされる必要があります。この場合は、ディスクから複数回の読取りが必要になることがあります。ソート/マージでは、メモリに2つのデータ・セットを保持できない場合に両方がディスクに書き込まれますが、各データ・セットが複数回読み取られることはありません。

ソート/マージ結合の仕組み

ネステッド・ループ結合と同様に、ソート/マージ結合では2つのデータ・セットが読み取られますが、ソートは、すでに行われていない場合に行われます。1つ目のデータ・セットの各行ごとに、2つ目のデータ・セットの開始行が検索され、一致しない行が見つかるまで2つ目のデータ・セットが読み取られます。

擬似コードでソート/マージの上位レベルのアルゴリズムを表すと、次のようになります。

READ data_set_1 SORT BY JOIN KEY TO temp_ds1
READ data_set_2 SORT BY JOIN KEY TO temp_ds2

READ ds1_row FROM temp_ds1
READ ds2_row FROM temp_ds2

WHILE NOT eof ON temp_ds1,temp_ds2
LOOP
IF ( temp_ds1.key = temp_ds2.key ) OUTPUT JOIN ds1_row,ds2_row
ELSIF ( temp_ds1.key <= temp_ds2.key ) READ ds1_row FROM temp_ds1
ELSIF ( temp_ds1.key => temp_ds2.key ) READ ds2_row FROM temp_ds2
END LOOP

たとえば、次の表に2つのデータ・セット(temp_ds1およびtemp_ds2)のソートされた値を示します。

表9-2 ソートされたデータ・セット

temp_ds1

temp_ds2

10

20

20

20

30

40

40

40

50

40

60

40

70

40

.

60

.

70

.

70

次の表に示すように、データベースはtemp_ds1の10の読取りから開始し、temp_ds2の最初の値を読み取ります。temp_ds2の20がtemp_ds1の10より大きいため、データベースはtemp_ds2の読取りを停止します。

表9-3 temp_ds1の10から開始

temp_ds1

temp_ds2

アクション

10 [ここから開始]

20 [ここから開始] [ここで停止]

temp_ds2の20は、temp_ds1の10より大きい値です。停止します。temp_ds1の次の行から再開します。

20

20

30

40

40

40

50

40

60

40

70

40

.

60

.

70

.

70

temp_ds1の次の値(20)に進みます。次の表に示すように、temp_ds2の処理が進みます。

表9-4 temp_ds1の20から開始

temp_ds1

temp_ds2

アクション

10

20 [ここから開始]

一致。temp_ds2の次の値に進みます。

20 [ここから開始]

20

一致。temp_ds2の次の値に進みます。

30

40 [ここで停止]

temp_ds2の40は、temp_ds1の20より大きい値です。停止します。temp_ds1の次の行から再開します。

40

40

50

40

60

40

70

40

.

60

.

70

.

70

データベースは、temp_ds1の次の行(30)に進みます。次の表に示すように、前回に一致した数値から読取りが開始され(20でした)、temp_ds2で一致が順に検索されていきます。

表9-5 temp_ds1の30から開始

temp_ds1

temp_ds2

アクション

10

20

20

20 [最後の一致から開始]

temp_ds2の20は、temp_ds1の30より小さい値です。temp_ds2の次の値に進みます。

30 [ここから開始]

40 [ここで停止]

temp_ds2の40は、temp_ds1の30より大きい値です。停止します。temp_ds1の次の行から再開します。

40

40

50

40

60

40

70

40

.

60

.

70

.

70

データベースは、temp_ds1の次の行(40)に進みます。次の表に示すように、temp_ds2の前回に一致した数値から読取りが開始され(20でした)、temp_ds2で一致が順に検索されていきます。

表9-6 temp_ds1の40から開始

temp_ds1

temp_ds2

アクション

10

20

20

20 [最後の一致から開始]

temp_ds2の20は、temp_ds1の40より小さい値です。temp_ds2の次の値に進みます。

30

40

一致。temp_ds2の次の値に進みます。

40 [ここから開始]

40

一致。temp_ds2の次の値に進みます。

50

40

一致。temp_ds2の次の値に進みます。

60

40

一致。temp_ds2の次の値に進みます。

70

40

一致。temp_ds2の次の値に進みます。

.

60 [ここで停止]

temp_ds2の60は、temp_ds1の40より大きい値です。停止します。temp_ds1の次の行から再開します。

.

70

.

70

temp_ds2の最後の70と一致するまで、この方法で継続します。このシナリオは、データベースがtemp_ds1全体を読み取るため、temp_ds2の各行を読み取る必要がないことを示しています。これが、ネステッド・ループ結合に勝る利点です。

例9-5 索引を使用したソート/マージ結合

次の問合せでは、employees表とdepartments表がdepartment_id列で結合され、次のように行がdepartment_idによって順序付けられます。

SELECT e.employee_id, e.last_name, e.first_name, e.department_id,
d.department_name
FROM   employees e, departments d
WHERE  e.department_id = d.department_id
ORDER BY department_id;

DBMS_XPLAN.DISPLAY_CURSORの問合せによって、計画でソート/マージ結合が使用されていることがわかります。

--------------------------------------------------------------------------------
|Id| Operation                    | Name        |Rows|Bytes |Cost (%CPU)| Time |
--------------------------------------------------------------------------------
| 0| SELECT STATEMENT             |             |    |      | 5(100)|          |
| 1|  MERGE JOIN                  |             |106 | 4028 | 5 (20)| 00:00:01 |
| 2|   TABLE ACCESS BY INDEX ROWID| DEPARTMENTS | 27 |  432 | 2  (0)| 00:00:01 |
| 3|    INDEX FULL SCAN           | DEPT_ID_PK  | 27 |      | 1  (0)| 00:00:01 |
|*4|   SORT JOIN                  |             |107 | 2354 | 3 (34)| 00:00:01 |
| 5|    TABLE ACCESS FULL         | EMPLOYEES   |107 | 2354 | 2  (0)| 00:00:01 |
--------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

4 - access("E"."DEPARTMENT_ID"="D"."DEPARTMENT_ID")
filter("E"."DEPARTMENT_ID"="D"."DEPARTMENT_ID")

2つのデータ・セットは、departments表とemployees表です。索引でdepartments表は、department_idによって順序付けられるため、この索引を読み取ることでソート(手順3)を回避できます。必要なのはemployees表のソート(手順4)のみであり、これが最もCPUの負荷が高い操作です。

例9-6 索引を使用しないソート/マージ結合

employees表とdepartments表がdepartment_id列で結合され、次のように行がdepartment_idによって順序付けられます。この例では、NO_INDEXおよびUSE_MERGEを指定することによって、オプティマイザにソート/マージの選択を強制します。

SELECT /*+ USE_MERGE(d e) NO_INDEX(d) */ e.employee_id, e.last_name, e.first_name,
e.department_id, d.department_name
FROM   employees e, departments d
WHERE  e.department_id = d.department_id
ORDER BY department_id;

DBMS_XPLAN.DISPLAY_CURSORの問合せによって、計画でソート/マージ結合が使用されていることがわかります。

--------------------------------------------------------------------------------
| Id| Operation           | Name        | Rows  | Bytes | Cost (%CPU)| Time    |
--------------------------------------------------------------------------------
| 0 | SELECT STATEMENT    |             |       |       |     6 (100)|         |
| 1 |  MERGE JOIN         |             |   106 |  9540 |     6  (34)| 00:00:01|
| 2 |   SORT JOIN         |             |    27 |   567 |     3  (34)| 00:00:01|
| 3 |    TABLE ACCESS FULL| DEPARTMENTS |    27 |   567 |     2   (0)| 00:00:01|
|*4 |   SORT JOIN         |             |   107 |  7383 |     3  (34)| 00:00:01|
| 5 |    TABLE ACCESS FULL| EMPLOYEES   |   107 |  7383 |     2   (0)| 00:00:01|
--------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

4 - access("E"."DEPARTMENT_ID"="D"."DEPARTMENT_ID")
filter("E"."DEPARTMENT_ID"="D"."DEPARTMENT_ID")

departments.department_id索引が無視されるため、オプティマイザによってソートが実行されて、手順2と手順3を合わせたコストが67%増加します(3から5まで)。

ソート/マージ結合の制御

USE_MERGEヒントによって、ソート/マージ結合を使用するようオプティマイザに指示します。

状況によっては、USE_MERGEヒントを使用してオプティマイザを上書きすることが適切な場合もあります。たとえば、オプティマイザは表に対する全体スキャンを選択して問合せ内でのソート操作を回避できます。ただし、大きい表は全表スキャンによる高速アクセスの場合とは異なり、索引および単一ブロック読取りでアクセスされるため、コストがかかります。

関連項目:

USE_MERGEヒントの詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

デカルト結合

文に他の表との結合条件のない表が1つ以上存在する場合、デカルト結合が使用されます。

オプティマイザは、データ・ソースにあるすべての行を、2つのセットのデカルト積を作成しながら、別のデータ・ソースにあるすべての行と結合します。したがって、結合で生成される行の合計数は、次の式で計算されます(rs1は、1つ目の行セットの行数で、rs2は、2つ目の行セットの行数です)。

rs1 X rs2 = total rows in result set

オプティマイザがデカルト結合を考慮する場合

オプティマイザでは、次のいずれかの状況に該当する2つの行ソースに対して、デカルト結合が使用されます。

- 結合条件が存在しません。
場合によっては、2つの表の間に共通のフィルタ条件が、可能な結合条件として採用されることがあります。

注意:

結合条件が誤って省略されたために、問合せ計画にデカルト結合が出現する場合があります。一般に、問合せでn個の表が結合される場合、デカルト結合を回避するにはn-1個の結合条件が必要です。

- デカルト結合が効率的です。
たとえば、オプティマイザによって、同じ大きい表に結合されている、非常に小さい2つの表のデカルト積を生成するように決定される場合もあります。

- 結合表が指定される前に、ORDEREDヒントによって表が指定されています。

デカルト結合の仕組み

上位レベルにおいて、デカルト結合のアルゴリズムは次のようになります(ds1が、通常小さい方のデータセットで、ds2が大きい方のデータ・セットです)。

FOR ds1_row IN ds1 LOOP
FOR ds2_row IN ds2 LOOP
output ds1_row and ds2_row
END LOOP
END LOOP

例9-7 デカルト結合

この例では、ユーザーはemployees表とdepartments表の内部結合を実行しようとして、誤って結合条件を省略しています。

SELECT e.last_name, d.department_name
FROM   employees e, departments d

実行計画は次のようになります。

--------------------------------------------------------------------------------
| Id| Operation              | Name        | Rows  | Bytes |Cost (%CPU)| Time  |
--------------------------------------------------------------------------------
| 0 | SELECT STATEMENT       |             |       |       |11 (100)|          |
| 1 |  MERGE JOIN CARTESIAN  |             |  2889 | 57780 |11   (0)| 00:00:01 |
| 2 |   TABLE ACCESS FULL    | DEPARTMENTS |    27 |   324 | 2   (0)| 00:00:01 |
| 3 |   BUFFER SORT          |             |   107 |   856 | 9   (0)| 00:00:01 |
| 4 |    INDEX FAST FULL SCAN| EMP_NAME_IX |   107 |   856 | 0   (0)|          |
--------------------------------------------------------------------------------

この計画では、手順1のCARTESIANキーワードによって、デカルト結合が行われることが示されています。行数(2889)は、27と107の積です。

手順3のBUFFER SORT操作は、emp_name_ixのスキャンで取得されたデータ・ブロックが、SGAからPGAにコピーされることを意味しています。この方法によって、データベース・バッファ・キャッシュにおける同一ブロックの複数回スキャンが回避される結果、多数の論理読取りが生成されて、リソース競合が生じる可能性があります。

デカルト結合の制御

ORDEREDヒントによって、FROM句に現れる順序で表を結合するようオプティマイザに指示します。直接関係のない2つの表を強制的に結合させることにより、デカルト結合が実行されます。

関連項目:

ORDEREDヒントの詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

例9-8 ORDEREDヒント

次の例では、ORDEREDヒントによって、オプティマイザにemployees表とlocations表を結合するよう指示しますが、これら2つの行ソースをつなぐ結合条件はありません。

SELECT /*+ORDERED*/ e.last_name, d.department_name, l.country_id, l.state_province
FROM   employees e, locations l, departments d
WHERE  e.department_id = d.department_id
AND    d.location_id = l.location_id

次の実行計画ではlocations (手順6)とemployees (手順4)とのデカルト積(手順3)が行われ、次にそれがdepartments表に結合されます(手順2)。

--------------------------------------------------------------------------------
| Id| Operation             | Name        | Rows  | Bytes |Cost (%CPU)|Time    |
--------------------------------------------------------------------------------
| 0 | SELECT STATEMENT      |             |       |       | 37 (100)|          |
|*1 |  HASH JOIN            |             |   106 |  4664 | 37   (6)| 00:00:01 |
| 2 |   TABLE ACCESS FULL   | DEPARTMENTS |    27 |   513 |  2   (0)| 00:00:01 |
| 3 |   MERGE JOIN CARTESIAN|             |  2461 | 61525 | 34   (3)| 00:00:01 |
| 4 |    TABLE ACCESS FULL  | EMPLOYEES   |   107 |  1177 |  2   (0)| 00:00:01 |
| 5 |    BUFFER SORT        |             |    23 |   322 | 32   (4)| 00:00:01 |
| 6 |     TABLE ACCESS FULL | LOCATIONS   |    23 |   322 |  0   (0)|          |
--------------------------------------------------------------------------------

結合タイプ

結合タイプは、結合条件のタイプによって決定されます。

この項の内容は次のとおりです。

- 内部結合

- 外部結合

- セミ結合

- アンチ結合

内部結合

内部結合(単純結合とも呼ばれる)は、結合条件を満たす行のみが返される結合です。内部結合は、等価結合または非等価結合です。

等価結合

等価結合は、結合条件に等価演算子が含まれる内部結合です。

次の例は、結合条件に等価演算子のみが含まれているため、等価結合です。

SELECT e.employee_id, e.last_name, d.department_name
FROM   employees e, departments d
WHERE  e.department_id=d.department_id;

この問合せにおける結合条件はe.department_id=d.department_idです。employees表に、departments表の行の部門IDに一致する値を持つ行があれば、結合結果が返され、そうでない場合、結果は返されません。

非等価結合

非等価結合は、結合条件に等価演算子ではない演算子が含まれる内部結合です。

次の問合せでは、従業員176がこの企業で働いていた間に、雇用日が発生したすべての従業員が示されます(従業員176は2007年に転職したため、job_historyに記載されています)。

SELECT e.employee_id, e.first_name, e.last_name, e.hire_date
FROM   employees e, job_history h
WHERE  h.employee_id = 176
AND    e.hire_date BETWEEN h.start_date AND h.end_date;

この例では、employeesとjob_historyを結合する条件に等価演算子が含まれないため、非等価結合です。非等価結合は、比較的まれです。

ハッシュ結合には、少なくとも部分等価結合が必要です。次のSQLスクリプトには、等価結合条件(e1.empno = e2.empno)および非等価条件が含まれています。

SET AUTOTRACE TRACEONLY EXPLAIN
SELECT *
FROM   scott.emp e1 JOIN scott.emp e2
ON     ( e1.empno = e2.empno
AND      e1.hiredate BETWEEN e2.hiredate-1 AND e2.hiredate+1 )

次の計画で示されているように、オプティマイザでは、この問合せに対してハッシュ結合が選択されます。

Execution Plan
----------------------------------------------------------
Plan hash value: 3638257876

---------------------------------------------------------------------------
| Id  | Operation          | Name | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |      |     1 |   174 |     5  (20)| 00:00:01 |
|*  1 |  HASH JOIN         |      |     1 |   174 |     5  (20)| 00:00:01 |
|   2 |   TABLE ACCESS FULL| EMP  |    14 |  1218 |     2   (0)| 00:00:01 |
|   3 |   TABLE ACCESS FULL| EMP  |    14 |  1218 |     2   (0)| 00:00:01 |
---------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

1 - access("E1"."EMPNO"="E2"."EMPNO")
filter("E1"."HIREDATE">=INTERNAL_FUNCTION("E2"."HIREDATE")-1 AND
"E1"."HIREDATE"<=INTERNAL_FUNCTION("E2"."HIREDATE")+1)

外部結合

外部結合では、結合条件に一致するすべての行、および結合条件が他方の表のどの行とも一致しない、一方の表の一部またはすべての行が返されます。したがって、外部結合では単純結合の結果が拡張されます。

ANSI構文では、OUTER JOIN句で外部結合を指定します。FROM句において、左表はOUTER JOINキーワードの左に表示され、右表はこのキーワードの右に表示されます。左表は外部表とも呼ばれ、右表は内部表とも呼ばれます。たとえば、次の文において、employees表は左表または外部表です。

SELECT employee_id, last_name, first_name
FROM   employees LEFT OUTER JOIN departments
ON     (employees.department_id=departments.departments_id);

外部結合では、外部結合表が駆動表となる必要があります。この例では、employeesが駆動表で、departments被駆動表です。

この項の内容は次のとおりです。

- ネステッド・ループ外部結合

- ハッシュ結合外部結合

- ソート/マージ外部結合

- 完全外部結合

- 左側に複数の表がある外部結合

ネステッド・ループ外部結合

この操作は、2つの表の外部結合をループ処理する場合に使用されます。外部結合は、内部(オプション)表に対応する行がない場合でも、外部(保存されている)表の行を戻します。

標準的なネステッド・ループでは、表の順序(どちらが駆動表で、どちら被駆動表か)は、コストに基づいて決定されます。ただし、ネステッド・ループ外部結合では、結合条件によって表の順序が決まります。外部表(行が格納される表)によって、内部表が駆動されます。

オプティマイザは、ネステッド・ループ結合を使用し、次の状況で外部結合を処理します。

- 外部表から内部表を駆動できる。

- データ量が少なく、ネステッド・ループ方法が効果的と判断できる。

ネステッド・ループ外部結合の例の場合は、USE_NLヒントを例9-9に追加して、ネステッド・ループを使用するようにオプティマイザに指示できます。次に例を示します。

SELECT /*+ USE_NL(c o) */ cust_last_name,
SUM(NVL2(o.customer_id,0,1)) "Count"
FROM   customers c, orders o
WHERE  c.credit_limit > 1000
AND    c.customer_id = o.customer_id(+)
GROUP BY cust_last_name;

ハッシュ結合外部結合

オプティマイザでは、次の条件のいずれか該当する場合に、外部結合の処理にハッシュ結合が使用されます。

- データ量が十分に多く、ハッシュ結合法が効果的である。

- 外部表から内部表まで起動することができない。

表の順序はコストによって決まります。外部表は、保存された行も含めて、ハッシュ表を作成する場合に使用されるか、またはハッシュ表を調べるときに使用される場合があります。

例9-9 ハッシュ結合外部結合

この例に、一般的なハッシュ結合外部結合の問合せおよびその実行計画を示します。この例では、与信限度が1000を超えるすべての顧客が問い合されます。問合せで注文のない顧客を取得するには、外部結合が必要です。

- 外部表はcustomersです。

- 内部表はordersです。

- この結合は、orders内に対応する行を持たない行を含むcustomers行を保存します。

行を戻すには、NOT EXISTS副問合せを使用できます。ただし、表の全行の問合せを行っているため、ハッシュ結合の方がパフォーマンスが優れています(NOT EXISTS副問合せがネストされていない場合を除く)。

SELECT cust_last_name, SUM(NVL2(o.customer_id,0,1)) "Count"
FROM   customers c, orders o
WHERE  c.credit_limit > 1000
AND    c.customer_id = o.customer_id(+)
GROUP BY cust_last_name;

--------------------------------------------------------------------------------
| Id  | Operation          | Name      | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------------

PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
|  0 | SELECT STATEMENT    |           |       |       |     7 (100)|          |
|  1 |  HASH GROUP BY      |           |   168 |  3192 |     7  (29)| 00:00:01 |
|* 2 |   HASH JOIN OUTER   |           |   318 |  6042 |     6  (17)| 00:00:01 |
|* 3 |    TABLE ACCESS FULL| CUSTOMERS |   260 |  3900 |     3   (0)| 00:00:01 |
|* 4 |    TABLE ACCESS FULL| ORDERS    |   105 |   420 |     2   (0)| 00:00:01 |
--------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

2 - access("C"."CUSTOMER_ID"="O"."CUSTOMER_ID")

PLAN_TABLE_OUTPUT
-------------------------------------------------------------------------------
3 - filter("C"."CREDIT_LIMIT">1000)
4 - filter("O"."CUSTOMER_ID">0)

この問合せは、様々な条件に一致する顧客を検索します。内部表に対応する行が見つからないと、外部結合は外部(保たれている)表の行とともに内部表の列に対してNULLを戻します。この操作で、orders行も持たないcustomers行がすべて検索されます。

この場合、外部結合条件は次のとおりです。

customers.customer_id = orders.customer_id(+)

この条件の構成要素を次に示します。

例9-10 マルチ表ビューへの外部結合

この例では、外部結合はマルチ表ビューに対して行われます。オプティマイザは通常の結合のようにビューを操作したり、述語をプッシュできないので、ビューの行セット全体を作成します。

SELECT c.cust_last_name, sum(revenue)
FROM   customers c, v_orders o
WHERE  c.credit_limit > 2000
AND    o.customer_id(+) = c.customer_id
GROUP BY c.cust_last_name;

----------------------------------------------------------------------------
| Id  | Operation              |  Name        | Rows  | Bytes | Cost (%CPU)|
----------------------------------------------------------------------------
|   0 | SELECT STATEMENT       |              |   144 |  4608 |    16  (32)|
|   1 |  HASH GROUP BY         |              |   144 |  4608 |    16  (32)|
|*  2 |   HASH JOIN OUTER      |              |   663 | 21216 |    15  (27)|
|*  3 |    TABLE ACCESS FULL   | CUSTOMERS    |   195 |  2925 |     6  (17)|
|   4 |    VIEW                | V_ORDERS     |   665 | 11305 |            |
|   5 |     HASH GROUP BY      |              |   665 | 15960 |     9  (34)|
|*  6 |      HASH JOIN         |              |   665 | 15960 |     8  (25)|
|*  7 |       TABLE ACCESS FULL| ORDERS       |   105 |   840 |     4  (25)|
|   8 |       TABLE ACCESS FULL| ORDER_ITEMS  |   665 | 10640 |     4  (25)|
----------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("O"."CUSTOMER_ID"(+)="C"."CUSTOMER_ID")
3 - filter("C"."CREDIT_LIMIT">2000)
6 - access("O"."ORDER_ID"="L"."ORDER_ID")
7 - filter("O"."CUSTOMER_ID">0)

ビュー定義は、次のようになります。

CREATE OR REPLACE view v_orders AS
SELECT l.product_id, SUM(l.quantity*unit_price) revenue,
o.order_id, o.customer_id
FROM   orders o, order_items l
WHERE  o.order_id = l.order_id
GROUP BY l.product_id, o.order_id, o.customer_id;

ソート/マージ外部結合

外部結合で、外部(保たれている)表から内部(オプション)表への駆動ができない場合、外部結合ではハッシュ結合またはネステッド・ループ結合が使用できません。

この場合は、ソート/マージ外部結合が使用されます。

オプティマイザは、次の場合に外部結合にソート/マージを使用します。

- ネステッド・ループ結合の効率が悪い場合。データ量により、ネステッド・ループ結合は効率が悪い場合があります。

- 他の操作でソートが必要であるため、ハッシュ結合よりソート/マージを使用するほうがコストが低いと判断した場合。

完全外部結合

完全外部結合は、左および右外部結合の組合せです。内部結合では、内部結合の結果で戻されなかった両方の表からの行は保たれており、NULLで拡張されます。つまり、完全外部結合を使用すると、表をまとめて結合できますが、結合される表内に対応する行を持たない行も示すことができます。

例9-11 完全外部結合

次の問合せでは、全部門と、その各部門に属する全社員が取得されますが、これには次の内容も含まれます。

- 部門に属さない全社員

- 社員のいない全部門

SELECT d.department_id, e.employee_id
FROM   employees e FULL OUTER JOIN departments d
ON     e.department_id = d.department_id
ORDER BY d.department_id;

文からは、次の出力が作成されます。

DEPARTMENT_ID EMPLOYEE_ID
------------- -----------
10         200
20         201
20         202
30         114
30         115
30         116
...
270
280
178
207

125 rows selected.

例9-12 完全外部結合の実行計画

Oracle Database 11g以上では、可能なかぎり、完全外部結合を実行する場合、ハッシュ結合に基づいたネイティブの実行方法が自動的に使用されます。新しい方法を使用して完全外部結合を実行する場合、問合せの実行計画にはHASH JOIN FULL OUTERが含まれます。例9-11の問合せでは、次の実行計画が使用されます。

--------------------------------------------------------------------------------
| Id| Operation               | Name       |Rows |Bytes |Cost (%CPU)| Time     |
--------------------------------------------------------------------------------
| 0 | SELECT STATEMENT        |            | 122 | 4758 |   6  (34)| 00:0 0:01 |
| 1 |  SORT ORDER BY          |            | 122 | 4758 |   6  (34)| 00:0 0:01 |
| 2 |   VIEW                  | VW_FOJ_0   | 122 | 4758 |   5  (20)| 00:0 0:01 |
|*3 |    HASH JOIN FULL OUTER |            | 122 | 1342 |   5  (20)| 00:0 0:01 |
| 4 |     INDEX FAST FULL SCAN| DEPT_ID_PK |  27 |  108 |   2   (0)| 00:0 0:01 |
| 5 |     TABLE ACCESS FULL   | EMPLOYEES  | 107 |  749 |   2   (0)| 00:0 0:01 |
--------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------
3 - access("E"."DEPARTMENT_ID"="D"."DEPARTMENT_ID")

前述の計画にはHASH JOIN FULL OUTERが含まれており(手順3)、問合せでハッシュ完全外部結合の実行方法が使用されることがわかります。2つの表の完全外部結合条件が等価結合の場合、通常はハッシュ完全外部結合の実行方法が可能であるため、Oracle Databaseでは自動的にこの方法が使用されます。

ハッシュ完全外部結合の実行方法の使用を考慮するようにオプティマイザに指示するには、NATIVE_FULL_OUTER_JOINヒントを適用します。ハッシュ完全外部結合の実行方法の使用を考慮しないようにオプティマイザに指示するには、NO_NATIVE_FULL_OUTER_JOINヒントを適用します。NO_NATIVE_FULL_OUTER_JOINヒントでは、オプティマイザに対して、指定した各表を結合する際にネイティブの実行方法を除外するように指示します。かわりに、左外部結合とアンチ結合を組み合せたものとして完全外部結合が実行されます。

左側に複数の表がある外部結合

Oracle Database 12cでは、外部結合された表の左側に複数の表を配置できます。この拡張により、複数の表を含み、外部結合の左側に表示されるビューをマージできるようになりました。

Oracle Database 12c以前のリリースでは、次のような問合せは無効であり、ORA-01417エラー・メッセージが表示されます。

SELECT t1.d, t3.c
FROM   t1, t2, t3
WHERE  t1.z = t2.z
AND    t1.x = t3.x (+)
AND    t2.y = t3.y (+);

Oracle Database 12c以降では、前述の問合せは有効です。

セミ結合

セミ結合は、副問合せデータ・セットに一致する行が存在する場合に、1つ目のデータ・セットから行が返される、2つのデータ・セット間の結合です。最初の一致が検出された時点で、2つ目のデータ・セットの処理が停止されます。そのため、最適化により、2つ目のデータ・セットの複数の行が副問合せ基準に一致する場合に、1つ目のデータ・セットの行が複製されることはありません。

注意:

セミ結合とアンチ結合は、それらを実行するSQL構文が副問合せであっても、結合タイプとして考慮されます。これらは、副問合せ構文を結合形式で解決できるようにフラット化するため、オプティマイザによって使用される内部アルゴリズムです。

オプティマイザによってセミ結合が考慮される場合

一致が存在するかどうかさえ判別できればよい場合は、セミ結合によって大量の行が返されることを回避できます。大きなデータ・セットでは、この最適化によって、外部問合せのすべての行への内部問合せから返されるすべてのレコードを反復処理する必要があるネステッド・ループ結合で、大きな時間の節約が可能です。セミ結合は、ネステッド・ループ結合、ハッシュ結合、ソート/マージ結合に適用できます。

次の状況では、オプティマイザによってセミ結合が選択される可能性があります。

- 文でIN句またはEXISTS句を使用します。

- 文のIN句またはEXISTS句に、副問合せを含みます。

- IN句またはEXISTS句が、OR分岐の内部に含まれません。

セミ結合の仕組み

セミ結合による最適化は、使用される結合のタイプに応じて実装が異なります。次の擬似コードで、ネステッド・ループ結合のセミ結合を示します。

FOR ds1_row IN ds1 LOOP
match := false;
FOR ds2_row IN ds2_subquery LOOP
IF (ds1_row matches ds2_row) THEN
match := true;
EXIT -- stop processing second data set when a match is found
END IF
END LOOP
IF (match = true) THEN
RETURN ds1_row
END IF
END LOOP

この擬似コードでは、ds1が1つ目のデータ・セットで、ds2_subqueryが副問合せデータ・セットです。このコードでは、1つ目のデータ・セットの最初の行が取得され、次に副問合せデータ・セットの反復処理によって一致が検索されます。一致が見つかった時点で内部ループを抜けて、1つ目のデータ・セットの次の行の処理が開始されます。

例9-13 WHERE EXISTSを使用したセミ結合

次の例では、WHERE EXISTS句を使用して、従業員を含む部門のみが表示されます。

SELECT department_id, department_name
FROM   departments
WHERE EXISTS (SELECT 1
FROM   employees
WHERE  employees.department_id = departments.department_id)

実行計画では、手順1にNESTED LOOPS SEMI操作が示されています。

--------------------------------------------------------------------------------
| Id| Operation          | Name              |Rows|Bytes|Cost (%CPU)| Time     |
--------------------------------------------------------------------------------
| 0 | SELECT STATEMENT   |                   |    |     |    2 (100)|          |
| 1 |  NESTED LOOPS SEMI |                   | 11 | 209 |    2   (0)| 00:00:01 |
| 2 |   TABLE ACCESS FULL| DEPARTMENTS       | 27 | 432 |    2   (0)| 00:00:01 |
|*3 |   INDEX RANGE SCAN | EMP_DEPARTMENT_IX | 44 | 132 |    0   (0)|          |
--------------------------------------------------------------------------------

外部ループを形成するdepartmentsの各行ごとに部門IDが取得されて、employees.department_id索引で一致するエントリが検索されます。概念上、索引は次のようになります。

10,rowid
10,rowid
10,rowid
10,rowid
30,rowid
30,rowid
30,rowid
...

departments表の最初のエントリが部門30の場合、最初の30のエントリが見つかるまで索引のレンジ・スキャンが行われ、見つかった時点で索引の読取りが停止され、一致した行がdepartmentsから返されます。外部ループの次の行が部門20の場合、索引で20のエントリが検索されますが一致は見つからず、外部ループの次の反復処理に移ります。こうして、一致するすべての行が返されるまで処理が行われます。

例9-14 INを使用したセミ結合

次の問合せでは、IN句が使用されて、従業員を含む部門のみが表示されます。

SELECT department_id, department_name
FROM   departments
WHERE  department_id IN
(SELECT department_id
FROM   employees);

実行計画では、手順1にNESTED LOOPS SEMI操作が示されています。

--------------------------------------------------------------------------------
| Id| Operation          | Name              |Rows|Bytes|Cost (%CPU)| Time     |
--------------------------------------------------------------------------------
| 0 | SELECT STATEMENT   |                   |    |     |    2 (100)|          |
| 1 |  NESTED LOOPS SEMI |                   | 11 | 209 |    2   (0)| 00:00:01 |
| 2 |   TABLE ACCESS FULL| DEPARTMENTS       | 27 | 432 |    2   (0)| 00:00:01 |
|*3 |   INDEX RANGE SCAN | EMP_DEPARTMENT_IX | 44 | 132 |    0   (0)|          |
--------------------------------------------------------------------------------

この計画は、例9-13の計画と同じです。

アンチ結合

アンチ結合は、副問合せデータ・セットに一致する行が存在しない場合に、1つ目のデータ・セットから行が返される、2つのデータ・セット間の結合です。セミ結合と同様、アンチ結合でも、最初の一致が見つかった時点で副問合せデータ・セットの処理が停止されます。セミ結合と異なり、アンチ結合では一致が見つからなかった場合のみ行が返されます。

オプティマイザによってアンチ結合が考慮される場合

アンチ結合を使用すると、一致が存在しない場合のみ行を返す必要がある場合に、不必要な処理が避けられます。大きなデータ・セットでは、この最適化によって、外部問合せのすべての行への内部問合せから返されるすべてのレコードを反復処理する必要があるネステッド・ループ結合で、大きな時間の節約が可能です。アンチ結合による最適化は、ネステッド・ループ結合、ハッシュ結合、ソート/マージ結合に適用できます。

次の状況では、オプティマイザによってアンチ結合が選択される可能性があります。

- 文でNOT IN句またはNOT EXISTS句を使用します。

- 文のNOT IN句またはNOT EXISTS句に、副問合せが含まれます。

- NOT IN句またはNOT EXISTS句が、OR分岐の内部に含まれません。

- 次の例のように、外部結合を実行し、IS NULL条件を結合列に適用します。

SET AUTOTRACE TRACEONLY EXPLAIN
SELECT emp.*
FROM   emp, dept
WHERE  emp.deptno = dept.deptno(+)
AND    dept.deptno IS NULL

Execution Plan
----------------------------------------------------------
Plan hash value: 1543991079

---------------------------------------------------------------------------
| Id  | Operation          | Name | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |      |    14 |  1400 |     5  (20)| 00:00:01 |
|*  1 |  HASH JOIN ANTI    |      |    14 |  1400 |     5  (20)| 00:00:01 |
|   2 |   TABLE ACCESS FULL| EMP  |    14 |  1218 |     2   (0)| 00:00:01 |
|   3 |   TABLE ACCESS FULL| DEPT |     4 |    52 |     2   (0)| 00:00:01 |
---------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

1 - access("EMP"."DEPTNO"="DEPT"."DEPTNO")

Note
-----
- dynamic statistics used: dynamic sampling (level=2)

アンチ結合の仕組み

アンチ結合による最適化は、使用される結合のタイプに応じて実装が異なります。次の擬似コードで、ネステッド・ループ結合のアンチ結合を示します。

FOR ds1_row IN ds1 LOOP
match := true;
FOR ds2_row IN ds2 LOOP
IF (ds1_row matches ds2_row) THEN
match := false;
EXIT -- stop processing second data set when a match is found
END IF
END LOOP
IF (match = true) THEN
RETURN ds1_row
END IF
END LOOP

この擬似コードでは、ds1が1つ目のデータ・セットで、ds2が2つ目のデータ・セットです。このコードでは、1つ目のデータ・セットの最初の行が取得され、次に2つ目のデータ・セットの反復処理によって一致が検索されます。一致が見つかった時点で内部ループを抜けて、1つ目のデータ・セットの次の行の処理が開始されます。

例9-15 WHERE EXISTSを使用したセミ結合

次の例では、WHERE EXISTS句を使用して、従業員を含む部門のみが表示されます。

SELECT department_id, department_name
FROM   departments
WHERE EXISTS (SELECT 1
FROM   employees
WHERE  employees.department_id = departments.department_id)

実行計画では、手順1にNESTED LOOPS SEMI操作が示されています。

--------------------------------------------------------------------------------
| Id| Operation          | Name              |Rows|Bytes |Cost(%CPU)| Time     |
--------------------------------------------------------------------------------
| 0 | SELECT STATEMENT   |                   |    |      |   2 (100)|          |
| 1 |  NESTED LOOPS SEMI |                   | 11 |  209 |   2   (0)| 00:00:01 |
| 2 |   TABLE ACCESS FULL| DEPARTMENTS       | 27 |  432 |   2   (0)| 00:00:01 |
|*3 |   INDEX RANGE SCAN | EMP_DEPARTMENT_IX | 44 |  132 |   0   (0)|          |
--------------------------------------------------------------------------------

外部ループを形成するdepartmentsの各行ごとに部門IDが取得されて、employees.department_id索引で一致するエントリが検索されます。概念上、索引は次のようになります。

10,rowid
10,rowid
10,rowid
10,rowid
30,rowid
30,rowid
30,rowid
...

departments表の最初のレコードが部門30の場合、最初の30のエントリが見つかるまで索引のレンジ・スキャンが行われ、見つかった時点で索引の読取りが停止され、一致した行がdepartmentsから返されます。外部ループの次の行が部門20の場合、索引で20のエントリが検索されますが一致は見つからず、外部ループの次の反復処理に移ります。こうして、一致するすべての行が返されるまで処理が行われます。

アンチ結合でNULLが処理される仕組み

セミ結合では、INとEXISTSは、機能的に同じです。ただし、NOT INとNOT EXISTSは、機能的に同等ではありません。この違いはNULLが原因です。NULL値がNOT IN演算子に返される場合、文からはレコードが返されません。この理由を理解するために、次のWHERE句を検討します。

WHERE department_id NOT IN (null, 10, 20)

この式は次のようにテストされます。

WHERE (department_id != null)
AND   (department_id != 10)
AND   (department_id != 20)

式全体がtrueになるには、各条件がtrueになる必要があります。ただし、NULL値は他の値と比較することができないためにdepartment_id !=null条件がtrueになることはできず、したがって式全体がtrueになることができません。次の手法を使用すると、文のNOT IN演算子にNULLが返された場合でも、レコードを返させることができます。

- 副問合せから返された列にNVL関数を適用します。

- 副問合せにIS NOT NULL述語を追加します。

- NOT NULL制約を実装します。

NOT INとは異なり、NOT EXISTS句では、一致の存在を返す述語のみが考慮され、一致のない行やNULLのために判定不可能な行は無視されます。副問合せにおいて、少なくとも1行が外部問合せの行と一致している場合、NOT EXISTSによってfalseが返されます。一致しているタプルが存在しない場合、NOT EXISTSによってtrueが返されます。副問合せにおけるNULLの存在は、一致レコードの検索に影響しません。

Oracle Database 11gより前のリリースでは、副問合せでNULLが返される可能性がある場合に、オプティマイザでアンチ結合による最適化を使用することができませんでした。ただし、Oracle Database 11gからは、次の項で説明するANTI NA (およびANTI SNA)最適化によって、NULLが返される可能性がある場合でも、オプティマイザによるアンチ結合の使用が可能になりました。

例9-16 NOT INを使用したアンチ結合

ユーザーは、NOT IN句を使用した次の問合せを発行して、従業員を含まない部門を表示するとします。

SELECT department_id, department_name
FROM   departments
WHERE  department_id NOT IN
(SELECT department_id
FROM   employees);

この問合せでは、たとえ従業員を含まない部門が複数存在しても、行が返されません。ユーザーの意図とは異なるこのような結果が生じるのは、employees.department_id列がNULL値可能なためです。

実行計画では、手順2にNESTED LOOPS ANTI SNA操作が示されています。

--------------------------------------------------------------------------------
| Id| Operation              | Name              |Rows|Bytes|Cost (%CPU)| Time |
--------------------------------------------------------------------------------
| 0 | SELECT STATEMENT       |                   |    |     | 4(100)|          |
|*1 |  FILTER                |                   |    |     |       |          |
| 2 |   NESTED LOOPS ANTI SNA|                   | 17 | 323 | 4 (50)| 00:00:01 |
| 3 |    TABLE ACCESS FULL   | DEPARTMENTS       | 27 | 432 | 2  (0)| 00:00:01 |
|*4 |    INDEX RANGE SCAN    | EMP_DEPARTMENT_IX | 41 | 123 | 0  (0)|          |
|*5 |   TABLE ACCESS FULL    | EMPLOYEES         |  1 |   3 | 2  (0)| 00:00:01 |
--------------------------------------------------------------------------------

PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter( IS NULL)
4 - access("DEPARTMENT_ID"="DEPARTMENT_ID")
5 - filter("DEPARTMENT_ID" IS NULL)

ANTI SNAは、NULL認識単一アンチ結合を表します。ANTI NAは、NULL認識アンチ結合を表します。NULL認識操作が使用されると、NULL値可能列に対してもセミ結合の使用が可能になります。Oracle Database 11gより前のリリースでは、NULL値が可能な場合にNOT IN問合せでアンチ結合が実行できませんでした。

このユーザーが問合せを書き換えて、副問合せにIS NOT NULL条件を適用するとします。

SELECT department_id, department_name
FROM   departments
WHERE  department_id NOT IN
(SELECT department_id
FROM   employees
WHERE  department_id IS NOT NULL);

この問合せでは16行が返され、意図した結果が得られます。計画の手順1には、ANTI NA結合やANTI SNA結合のかわりに、標準のNESTED LOOPS ANTI結合が示されています。

--------------------------------------------------------------------------------
|Id| Operation          | Name              | Rows| Bytes | Cost (%CPU)| Time  |
--------------------------------------------------------------------------------
| 0| SELECT STATEMENT   |                   |     |       |  2 (100)|          |
| 1|  NESTED LOOPS ANTI |                   |  17 |   323 |  2   (0)| 00:00:01 |
| 2|   TABLE ACCESS FULL| DEPARTMENTS       |  27 |   432 |  2   (0)| 00:00:01 |
|*3|   INDEX RANGE SCAN | EMP_DEPARTMENT_IX |  41 |   123 |  0   (0)|          |
--------------------------------------------------------------------------------

PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------

3 - access("DEPARTMENT_ID"="DEPARTMENT_ID")
filter("DEPARTMENT_ID" IS NOT NULL)

例9-17 NOT EXISTSを使用したアンチ結合

ユーザーは、NOT EXISTS句を使用した次の問合せを発行して、従業員を含まない部門を表示するとします。

SELECT department_id, department_name
FROM   departments d
WHERE  NOT EXISTS
(SELECT null
FROM   employees e
WHERE  e.department_id = d.department_id)

この問合せでは、NOT IN句のNULL問題を回避できます。そのため、たとえemployees.department_id列がNULL値可能な場合でも、意図した結果が得られます。

実行計画の手順1には、ANTI NAバリアントではなく、NESTED LOOPS ANTI操作が示されています(これはNULL値が可能な場合、NOT INに必要です)。

--------------------------------------------------------------------------------
| Id| Operation          | Name              | Rows  | Bytes | Cost (%CPU)|Time|
--------------------------------------------------------------------------------
| 0 | SELECT STATEMENT   |                   |       |       | 2 (100)|        |
| 1 |  NESTED LOOPS ANTI |                   |    17 |   323 | 2   (0)|00:00:01|
| 2 |   TABLE ACCESS FULL| DEPARTMENTS       |    27 |   432 | 2   (0)|00:00:01|
|*3 |   INDEX RANGE SCAN | EMP_DEPARTMENT_IX |    41 |   123 | 0   (0)|        |
--------------------------------------------------------------------------------

PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------

3 - access("E"."DEPARTMENT_ID"="D"."DEPARTMENT_ID")

結合の最適化

Oracle Databaseでは、特定のタイプの結合を最適化できます。

この項では、一般的な結合の最適化について説明します。

- ブルーム・フィルタ

- パーティション・ワイズ結合

ブルーム・フィルタ

作成者Burton Bloomにちなんで名付けられたブルーム・フィルタは、集合の要素かどうかをテストする、低メモリーのデータ構造です。ブルーム・フィルタでは、ある要素が集合に属していない場合は正確に示されますが、ある要素が集合に属している場合は誤って示される場合があります。つまり、偽陰性の可能性はありませんが、擬陽性の可能性があります。

ブルーム・フィルタの目的

ブルーム・フィルタは、値のセットを1つテストして、これらが別のセット(たとえば、セット(10,20,30,40)とセット(10,30,60,70))のメンバーであるかどうかを判断します。このフィルタは、60と70は1つ目のセットのメンバーではないことが保証され、10と30はメンバーの可能性があると判断します。ブルーム・フィルタは、データ・セットのデータ量に比べて、フィルタの格納に必要なメモリー量が小さく、かつほとんどのデータが要素テストに落ちると予想される場合に、特に便利です。

Oracle Databaseでは、次のような様々な目的のためにブルーム・フィルタが使用されます。

- パラレル問合せにおいて、特にほとんどの行が結合条件に一致しないため破棄される場合に、スレーブ・プロセスに転送されるデータ量を低減します。

- パーティション・プルーニングと呼ばれる結合においてパーティション・アクセス・リストを作成する場合に、不必要なパーティションを排除します。

- サーバーの結果キャッシュにデータが存在するかどうかをテストして、ディスクの読取りを回避します。

- 特にスター・スキーマで大きなファクト表と小さなディメンション表を結合する場合に、Exadataセルの要素をフィルタします。

ブルーム・フィルタは、パラレル処理とシリアル処理の両方で実行される可能性があります。

ブルーム・フィルタの仕組み

ブルーム・フィルタでは、集合に含まれるかどうかを示すためにビット配列が使用されます。たとえば、最初は配列の8要素が0に設定されています(8要素は、この例で使用する任意の数です)。

e1 e2 e3 e4 e5 e6 e7 e8
0  0  0  0  0  0  0  0

この配列は集合を表しています。この配列で入力値iを表すために、3つの独立したハッシュ関数が、iに適用され(3つというのは、この例で使用する任意の数です)、それぞれの関数で1から8のハッシュ値が生成されます。

f1(i) = h1
f2(i) = h2
f3(i) = h3

この配列に値17を格納するために、ハッシュ関数でiが17に設定されて、次のハッシュ値が返されます。

f1(17) = 5
f2(17) = 3
f3(17) = 5

この例では、2つのハッシュ関数でたまたま同じ値5が返されました(ハッシュ衝突と呼ばれます)。個別のハッシュ値は5と3であるため、配列の5番目と3番目の要素に1が設定されます。

e1 e2 e3 e4 e5 e6 e7 e8
0  0  1  0  1  0  0  0

17がこの集合の要素かどうかをテストするには、逆の手順が実行されます。値17がこの集合から除外されることをテストするには、要素3または要素5に0が入る必要があります。どちらかの要素に0が入る場合、集合に17が含まれる可能性はありません。偽陰性はありえません。

17がこの集合に包含されることをテストするには、要素3と要素5の両方に1が入る必要があります。ただし、テストで両方の要素に1が入ることが示されても、集合に17が含まれない可能性は残ります。偽陽性はありえます。たとえば、次の配列も要素3と要素5はともに1ですが、値22が表されている可能性があります。

e1 e2 e3 e4 e5 e6 e7 e8
1  0  1  0  1  0  0  0

ブルーム・フィルタの制御

ブルーム・フィルタを使用するかどうかは、オプティマイザで自動的に決定されます。オプティマイザの決定をオーバーライドするには、PX_JOIN_FILTERヒントとNO_PX_JOIN_FILTERヒントを使用します。

関連項目:

ブルーム・フィルタのヒントの詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

ブルーム・フィルタのメタデータ

次の動的パフォーマンス・ビューには、ブルーム・フィルタのメタデータが含まれています。

- V$SQL_JOIN_FILTER
このビューでは、アクティブなブルーム・フィルタで除外された行数(FILTERED列)およびテストされた行数(PROBED列)が表示されます。

- V$PQ_TQSTAT
このビューでは、実行ツリーの各段階ごとに、各パラレル実行サーバーで処理される行数が表示されます。このビューを使用して、パラレル・プロセス間のデータ転送が、ブルーム・フィルタによってどの程度削減されているかが監視できます。

実行計画において、ブルーム・フィルタはOperation列のキーワードJOIN FILTERおよびName列の接頭辞:BFで示されます(次の計画のスニペットの手順9に示されているとおりです)。

----------------------------------------------------------------------------
| Id  | Operation                  | Name     |    TQ  |IN-OUT| PQ Distrib |
----------------------------------------------------------------------------
...
|   9 |      JOIN FILTER CREATE    | :BF0000  |  Q1,03 | PCWP |            |

計画のPredicate Information項において、文字列SYS_OP_BLOOM_FILTERで始まる関数を含むフィルタは、ブルーム・フィルタが使用されていることを示しています。

ブルーム・フィルタ: シナリオ

この例では、パラレル問合せでsalesファクト表がproductsディメンション表およびtimesディメンション表に結合されて、営業週18でフィルタ処理されます。

SELECT /*+ parallel(s) */ p.prod_name, s.quantity_sold
FROM   sh.sales s, sh.products p, sh.times t
WHERE  s.prod_id = p.prod_id
AND    s.time_id = t.time_id
AND    t.fiscal_week_number = 18;

DBMS_XPLAN.DISPLAY_CURSORの問合せによって、次の出力が得られます。

SELECT * FROM
TABLE(DBMS_XPLAN.DISPLAY_CURSOR(format => 'BASIC,+PARALLEL,+PREDICATE'));

EXPLAINED SQL STATEMENT:
------------------------
SELECT /*+ parallel(s) */ p.prod_name, s.quantity_sold FROM sh.sales s,
sh.products p, sh.times t WHERE s.prod_id = p.prod_id AND s.time_id =
t.time_id AND t.fiscal_week_number = 18

Plan hash value: 1183628457

----------------------------------------------------------------------------
| Id  | Operation                  | Name     |    TQ  |IN-OUT| PQ Distrib |
----------------------------------------------------------------------------
|   0 | SELECT STATEMENT           |          |        |      |            |
|   1 |  PX COORDINATOR            |          |        |      |            |
|   2 |   PX SEND QC (RANDOM)      | :TQ10003 |  Q1,03 | P->S | QC (RAND)  |
|*  3 |    HASH JOIN BUFFERED      |          |  Q1,03 | PCWP |            |
|   4 |     PX RECEIVE             |          |  Q1,03 | PCWP |            |
|   5 |      PX SEND BROADCAST     | :TQ10001 |  Q1,01 | S->P | BROADCAST  |
|   6 |       PX SELECTOR          |          |  Q1,01 | SCWC |            |
|   7 |        TABLE ACCESS FULL   | PRODUCTS |  Q1,01 | SCWP |            |
|*  8 |     HASH JOIN              |          |  Q1,03 | PCWP |            |
|   9 |      JOIN FILTER CREATE    | :BF0000  |  Q1,03 | PCWP |            |
|  10 |       BUFFER SORT          |          |  Q1,03 | PCWC |            |
|  11 |        PX RECEIVE          |          |  Q1,03 | PCWP |            |
|  12 |         PX SEND HYBRID HASH| :TQ10000 |        | S->P | HYBRID HASH|
|* 13 |          TABLE ACCESS FULL | TIMES    |        |      |            |
|  14 |      PX RECEIVE            |          |  Q1,03 | PCWP |            |
|  15 |       PX SEND HYBRID HASH  | :TQ10002 |  Q1,02 | P->P | HYBRID HASH|
|  16 |        JOIN FILTER USE     | :BF0000  |  Q1,02 | PCWP |            |
|  17 |         PX BLOCK ITERATOR  |          |  Q1,02 | PCWC |            |
|* 18 |          TABLE ACCESS FULL | SALES    |  Q1,02 | PCWP |            |
----------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

3 - access("S"."PROD_ID"="P"."PROD_ID")
8 - access("S"."TIME_ID"="T"."TIME_ID")
13 - filter("T"."FISCAL_WEEK_NUMBER"=18)
18 - access(:Z>=:Z AND :Z<=:Z)
filter(SYS_OP_BLOOM_FILTER(:BF0000,"S"."TIME_ID"))

シングル・サーバー・プロセスでtimes表がスキャンされ(手順13)、次にハイブリッド・ハッシュ分散方法を使用して、行がパラレル実行サーバーに送信されます(手順12)。セットQ1,03のプロセスによって、ブルーム・フィルタが作成されます(手順9)。セットQ1,02のプロセスによってsalesがパラレルでスキャンされ(手順18)、次にハイブリッド・ハッシュ分散によって行がセットQ1,03に送信される(手順15)前に、ブルーム・フィルタの使用によって行がsalesから破棄されます(手順16)。セットQ1,03のプロセスによって、times行がフィルタ処理済のsales行にハッシュ結合されます(手順8)。セットQ1,01のプロセスによってproductsがスキャンされた後(手順7)、行がQ1,03に送信されます(手順5)。最後にQ1,03のプロセスによって、products行が前回のハッシュ結合で生成された行に結合されます(手順3)。

次の図に、基本的なプロセスを示します。

図9-7 ブルーム・フィルタ

パーティション・ワイズ結合

パーティション・ワイズ結合は、2つの表の大規模な結合を分割する最適化です(一方の表が、結合キーで複数の小規模な結合にパーティション化されている必要があります)。

パーティション・ワイズ結合は、次のいずれかです。

- フル・パーティション・ワイズ結合
両方の表が、結合キーによって同一レベル・パーティション化されているか、参照パーティション化されている(つまり、参照制約によって関連付けられている)必要があります。2つのパーティション間で2つの結合済表から、大きな結合が小さな結合に分割されます。

- パーシャル・パーティション・ワイズ結合
1つの表のみが、結合キーでパーティション化されます。もう一方の表は、パーティション化してもしなくてもかまいません。

関連項目:

『Oracle Database VLDBおよびパーティショニング・ガイド』には、パーティション・ワイズ結合の詳細な説明があります。

パーティション・ワイズ結合の目的

パーティション・ワイズ結合では、結合がパラレルで実行されるときにパラレル実行サーバー間で交換されるデータ量が最小限に抑えられ、問合せのレスポンス時間が短縮されます。この手法により、レスポンス時間は大幅に短縮され、CPUとメモリーの使用率が改善されます。Oracle Real Application Clusters (Oracle RAC)環境では、パーティション・ワイズ結合でも、インターコネクトでのデータ・トラフィックが回避されるか、少なくとも制限されます。これは、大規模な結合操作で優れたスケーラビリティを実現するために重要です。

パーティション・ワイズ結合の仕組み

2つのパーティション化された表が、パーティション・ワイズ結合を使用することなくシリアル結合される場合は、シングル・サーバー・プロセスによって結合が実行されます。

次の図では、シングル・サーバー・プロセスによって表t1のすべてのパーティションが表t2のすべてのパーティションに結合されているため、結合はパーティション・ワイズではありません。

図9-8 パーティション・ワイズではない結合

フル・パーティション・ワイズ結合の仕組み

フル・パーティション・ワイズ結合がシリアルまたはパラレルで実行されます。

次の図は、パラレルで実行されたフル・パーティション・ワイズ結合を示しています。この場合、並列度のグラニュルはパーティションです。各パラレル実行サーバーにおいて、パーティションが対になって結合されます。たとえば、1つ目のパラレル実行サーバーでは、t1の1つ目のパーティションがt2の1つ目のパーティションと結合されます。その結果が、パラレル実行コーディネータで組み合わされます。

図9-9 パラレルでのフル・パーティション・ワイズ結合

フル・パーティション・ワイズ結合によって、パーティションをサブパーティションに結合することも可能です(各表で異なるパーティション化の方法が使用されている場合に有益です)。たとえば、customersはハッシュでパーティション化されていますが、salesは、レンジでパーティション化されているとします。salesをハッシュでサブパーティション化すると、customersのハッシュ・パーティションとsalesのハッシュ・サブパーティションとの間でフル・パーティション・ワイズ結合を実行できます。

次のスニペットのように、実行計画において結合前にパーティション操作が実行される場合は、フル・パーティション・ワイズ結合が実行されることを示唆しています。

|   8 |         PX PARTITION HASH ALL|
|*  9 |          HASH JOIN           |

関連項目:

『Oracle Database VLDBおよびパーティショニング・ガイド』には、パーティション・ワイズ結合の詳細な説明があり、いくつかの例が紹介されています。

パーシャル・パーティション・ワイズ結合の仕組み

フル・パーティション・ワイズ結合と異なり、パーシャル・パーティション・ワイズ結合はパラレルで実行される必要があります。

次の図は、パーティション化されているt1とパーティション化されていないt2の間のパーシャル・パーティション・ワイズ結合を示しています。

図9-10 パーシャル・パーティション・ワイズ結合

t2はパーティション化されていないため、必要に応じ、パラレル実行サーバーのセットによって、t2からパーティションが生成される必要があります。次に、別のパラレル実行サーバーのセットによって、t1のパーティションが、動的に生成されるパーティションに結合されます。その結果が、パラレル実行コーディネータで組み合わされます。

次のスニペットのように、実行計画におけるPX SEND PARTITION (KEY)操作は、パーシャル・パーティション・ワイズ結合が実行されることを示唆しています。

|  11 |            PX SEND PARTITION (KEY)    |

関連項目:

『Oracle Database VLDBおよびパーティショニング・ガイド』には、パーティション・ワイズ結合の詳細な説明があり、いくつかの例が紹介されています。

第V部 オプティマイザ統計

オプティマイザは、実行計画を作成する際に統計に依存します。

この部には次の章が含まれます:

- オプティマイザ統計の概念

- ヒストグラム

- オプティマイザ統計の管理: 基本的なトピック

- オプティマイザ統計の管理: 高度なトピック

10 オプティマイザ統計の概念

Oracle Databaseのオプティマイザ統計は、データベースおよびそのオブジェクトに関する詳細を表します。

この章の内容は次のとおりです。

- オプティマイザ統計の概要

- オプティマイザ統計のタイプについて

- データベースがオプティマイザ統計を収集する方法

- データベースがオプティマイザ統計を収集する場合

関連項目:

- 問合せオプティマイザの概念

- ヒストグラム

- 「オプティマイザ統計の管理: 基本的なトピック」

- オプティマイザ統計の管理: 高度なトピック

オプティマイザ統計の概要

オプティマイザのコスト・モデルは、問合せに関連するオブジェクトについて収集された統計および問合せが実行されるデータベースとホストに基づきます。

統計は、オプティマイザが各SQL文に対して最適な実行計画を選択するために不可欠のものです。

オプティマイザ統計には次のものがあります。

- 表統計

- 行数

- ブロック数

- 行の平均長さ

- 列統計

- 列内の個別値(NDV)数

- 列内のNULL数

- データ配分(ヒストグラム)

- 拡張統計

- 索引統計

- リーフ・ブロック数

- レベル数

- 索引クラスタ化係数

- システム統計

- I/Oパフォーマンスと使用率

- CPUパフォーマンスと使用率

図10-1に示されているように、データベースでは、表、列、索引およびシステムのオプティマイザ統計がデータ・ディクショナリに格納されます。これらの統計は、データ・ディクショナリ・ビューを使用してアクセスできます。

注意:

オプティマイザ統計は、V$ビューで参照可能なパフォーマンス統計とは異なるものです。

図10-1 オプティマイザ統計

オプティマイザ統計のタイプについて

オプティマイザは、様々なタイプのデータベース・オブジェクトおよび様々な特性のデータベース環境で統計を収集します。

この項の内容は次のとおりです。

- 表統計

- 列統計

- 索引統計

- グローバル一時表のセッション固有統計

- システム統計

- ユーザー定義のオプティマイザ統計

表統計

Oracle Databaseの表統計には、行およびブロックに関する情報が含まれます。

オプティマイザは、これらの統計を使用して、表スキャンおよび表結合のコストを判断します。DBMS_STATSは、永続表と一時表の両方の統計を収集できます。

データベースは、永続表に関するすべての関連統計を追跡します。DBMS_STATS.GATHER_TABLE_STATSは、永続表での統計の収集前にコミットされます。たとえば、DBA_TAB_STATISTICSに格納された表統計は、次のものを追跡します。

- 行数および行の長さの平均
データベースでは、カーディナリティの判定の際、DBA_TAB_STATISTICSに格納された行カウントが使用されます。

- データ・ブロック数
オプティマイザは、DB_FILE_MULTIBLOCK_READ_COUNT初期化パラメータに指定されているデータ・ブロックの数を使用して、実表のアクセス・コストを判断します。

例10-1 表統計

この例では、sh.customers表の一部の表統計を問い合せます。

sys@PROD> SELECT NUM_ROWS, AVG_ROW_LEN, BLOCKS, LAST_ANALYZED
2  FROM   DBA_TAB_STATISTICS
3  WHERE  OWNER='SH'
4  AND    TABLE_NAME='CUSTOMERS';

NUM_ROWS AVG_ROW_LEN     BLOCKS LAST_ANAL
---------- ----------- ---------- ---------
55500         181       1486 14-JUN-10

関連項目:

- 「オプティマイザの初期化パラメータについて」

- 「スキーマ統計および表統計の収集」

- DBA_TAB_STATISTICSビューおよびDB_FILE_MULTIBLOCK_READ_COUNT初期化パラメータの詳細は、『Oracle Databaseリファレンス』を参照してください

列統計

列統計では、列値およびデータ配分に関する情報が追跡されます。

オプティマイザは、列統計を使用して、正確なカーディナリティの見積りを生成し、索引の使用、結合順序、結合方法などについてより適切な決定を行います。たとえば、DBA_TAB_COL_STATISTICSの統計は、次のものを追跡します。

- 個別値の数。

- NULLの数

- 上限値および下限値

- ヒストグラム関連情報

オプティマイザは拡張統計を使用できます。これは特殊な列統計です。これらの統計は、オプティマイザに列間の論理的な関係を伝える場合に役立ちます。

関連項目:

- ヒストグラム

- 「列グループの統計について」

- DBA_TAB_COL_STATISTICSビューの詳細は、『Oracle Databaseリファレンス』を参照してください

索引統計

索引統計には、索引レベルの数、索引ブロックの数および索引とデータ・ブロックの関係に関する情報が含まれます。オプティマイザは、これらの統計を使用して、索引スキャンのコストを判断します。

索引統計のタイプ

DBA_IND_STATISTICSビューは索引統計を追跡します。

統計には次のものがあります。

- レベル
BLEVEL列には、ルート・ブロックからリーフ・ブロックに達するまでに必要なブロックの数が示されます。Bツリー索引には、検索用のブランチ・ブロックと、値を格納するリーフ・ブロックの2種類のブロックがあります。Bツリー索引の概要は、『Oracle Database概要』を参照してください。

- 個別キー
この列は、索引が付けられた個別値の数を追跡します。一意制約が定義され、かつNOT NULL制約は定義されていない場合、この値は、NULL以外の値の数と等しくなります。

- 索引が付けられた各個別キーのリーフ・ブロックの平均数

- 索引が付けられた各個別キーによってポイントされたデータ・ブロックの平均数

関連項目:

DBA_IND_STATISTICSビューの詳細は、『Oracle Databaseリファレンス』を参照してください

例10-2 索引統計

この例では、sh.customers表のcust_lname_ixおよびcustomers_pk索引の一部の索引統計を問い合せます(出力例も示します)。

SELECT INDEX_NAME, BLEVEL, LEAF_BLOCKS AS "LEAFBLK", DISTINCT_KEYS AS "DIST_KEY",
AVG_LEAF_BLOCKS_PER_KEY AS "LEAFBLK_PER_KEY",
AVG_DATA_BLOCKS_PER_KEY AS "DATABLK_PER_KEY"
FROM   DBA_IND_STATISTICS
WHERE  OWNER = 'SH'
AND    INDEX_NAME IN ('CUST_LNAME_IX','CUSTOMERS_PK');

INDEX_NAME     BLEVEL LEAFBLK DIST_KEY LEAFBLK_PER_KEY DATABLK_PER_KEY
-------------- ------ ------- -------- --------------- ---------------
CUSTOMERS_PK        1     115    55500               1               1
CUST_LNAME_IX       1     141      908               1              10

索引クラスタ化係数

Bツリー索引では、索引クラスタ化係数により、姓などの索引値との関連で行の物理グループ化が測定されます。

索引クラスタ化係数は、オプティマイザが、特定の問合せで索引スキャンと全表スキャンのいずれがより効率的かを判断するのに役立ちます)。クラスタ化係数が低い場合は、索引スキャンが効率的であることを示しています。

表内のブロックの数に近いクラスタ化係数は、行が索引キーによって表ブロック内で物理的に順序付けられていることを示します。データベースが全表スキャンを実行した場合、データベースは、多くの場合、ディスク上に格納されているとおりに(行は索引キーによってソートされています)行を取得します。行の数に近いクラスタ化係数は、行が索引キーとの関連でデータベース・ブロックにランダムに分散されていることを示します。データベースが全表スキャンを実行する場合、データベースは、この索引キーによってソートされた順番では行を取得しません。

クラスタ化係数は、特定の索引のプロパティであって、表のプロパティではありません。表に複数の索引が存在する場合、ある索引のクラスタ化係数は小さく、別の索引のクラスタ化係数は大きい値になる可能性があります。表を再編成してある索引のクラスタ化係数を改善しようとすると、別の索引のクラスタ化係数が低下することがあります。

例10-3 索引クラスタ化係数

この例は、オプティマイザが、索引を使用するほうが全表スキャンよりも効果的であるかどうかを判断するために索引クラスタ化係数をどのように使用するかを示しています。

1. SQL*Plusを起動し、shとしてデータベースに接続します。そして、sh.customers表内の行とブロックの数を問い合せます(出力例も示します)。

SELECT  table_name, num_rows, blocks
FROM    user_tables
WHERE   table_name='CUSTOMERS';

TABLE_NAME                       NUM_ROWS     BLOCKS
------------------------------ ---------- ----------
CUSTOMERS                           55500       1486

2. customers.cust_last_name列で索引を作成します。
たとえば、次の文を実行します。

CREATE INDEX CUSTOMERS_LAST_NAME_IDX ON customers(cust_last_name);

3. 新たに作成された索引の索引クラスタ化係数を問い合せます。
次の問合せは、クラスタ化係数が表内のブロック数よりもはるかに大きいため、customers_last_name_idx索引のクラスタ化係数が高いことを示しています。

SELECT index_name, blevel, leaf_blocks, clustering_factor
FROM   user_indexes
WHERE  table_name='CUSTOMERS'
AND    index_name= 'CUSTOMERS_LAST_NAME_IDX';

INDEX_NAME                         BLEVEL LEAF_BLOCKS CLUSTERING_FACTOR
------------------------------ ---------- ----------- -----------------
CUSTOMERS_LAST_NAME_IDX                 1         141              9859

4. customers表の新しいコピーを作成し、cust_last_nameで行をソートします。
たとえば、次の文を実行します。

DROP TABLE customers3 PURGE;
CREATE TABLE customers3 AS
SELECT *
FROM   customers
ORDER BY cust_last_name;

5. このcustomers3表の統計情報データを収集します。
たとえば、GATHER_TABLE_STATSプロシージャを次のように実行します。

EXEC DBMS_STATS.GATHER_TABLE_STATS(null,'CUSTOMERS3');

6. customers3表内の行とブロックの数を問い合せます。
たとえば、次の問合せを入力します(出力例も示します)。

SELECT    TABLE_NAME, NUM_ROWS, BLOCKS
FROM      USER_TABLES
WHERE     TABLE_NAME='CUSTOMERS3';

TABLE_NAME                       NUM_ROWS     BLOCKS
------------------------------ ---------- ----------
CUSTOMERS3                          55500       1485

7. customers3のcust_last_name列で索引を作成します。
たとえば、次の文を実行します。

CREATE INDEX CUSTOMERS3_LAST_NAME_IDX ON customers3(cust_last_name);

8. customers3_last_name_idx索引の索引クラスタ化係数を問い合せます。
次の問合せは、customers3_last_name_idx索引のクラスタ化係数がより低いことを示しています。

SELECT INDEX_NAME, BLEVEL, LEAF_BLOCKS, CLUSTERING_FACTOR
FROM   USER_INDEXES
WHERE  TABLE_NAME = 'CUSTOMERS3'
AND    INDEX_NAME = 'CUSTOMERS3_LAST_NAME_IDX';

INDEX_NAME                         BLEVEL LEAF_BLOCKS CLUSTERING_FACTOR
------------------------------ ---------- ----------- -----------------
CUSTOMERS3_LAST_NAME_IDX                1         141              1455

表customers3には元のcustomers表と同じデータがありますが、customers3表内のデータはcust_last_nameでソートされているため、この表の索引のクラスタ化係数は大幅に低くなっています。クラスタ化係数は、ブロック数の70倍から10倍になっています。

9. customers表を問い合せます。
たとえば、次の問合せを実行します(出力例も示します)。

SELECT cust_first_name, cust_last_name
FROM   customers
WHERE  cust_last_name BETWEEN 'Puleo' AND 'Quinn';

CUST_FIRST_NAME      CUST_LAST_NAME
-------------------- ----------------------------------------
Vida                 Puleo
Harriett             Quinlan
Madeleine            Quinn
Caresse              Puleo

10. 問合せのカーソルを表示します。
たとえば、次の問合せを実行します(出力例の一部も示します)。

SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR());

-------------------------------------------------------------------------------
| Id | Operation                 | Name      | Rows |Bytes|Cost (%CPU)| Time  |
-------------------------------------------------------------------------------
|   0| SELECT STATEMENT          |           |      |     | 405 (100)|        |
|*  1|  TABLE ACCESS STORAGE FULL| CUSTOMERS |  2335|35025| 405   (1)|00:00:01|
-------------------------------------------------------------------------------

前述の計画は、オプティマイザが元のcustomers表の索引を使用しなかったことを示しています。

11. customers3表を問い合せます。
たとえば、次の問合せを実行します(出力例も示します)。

SELECT cust_first_name, cust_last_name
FROM   customers3
WHERE  cust_last_name BETWEEN 'Puleo' AND 'Quinn';

CUST_FIRST_NAME      CUST_LAST_NAME
-------------------- ----------------------------------------
Vida                 Puleo
Harriett             Quinlan
Madeleine            Quinn
Caresse              Puleo

12. 問合せのカーソルを表示します。
たとえば、次の問合せを実行します(出力例の一部も示します)。

SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR());

---------------------------------------------------------------------------------------
|Id| Operation                   | Name                   |Rows|Bytes|Cost(%CPU)| Time|
---------------------------------------------------------------------------------------
| 0| SELECT STATEMENT            |                        |    |     |69(100)|        |
| 1|  TABLE ACCESS BY INDEX ROWID|CUSTOMERS3              |2335|35025|69(0)  |00:00:01|
|*2|   INDEX RANGE SCAN          |CUSTOMERS3_LAST_NAME_IDX|2335|     |7(0)   |00:00:01|
---------------------------------------------------------------------------------------

結果セットは同じですが、オプティマイザは索引を選択します。この計画のコストは、元のcustomers表で使用された計画のコストより大幅に低下しています。

13. オプティマイザが索引を使用するように強制するヒントとともにcustomersを問い合せます。
たとえば、次の問合せを実行します(出力例の一部も示します)。

SELECT /*+ index (Customers CUSTOMERS_LAST_NAME_IDX) */ cust_first_name,
cust_last_name
FROM   customers
WHERE  cust_last_name BETWEEN 'Puleo' and 'Quinn';

CUST_FIRST_NAME      CUST_LAST_NAME
-------------------- ----------------------------------------
Vida                 Puleo
Caresse              Puleo
Harriett             Quinlan
Madeleine            Quinn

14. 問合せのカーソルを表示します。
たとえば、次の問合せを実行します(出力例の一部も示します)。

SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR());

-----------------------------------------------------------------------------------------
| Id  | Operation                | Name                  |Rows|Bytes|Cost(%CPU)| Time   |
-----------------------------------------------------------------------------------------
| 0| SELECT STATEMENT            |                       |    |     | 422(100) |        |
| 1|  TABLE ACCESS BY INDEX ROWID|CUSTOMERS              |335 |35025| 422(0)   |00:00:01|
|*2|   INDEX RANGE SCAN          |CUSTOMERS_LAST_NAME_IDX|2335|     | 7(0)     |00:00:01|
-----------------------------------------------------------------------------------------

前述の計画は、customersの索引を使用するコストは全表スキャンよりも高いことを示しています。したがって、索引の使用によりパフォーマンスが向上するとはかぎりません。索引クラスタ化係数は、索引スキャンのほうが全表スキャンよりも効果的であるかどうかを判断するための目安です。

索引クラスタ化係数がコストに与える影響: 例

この例は、索引クラスタ化係数が表アクセスのコストにどのように影響するかを説明しています。

次の使用例を考えてみます。

- 表には9つの行があり、それらは3つのデータ・ブロックに格納されています。

- col1列は現在、値A、BおよびCを格納しています。

- この表では、col1_idxという名前の非一意索引がcol1に存在します。

例10-4 配列されているデータ

次のように行がデータ・ブロックに格納されていると仮定します。

Block 1       Block 2        Block 3
-------       -------        -------
A  A  A       B  B  B        C  C  C

この例では、col1_idxの索引クラスタ化係数は低くなります。c1に対して同じ索引付きの列の値を持つ行が、表の中の同じデータ・ブロック内にあります。そのため、索引レンジ・スキャンを使用して値Aを持つすべての行を戻す場合、表の中のブロックを1つのみ読み取れば済むため、低いコストで済みます。

例10-5 分散されているデータ

次のように同じ行が複数のデータ・ブロックに分散されていると仮定します。

Block 1       Block 2        Block 3
-------       -------        -------
A  B  C       A  C  B        B  A  C

この例では、col1_idxの索引クラスタ化係数は高くなります。データベースは、表の中の3つのブロックをすべて読み取って、col1内に値Aを持つすべての行を取得する必要があります。

関連項目:

DBA_INDEXESビューの詳細は、『Oracle Databaseリファレンス』を参照してください

グローバル一時表のセッション固有統計

グローバル一時表は、特定の期間、セッション固有の中間データを格納する特殊な表です。

CREATE GLOBAL TEMPORARY TABLEのON COMMIT句は、表がトランザクション固有(DELETE ROWS)であるか、セッション固有(PRESERVE ROWS)であるかを示します。こうして、一時表には、トランザクションまたはセッションのいずれかの間、中間結果セットが保持されます。

グローバル一時表を作成するとき、すべてのセッションで参照できる定義を作成します。物理記憶域は割り当てられません。セッションが最初に表にデータを配置する際、データベースは記憶域を割り当てます。一時表内のデータは、現在のセッションのみが参照できます。

グローバル一時表の共有統計およびセッション固有統計

Oracle Database 12cからは、表レベルのプリファレンスGLOBAL_TEMP_TABLE_STATSを設定して、グローバル一時表の統計を共有するか(SHARED)、セッション固有のものとするか(SESSION)を選択できるようになりました。

GLOBAL_TEMP_TABLE_STATSがSESSIONの場合、1つのセッションでグローバル一時表の統計を収集できますが、統計はこのセッションでのみ使用できます。その一方で、ユーザーは共有バージョンの統計を引き続き維持できます。オプティマイザは、最適化時にはまずグローバル一時表にセッション固有の統計があるかどうかを確認します。ある場合、オプティマイザはそれらを使用します。ない場合は、共有の統計があればそれを使用します。

注意:

Oracle Database 12cより前のリリースでは、データベースで、グローバル一時表と非グローバル一時表のオプティマイザ統計は別々に維持されていませんでした。別々のセッションのデータが異なっている可能性があっても、データベースでは、すべてのセッションで共有されている統計の1つのバージョンが維持されていました。

セッション固有のオプティマイザ統計は、次のような特性を持っています。

- 統計を追跡するディクショナリ・ビューには、共有の統計と現在のセッションのセッション固有の統計の両方が表示されます。
ビューは、DBA_TAB_STATISTICS、DBA_IND_STATISTICS、DBA_TAB_HISTOGRAMSおよびDBA_TAB_COL_STATISTICSです(各ビューには、対応するUSER_およびALL_バージョンがあります)。SCOPE列は、統計がセッション固有であるか、共有であるかを示します。セッション固有の統計は、複数のプロセスがOracle RACでこれらの統計にアクセスできるように、データ・ディクショナリに格納する必要があります。

- CREATE ... AS SELECTでは、オプティマイザ統計を自動収集します。ただし、GLOBAL_TEMP_TABLE_STATSがSHAREDに設定されている場合、DBMS_STATSを使用して統計を手動で収集する必要があります。

- 保留中の統計情報はサポートされていません。

- 他のセッションでは、セッション固有の統計を使用するカーソルを共有しません。
Oracle Database 12cより前のリリースと同様に、共有されている統計を使用するカーソルは、別のセッションでも共有できます。同一セッションでは、セッション固有の統計を使用するカーソルを共有できます。

- デフォルトでは、一時表のGATHER_TABLE_STATSは、同一セッションでコンパイルされた直前のカーソルを即座に無効にします。ただし、この手順によって、他のセッションでコンパイルされたカーソルが無効になることはありません。

関連項目:

- GLOBAL_TEMP_TABLE_STATSプリファレンスの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください

- DBA_TAB_STATISTICSビューの詳細は、『Oracle Databaseリファレンス』を参照してください

トランザクション固有一時表へのDBMS_STATSの影響

DBMS_STATSは、セッション固有のグローバル一時表への変更をコミットしますが、トランザクション固有のグローバル一時表への変更はコミットしません。

Oracle Database 12cより前は、トランザクション固有の一時表(ON COMMIT DELETE ROWS)でDBMS_STATS.GATHER_TABLE_STATSを実行すると、表内のすべての行が削除され、統計ではその表が空と表示されていました。Oracle Database 12cからは、次のプロシージャにおいてトランザクション固有の一時表へのコミットが行われないため、これらの表の行が削除されることはありません。

- GATHER_TABLE_STATS

- DELETE_TABLE_STATS

- DELETE_COLUMN_STATS

- DELETE_INDEX_STATS

- SET_TABLE_STATS

- SET_COLUMN_STATS

- SET_INDEX_STATS

- GET_TABLE_STATS

- GET_COLUMN_STATS

- GET_INDEX_STATS

前述のプログラム・ユニットはGLOBAL_TEMP_TABLE_STATSプリファレンスを確認します。たとえば、表プリファレンスがSESSIONに設定されている場合、SET_TABLE_STATSによってセッション統計が設定され、GATHER_TABLE_STATSによってトランザクション固有一時表のすべての行が保存されます。たとえば、表プリファレンスがSHAREDに設定されている場合、SET_TABLE_STATSによって共有統計が設定され、GATHER_TABLE_STATSによってトランザクション固有一時表のすべての行が削除されます。

関連項目:

- 「スキーマ統計および表統計の収集」

- グローバル一時表の詳細は、『Oracle Database概要』を参照してください

- DBMS_STATS.GATHER_TABLE_STATSプロシージャの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

システム統計

システム統計は、ハードウェア特性(I/O、CPUのパフォーマンスおよび使用率など)を記述します。

システム統計を使用すると、問合せオプティマイザは、実行計画を選択する際に、I/OおよびCPUコストをより正確に見積ることができます。システム統計の更新時には、解析済のSQL文は無効にされません。データベースでは、新しいSQL文はすべて、新しい統計を使用して解析されます。

関連項目:

- 「システム統計の手動収集」

- 『Oracle Databaseリファレンス』

ユーザー定義のオプティマイザ統計

ユーザー定義ファンクションおよび索引の作成者は、拡張可能オプティマイザを使用して、統計集計ファンクション、選択ファンクションおよびコスト・ファンクションを作成できます。オプティマイザのコスト・モデルは拡張されて、CPUおよびI/Oコストを評価するために、ユーザーによって提供される情報が統合されます。

統計タイプは、実行計画の選択に影響を与えるユーザー定義関数のインタフェースとして機能します。ただし、統計タイプを使用するために、オプティマイザでは、列、スタンドアロン・ファンクション、オブジェクト型、索引、索引タイプ、パッケージなどのデータベース・オブジェクトにタイプをバインドするメカニズムが必要です。SQL文ASSOCIATE STATISTICSによりこのバインドが発生することがあります。

ユーザー定義の統計のファンクションは、標準SQLデータ型およびオブジェクト型の両方を使用する列、およびドメイン索引に関連しています。統計タイプを列またはドメイン索引に関連付ける場合、DBMS_STATSによって統計が収集されるたびに、統計タイプの統計コレクション・メソッドがコールされます。

関連項目:

- 「スキーマ統計および表統計の収集」

- 拡張可能オプティマイザおよびユーザー定義統計の詳細は、Oracle Databaseデータ・カートリッジ開発者ガイドを参照してください

データベースがオプティマイザ統計を収集する方法

Oracle Databaseには、統計を収集するためのいくつかのメカニズムがあります。

この項の内容は次のとおりです。

- DBMS_STATSパッケージ

- 補足的な動的統計

- バルク・ロードのためのオンライン統計収集

DBMS_STATSパッケージ

DBMS_STATS PL/SQLパッケージは、オプティマイザ統計を収集および管理します。

このパッケージにより、統計収集の並列度、サンプリング方法、パーティション表での統計収集の粒度など、どの統計をどのように収集するかを制御できます。

注意:

オプティマイザ統計の収集に、ANALYZE文でCOMPUTE句およびESTIMATE句を使用しないでください。これらの句は非推奨になりました。かわりに、DBMS_STATSを使用します。

DBMS_STATSパッケージによって収集される統計は、正確な実行計画を作成するために必要です。たとえば、DBMS_STATSによって収集される表統計には、行の数、ブロックの数、行の長さの平均などがあります。

デフォルトでは、自動オプティマイザ統計収集が使用されます。この場合、データベースでは、DBMS_STATSが自動的に実行され、統計がないか失効しているすべてのスキーマ・オブジェクトのオプティマイザ統計が自動的に収集されます。このプロセスは、オプティマイザの管理に関連する多数の手動タスクが削減し、統計の欠如または失効のために最適ではない実行計画が生成されるリスクを大幅に減らします。DBMS_STATSを手動で実行することで、オプティマイザ統計を更新して管理することもできます。

関連項目:

- 「自動オプティマイザ統計収集の構成」

- 「オプティマイザ統計の手動収集」

- 自動メンテナンス・タスクの詳細は、『Oracle Database管理者ガイド』を参照してください

- DBMS_STATSの詳細は、Oracle Database PL/SQLパッケージ・プロシージャおよびタイプ・リファレンスを参照してください

補足的な動的統計

デフォルトでは、オプティマイザ統計が存在しないか、失効しているか、不十分な場合、データベースでは、解析中に動的統計が自動的に収集されます。データベースでは、再帰的SQLを使用して、表ブロックの小さなランダム・サンプルがスキャンされます。

注意:

動的統計は、統計にかわるものを提供するのではなく、統計を増強します。

動的統計は、表および索引のブロック・カウント、表および結合のカーディナリティ(概算行数)、結合列の統計、GROUP BY統計などのオプティマイザ統計を補完します。この情報により、オプティマイザは、述語のカーディナリティに対してより正確な見積りを行うことで、計画を改善できます。

動的統計にメリットがあるのは、次の場合です。

- 複雑な述語のために、実行計画が最適ではなくなっている場合。

- サンプリングにかかる時間が、問合せの実行時間全体のごく一部である場合。

- サンプリング時間をならすために、問合せが何度も実行される場合。

関連項目:

- 「データベースがデータをサンプリングする場合」

- 「サンプル・サイズの設定のガイドライン」

- 「動的統計の制御」

バルク・ロードのためのオンライン統計収集

Oracle Database 12cからは、次のタイプのバルク・ロード時に表統計を自動的に収集できるようになりました。ダイレクト・パス・インサートを使用した、空の表へのINSERT INTO ... SELECTおよびCREATE TABLE AS SELECT。

注意:

デフォルトでは、パラレル・インサートはダイレクト・パス・インサートを使用します。/*+APPEND*/ヒントを使用して、ダイレクト・パス・インサートを強制することができます。

この項の内容は次のとおりです。

- バルク・ロードのためのオンライン統計収集の目的

- 空のパーティション化された表への挿入時のグローバル統計

- バルク・ロード時の索引統計およびヒストグラム

- バルク・ロードのためのオンライン統計収集の制限

- バルク・ロードのためのオンライン統計収集のヒント

関連項目:

バルク・ロードの詳細は、『Oracle Databaseデータ・ウェアハウス・ガイド』を参照してください。

バルク・ロードのためのオンライン統計収集の目的

一般に、データ・ウェアハウスからは、大量のデータがデータベースにロードされます。たとえば、販売データ・ウェアハウスでは、毎晩販売データをロードすることが考えられます。

Oracle Database 12cより前のリリースでは、失効した統計によって計画が最適なものとならない可能性を避けるため、バルク・ロードの後に手動で統計を収集する必要がありました。バルク・ロード時の自動統計収集機能には、次のような利点があります。

- パフォーマンスの向上
ロード中に統計を収集することで、表統計を収集するための追加の表スキャンを回避できます。

- 管理性の向上
バルク・ロード後、統計を収集するためのユーザーの操作は必要ありません。

空のパーティション化された表への挿入時のグローバル統計

空のパーティション化された表に行を挿入する場合、挿入時にグローバル統計が収集されます。

たとえば、salesが空のパーティション表である場合およびINSERT INTO sales SELECTを実行する場合、データベースはsalesのグローバル統計を収集します。ただし、データベースではパーティション・レベルの統計を収集しません。

拡張構文を使用して行を空である特定のパーティションまたはサブパーティションに挿入する別のケースを仮定します。データベースでは、挿入中に空のパーティションの統計を収集します。ただし、グローバル統計は収集しません。

INSERT INTO sales PARTITION (sales_q4_2000) SELECTを実行するとします。挿入前にパーティションsales_q4_2000が空である場合(他のパーティションは空である必要はありません)、データベースでは挿入中に統計を収集します。さらに、INCREMENTALプリファレンスがsalesで有効化されている場合は、sales_q4_2000のシノプシスも収集されます。統計はINSERT文の直後に使用できます。ただし、トランザクションをロールバックすると、バルク・ロード中に収集された統計は自動的に削除されます。

関連項目:

- 「増分統計メンテナンスの考慮事項」

- INSERTの構文およびセマンティクスについては、Oracle Database SQL言語リファレンスを参照してください

バルク・ロード時の索引統計およびヒストグラム

オンラインでの統計の収集時、データベースでは、索引統計は収集されずヒストグラムは作成されません。これらの統計が必要な場合には、バルク・ロード後にDBMS_STATS.GATHER_TABLE_STATSのoptionsパラメータをGATHER AUTOに設定して実行することをお薦めします。

たとえば、次のコマンドによって、バルク・ロードされたsh_ctas表の統計が収集されます。

EXEC DBMS_STATS.GATHER_TABLE_STATS( user, 'SH_CTAS', options => 'GATHER AUTO' );

この例では、見つからないか、失効している統計のみ収集されます。バルク・ロード時に収集される表統計および基本列統計は収集されません。

注意:

バルク・ロードする表の表プリファレンスoptionsをGATHER AUTOに設定できます。このようにすることで、GATHER_TABLE_STATSの実行時にoptionsパラメータを明示的に設定する必要がなくなります。

関連項目:

- 「スキーマ統計および表統計の収集」

- バルク・ロードの詳細は、『Oracle Databaseデータ・ウェアハウス・ガイド』を参照してください

バルク・ロードのためのオンライン統計収集の制限

状況によっては、バルク・ロードのための統計収集は自動的に発生しません。

ターゲット表、パーティションまたはサブパーティションが次のいずれかの条件に該当する場合、バルク・ロードの統計は収集されません。

- 空ではなく、INSERT INTO ... SELECTを実行します。
この場合、OPTIMIZER STATISTICS GATHERING行ソースは計画に表示されますが、この行ソースはパス・スルーされるにすぎません。オプティマイザ統計は、実際には収集されません。

注意:

空の表へのバルク・ロードによって、DBA_TAB_COL_STATISTICS.NOTES列はSTATS_ON_LOADに設定されます。ただし、空ではない表へのその後のバルク・ロードでは、NOTES列がリセットされません、。統計が収集されているかどうかを判別する1つの手法は、DBMS_STATS.FLUSH_DATABASE_MONITORING_INFOを実行して、USER_TAB_MODIFICATIONS.INSERTSを問い合せることです。問合せによってロードされた行数を示す行が返された場合、前回のバルク・ロード時に、統計は自動的に収集されていません。

- Oracle所有のスキーマ内に存在する表(SYSなど)である。

- ネストした表である。

- 索引構成表(IOT)である。

- 外部表である。

- ON COMMIT DELETE ROWSとして定義されたグローバル一時表である。

- 仮想列を含む表である。

- PUBLISHプリファレンスがFALSEに設定されている表である。

- オプティマイザ統計がロックされています。

- INCREMENTALがtrueに設定されており、拡張構文が使用できないパーティション表です。
たとえば、DBMS_STATS.SET_TABLE_PREFS(null, 'sales', incremental', 'true')を実行するとします。この場合、salesが空であっても、INSERT INTO sales SELECTの統計は収集されません。ただし、INSERT INTO sales PARTITION (sales_q4_2000) SELECT の統計は自動的に収集されます。

- 複数表のINSERT文を使用してロードされます。

関連項目:

「スキーマ統計および表統計の収集」

バルク・ロードのためのオンライン統計収集のヒント

デフォルトでは、バルク・ロード時に統計が収集されます。NO_GATHER_OPTIMIZER_STATISTICSヒントを使用すると、この機能を文レベルで無効にでき、GATHER_OPTIMIZER_STATISTICSヒントを使用すると、この機能を文レベルで有効にできます。

たとえば、次の文はバルク・ロードでのオンライン統計収集を無効にします。

CREATE TABLE employees2 AS
SELECT /*+NO_GATHER_OPTIMIZER_STATISTICS*/ * FROM employees

関連項目:

GATHER_OPTIMIZER_STATISTICSヒントとNO_GATHER_OPTIMIZER_STATISTICSヒントの詳細は、『Oracle Database SQL言語リファレンス』を参照してください

データベースがオプティマイザ統計を収集する場合

データベースでは、様々なソースから様々なタイミングでオプティマイザ統計が収集されます。

この項の内容は次のとおりです。

- オプティマイザ統計のソース

- SQL計画ディレクティブ

- データベースがデータをサンプリングする場合

- データベースがデータをサンプリングする方法

オプティマイザ統計のソース

オプティマイザはオプティマイザ統計に複数の異なるソースを使用します。

ソースは次のとおりです。

- DBMS_STATS実行、自動または手動
このPL/SQLパッケージは、オプティマイザ統計を収集するための主要な手段です。

- SQLのコンパイル
SQLのコンパイル時に、データベースでは、以前にDBMS_STATSを使用して収集した統計を増強することができます。この段階で、SQL文のWHERE句の述語を満たす行が表内にどれぐらいあるのか、より正確な情報を取得するために追加の問合せが実行されます。

- SQLの実行
実行時、データベースでは、以前に収集された統計をさらに増強できます。この段階では、Oracle Databaseは、SQL文の実行中にすべての行ソースによって生成された多数の行を収集します。実行の最後に、オプティマイザは、行数の見積りが、次の文の実行時に再解析の必要性があるほど不正確であるかどうかを判断します。カーソルが再解析とマークされている場合、オプティマイザは、見積りではなく、以前の実行で収集された実際の行カウントを使用します。

- SQLプロファイル
SQLプロファイルは、問合せの補助統計のコレクションです。プロファイルは、データ・ディクショナリにこれらの補足的な統計を格納します。オプティマイザは、最適化時にSQLプロファイルを使用して、最適な計画を特定します。

データベースでは、データ・ディクショナリにオプティマイザ統計が格納され、必要に応じて更新または置換されます。データ・ディクショナリ・ビュー内の統計を問い合せることができます。

関連項目:

- 「データベースがデータをサンプリングする場合」

- 「SQLプロファイルについて」

- DBMS_STATS.GATHER_TABLE_STATSプロシージャの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

SQL計画ディレクティブ

SQL計画ベースラインは、オプティマイザがより最適な計画を生成するために使用できる追加情報および命令です。たとえば、SQL計画ディレクティブは、欠落している拡張を記録するようオプティマイザに指示できます。

SQL計画ディレクティブについて

SQLの実行時に、カーディナリティが誤って見積られた場合、データベースでSQL計画ディレクティブが作成されます。

SQLのコンパイル時に、オプティマイザは、欠落している拡張またはヒストグラムが存在するかどうかを判断するために、ディレクティブに対応する問合せを確認します。オプティマイザは欠落している拡張をすべて記録します。以降のDBMS_STATSコールでは、この拡張に対する統計が収集されます。

ディレクティブに対応する統計が不十分な場合、オプティマイザは動的統計を使用します。たとえば、オプティマイザは列グループの統計が作成されるまで、および統計の作成後も誤った見積りが行われるたびに動的統計を収集します。この場合、オプティマイザは列グループのみを監視します。オプティマイザは、式に対する拡張は作成しません。

SQL計画ディレクティブは、特定のSQL文またはSQL IDに関連していません。ディレクティブは問合せ式で定義されるため、オプティマイザは、ほぼ同一の文に対してディレクティブを使用できます。たとえば、ディレクティブは、選択リスト・アイテムを除いて同じである問合せなど、類似のパターンを使用する問合せの場合、オプティマイザにとって有益です。

SQL計画ディレクティブは、データベースによって自動的に管理されます。ディレクティブはデータベースによって最初に共有プール内に作成されます。データベースは、SYSAUX表領域に定期的にディレクティブを書き込みます。ディレクティブは、DBMS_SPDパッケージで使用可能なAPIによって管理できます。

関連項目:

- 「拡張統計の管理」

- 「列グループの統計について」

オプティマイザがSQL計画ディレクティブを使用する際の仕組み: 例

この例では、SQL文のSQL計画ディレクティブが自動的に作成および使用される際の仕組みを示します。

前提条件

shスキーマへの問合せを実行しようとしています。このスキーマ、データ・ディクショナリおよびV$ビューに対する権限は保有しています。

データベースがSQL計画ディレクティブを使用する際の仕組みを確認する手順は次のとおりです。

1. sh.customers表を問い合せます。

SELECT /*+gather_plan_statistics*/ *
FROM   customers
WHERE  cust_state_province='CA'
AND    country_id='US';

gather_plan_statisticsヒントは、計画内の各操作で戻された実際の行数を示します。これにより、オプティマイザの見積りと実際に戻された行数を比較できます。

2. 前述の問合せの計画を問い合せます。
次の例に、実行計画を示します(出力例も示します)。

SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(FORMAT=>'ALLSTATS LAST'));

PLAN_TABLE_OUTPUT
-------------------------------------
SQL_ID  b74nw722wjvy3, child number 0
-------------------------------------
select /*+gather_plan_statistics*/ * from customers where
CUST_STATE_PROVINCE='CA' and country_id='US'

Plan hash value: 1683234692
--------------------------------------------------------------------------------------------
| Id| Operation         | Name      | Starts |E-Rows| A-Rows |   A-Time   |Buffers | Reads |
--------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT  |           |      1 |      |     29 |00:00:00.01 |     17 |    14 |
|*1 |  TABLE ACCESS FULL| CUSTOMERS |      1 |    8 |     29 |00:00:00.01 |     17 |    14 |
--------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

1 - filter(("CUST_STATE_PROVINCE"='CA' AND "COUNTRY_ID"='US'))

計画内の各操作で戻された実際の行数(A-Rows)は、見積り(E-Rows)と大きく異なっています。この文は、自動再最適化の候補です。

3. customers問合せを再最適化できるかどうかを確認します。
次の文では、V$SQL.IS_REOPTIMIZABLEの値を問い合せます(出力例も示します)。

SELECT SQL_ID, CHILD_NUMBER, SQL_TEXT, IS_REOPTIMIZABLE
FROM   V$SQL
WHERE  SQL_TEXT LIKE 'SELECT /*+gather_plan_statistics*/%';

SQL_ID        CHILD_NUMBER SQL_TEXT    I
------------- ------------ ----------- -
b74nw722wjvy3            0 select /*+g Y
ather_plan_
statistics*
/ * from cu
stomers whe
re CUST_STA
TE_PROVINCE
='CA' and c
ountry_id='
US'

IS_REOPTIMIZABLE列はYとマークされています。そのため、次の実行ではcustomers問合せのハード解析が実行されます。オプティマイザは、この最初の実行から実行統計を使用して計画を決定します。再最適化によって得られた情報はSQL計画ディレクティブとしてデータベースに保持されます。

4. shスキーマのディレクティブを表示します。
次の例では、DBMS_SPDを使用してディスクにSQL計画ディレクティブを書き込んでから、shスキーマのみのディレクティブを表示します。

EXEC DBMS_SPD.FLUSH_SQL_PLAN_DIRECTIVE;

SELECT TO_CHAR(d.DIRECTIVE_ID) dir_id, o.OWNER AS "OWN", o.OBJECT_NAME AS "OBJECT",
o.SUBOBJECT_NAME col_name, o.OBJECT_TYPE, d.TYPE, d.STATE, d.REASON
FROM   DBA_SQL_PLAN_DIRECTIVES d, DBA_SQL_PLAN_DIR_OBJECTS o
WHERE  d.DIRECTIVE_ID=o.DIRECTIVE_ID
AND    o.OWNER IN ('SH')
ORDER BY 1,2,3,4,5;

DIR_ID              OWN OBJECT    COL_NAME    OBJECT TYPE             STATE  REASON
------------------- --- --------- ----------- ------ ---------------- ------ ------------
1484026771529551585 SH  CUSTOMERS COUNTRY_ID  COLUMN DYNAMIC_SAMPLING USABLE SINGLE TABLE
CARDINALITY
MISESTIMATE
1484026771529551585 SH  CUSTOMERS CUST_STATE_ COLUMN DYNAMIC_SAMPLING USABLE SINGLE TABLE
PROVINCE                                   CARDINALITY
MISESTIMATE
1484026771529551585 SH  CUSTOMERS             TABLE  DYNAMIC_SAMPLING USABLE SINGLE TABLE
CARDINALITY
MISESTIMATE

SQL計画ディレクティブは、データベースによってまずメモリーに格納され、その後15分おきにディスクに書き込まれます。そのため、前述の例では、DBMS_SPD.FLUSH_SQL_PLAN_DIRECTIVEをコールして、ディレクティブがSYSAUX表領域に強制的に書き込まれるようにしています。

ビューDBA_SQL_PLAN_DIRECTIVESおよびDBA_SQL_PLAN_DIR_OBJECTSを使用してディレクティブを監視します。3つのエントリ(customers表用に1つ、相関列のそれぞれの列用に1つずつ)がビューに表示されます。customers問合せのIS_REOPTIMIZABLE値がYであるため、この文を再度実行すると、データベースでハード解析が再度実行され、前回の実行統計に基づいて計画が生成されます。

5. customers表を再度問い合せます。
たとえば、次の文を入力します。

SELECT /*+gather_plan_statistics*/ *
FROM   customers
WHERE  cust_state_province='CA'
AND    country_id='US';

6. カーソル内の計画を問い合せます。
次の例に、実行計画を示します(出力例も示します)。

SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(FORMAT=>'ALLSTATS LAST'));

PLAN_TABLE_OUTPUT
-------------------------------------
SQL_ID  b74nw722wjvy3, child number 1
-------------------------------------
select /*+gather_plan_statistics*/ * from customers where
CUST_STATE_PROVINCE='CA' and country_id='US'

Plan hash value: 1683234692
---------------------------------------------------------------------------
|Id | Operation         |Name     |Start|E-Rows|A-Rows|   A-Time  |Buffers|
---------------------------------------------------------------------------
|  0| SELECT STATEMENT  |         |    1|      |    29|00:00:00.01|     17|
|* 1|  TABLE ACCESS FULL|CUSTOMERS|    1|    29|    29|00:00:00.01|     17|
---------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

1 - filter(("CUST_STATE_PROVINCE"='CA' AND "COUNTRY_ID"='US'))

Note
-----
- cardinality feedback used for this statement

Noteセクションは、この文に対して再最適化が使用されたことを示しています。今回は見積られた行数(E-Rows)が正確な値になっています。SQL計画ディレクティブはまだ使用されていません。

7. customers問合せのカーソルを問い合せます。
たとえば、次の問合せを実行します(出力例も示します)。

SELECT SQL_ID, CHILD_NUMBER, SQL_TEXT, IS_REOPTIMIZABLE
FROM   V$SQL
WHERE  SQL_TEXT LIKE 'SELECT /*+gather_plan_statistics*/%';

SQL_ID        CHILD_NUMBER SQL_TEXT    I
------------- ------------ ----------- -
b74nw722wjvy3            0 select /*+g Y
ather_plan_
statistics*
/ * from cu
stomers whe
re CUST_STA
TE_PROVINCE
='CA' and c
ountry_id='
US'

b74nw722wjvy3            1 select /*+g N
ather_plan_
statistics*
/ * from cu
stomers whe
re CUST_STA
TE_PROVINCE
='CA' and c
ountry_id='
US'

customers問合せの新しい計画が存在し、子カーソルも存在します。

8. SQL計画ディレクティブが存在し、他の文でも使用できることを確認します。
たとえば、次の問合せを実行します。この問合せは類似していますが、元のcustomers問合せとは異なります(STATEが CAではなくMAになっています)。

SELECT /*+gather_plan_statistics*/ CUST_EMAIL
FROM   CUSTOMERS
WHERE  CUST_STATE_PROVINCE='MA'
AND    COUNTRY_ID='US';

9. カーソル内の計画を問い合せます。
次の文では、カーソルを問い合せます(出力例も示します)。

SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(FORMAT=>'ALLSTATS LAST'));

PLAN_TABLE_OUTPUT
-------------------------------------
SQL_ID  3tk6hj3nkcs2u, child number 0
-------------------------------------
Select /*+gather_plan_statistics*/ cust_email From   customers Where
cust_state_province='MA' And    country_id='US'

Plan hash value: 1683234692

---------------------------------------------------------------------------
|Id | Operation         | Name      |Starts|E-Rows|A-Rows| A-Time |Buffers|
---------------------------------------------------------------------------
| 0 | SELECT STATEMENT  |           |    1 |      |  2 |00:00:00.01|   16 |
|*1 |  TABLE ACCESS FULL| CUSTOMERS |    1 |    2 |  2 |00:00:00.01|   16 |
---------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

1 - filter(("CUST_STATE_PROVINCE"='MA' AND "COUNTRY_ID"='US'))

Note
-----
- dynamic sampling used for this statement (level=2)
- 1 Sql Plan Directive used for this statement

計画のNoteセクションは、オプティマイザがこの文に対してSQLディレクティブを使用し、動的統計も使用したことを示しています。

関連項目:

- 「自動再最適化」

- 「SQL計画ディレクティブの管理」

- DBA_SQL_PLAN_DIRECTIVES、V$SQLおよび他のデータベース・ビューの詳細は、『Oracle Databaseリファレンス』を参照してください

- DBMS_SPDの詳細は、『Oracle Databaseリファレンス』を参照してください

オプティマイザが拡張およびSQL計画ディレクティブを使用する際の仕組み: 例

この例では、オプティマイザによって、拡張が存在し、統計が適用可能であることが確認されるまでは、SQL計画ディレクティブが使用される際の仕組みを示します。

この時点で、ディレクティブのステータスはSUPERSEDEDに変更されます。以降のコンパイルではディレクティブのかわりに統計が使用されます。

前提条件

この例では、「オプティマイザがSQL計画ディレクティブを使用する際の仕組み: 例」の手順をすでに実行していることを前提としています。

オプティマイザが拡張およびSQL計画ディレクティブを使用する際の仕組みを確認する手順は次のとおりです。

1. sh.customers表の統計を収集します。
たとえば、次のPL/SQLプログラムを実行します。

BEGIN
DBMS_STATS.GATHER_TABLE_STATS('SH','CUSTOMERS');
END;
/

2. customers表に拡張が存在するかどうかを確認します。
たとえば、次の問合せを実行します(出力例も示します)。

SELECT TABLE_NAME, EXTENSION_NAME, EXTENSION
FROM   DBA_STAT_EXTENSIONS
WHERE  OWNER='SH'
AND    TABLE_NAME='CUSTOMERS';

TABLE_NAM EXTENSION_NAME                 EXTENSION
--------- ------------------------------ -----------------------
CUSTOMERS SYS_STU#S#WF25Z#QAHIHE#MOFFMM_ ("CUST_STATE_PROVINCE",
"COUNTRY_ID")

前述の出力は、cust_state_province列およびcountry_id列に列グループの拡張が存在することを示しています。

3. SQL計画ディレクティブの状態を問い合せます。
例10-6では、ディレクティブに関する情報をデータ・ディクショナリに問い合せます。

列グループの統計が存在しますが、データベースで文の再コンパイルがまだ行われていないため、ディレクティブの状態はUSABLEになっています。次のコンパイル時に、オプティマイザは、統計が適用可能であるかどうかを確認します。適用可能な場合は、ディレクティブのステータスがSUPERSEDEDに変更されます。以降のコンパイルではディレクティブのかわりに統計が使用されます。

4. sh.customers表を問い合せます。

SELECT /*+gather_plan_statistics*/ *
FROM   customers
WHERE  cust_state_province='CA'
AND    country_id='US';

5. カーソル内の計画を問い合せます。
例10-7に、実行計画を示します(出力例も示します)。

Noteセクションは、オプティマイザが拡張統計ではなくディレクティブを使用したことを示しています。コンパイル時に、データベースによって拡張統計が検証されました。

6. SQL計画ディレクティブの状態を問い合せます。
例10-8では、ディレクティブに関する情報をデータ・ディクショナリに問い合せます。

SUPERSEDEDに変更されたディレクティブの状態は、対応する列またはグループに拡張またはヒストグラムがあること、またはディレクティブに使用できる別のSQL計画ディレクティブが存在することを示します。

7. 若干異なる形式の文を使用して、sh.customers表を再度問い合せます。
たとえば、次の問合せを実行します。

SELECT /*+gather_plan_statistics*/ /* force reparse */ *
FROM   customers
WHERE  cust_state_province='CA'
AND    country_id='US';

共有SQL領域にカーソルがある場合は、通常、データベースでカーソルが共有されます。強制的に再解析が行われるように、この手順では、コメントを追加してSQLテキストを若干変更しています。

8. カーソル内の計画を問い合せます。
例10-9に、実行計画を示します(出力例も示します)。

Noteが存在しないのは、オプティマイザがSQL計画ディレクティブのかわりに拡張統計を使用したことを示しています。ディレクティブは、53週間使用されない場合、自動的に消去されます。

関連項目:

- 「SQL計画ディレクティブの管理」

- DBA_SQL_PLAN_DIRECTIVES、V$SQLおよび他のデータベース・ビューの詳細は、『Oracle Databaseリファレンス』を参照してください

- DBMS_SPDの詳細は、『Oracle Databaseリファレンス』を参照してください

例10-6 shスキーマのディレクティブの表示

EXEC DBMS_SPD.FLUSH_SQL_PLAN_DIRECTIVE;

SELECT TO_CHAR(d.DIRECTIVE_ID) dir_id, o.OWNER, o.OBJECT_NAME,
o.SUBOBJECT_NAME col_name, o.OBJECT_TYPE, d.TYPE, d.STATE, d.REASON
FROM   DBA_SQL_PLAN_DIRECTIVES d, DBA_SQL_PLAN_DIR_OBJECTS o
WHERE  d.DIRECTIVE_ID=o.DIRECTIVE_ID
AND    o.OWNER IN ('SH')
ORDER BY 1,2,3,4,5;

DIR_ID              OWN OBJECT_NA COL_NAME   OBJECT  TYPE             STATE  REASON
------------------- --- --------- ---------- ------- ---------------- ------ ------------
1484026771529551585  SH CUSTOMERS COUNTRY_ID  COLUMN DYNAMIC_SAMPLING USABLE SINGLE TABLE
CARDINALITY
MISESTIMATE
1484026771529551585  SH CUSTOMERS CUST_STATE_ COLUMN DYNAMIC_SAMPLING USABLE SINGLE TABLE
PROVINCE                                   CARDINALITY
MISESTIMATE
1484026771529551585  SH CUSTOMERS              TABLE DYNAMIC_SAMPLING USABLE SINGLE TABLE
CARDINALITY
MISESTIMATE

例10-7 実行計画

SQL> SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(FORMAT=>'ALLSTATS LAST'));

PLAN_TABLE_OUTPUT
-------------------------------------
SQL_ID  b74nw722wjvy3, child number 0
-------------------------------------
select /*+gather_plan_statistics*/ * from customers where
CUST_STATE_PROVINCE='CA' and country_id='US'

Plan hash value: 1683234692

-----------------------------------------------------------------------------------------
| Id  | Operation         | Name      | Starts | E-Rows | A-Rows |   A-Time   | Buffers |
-----------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |           |      1 |        |     29 |00:00:00.01 |      16 |
|*  1 |  TABLE ACCESS FULL| CUSTOMERS |      1 |     29 |     29 |00:00:00.01 |      16 |
-----------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

1 - filter(("CUST_STATE_PROVINCE"='CA' AND "COUNTRY_ID"='US'))

Note
-----
- dynamic sampling used for this statement (level=2)
- 1 Sql Plan Directive used for this statement

例10-8 shスキーマのディレクティブの表示

EXEC DBMS_SPD.FLUSH_SQL_PLAN_DIRECTIVE;

SELECT TO_CHAR(d.DIRECTIVE_ID) dir_id, o.OWNER, o.OBJECT_NAME,
o.SUBOBJECT_NAME col_name, o.OBJECT_TYPE, d.TYPE, d.STATE, d.REASON
FROM   DBA_SQL_PLAN_DIRECTIVES d, DBA_SQL_PLAN_DIR_OBJECTS o
WHERE  d.DIRECTIVE_ID=o.DIRECTIVE_ID
AND    o.OWNER IN ('SH')
ORDER BY 1,2,3,4,5;

DIR_ID              OWN OBJECT_NA  COL_NAME    OBJECT TYPE     STATE      REASON
------------------- --- ---------  ----------  ------ -------- ---------  ------------
1484026771529551585  SH CUSTOMERS  COUNTRY_ID  COLUMN DYNAMIC_ SUPERSEDED SINGLE TABLE
SAMPLING            CARDINALITY
MISESTIMATE
1484026771529551585  SH CUSTOMERS  CUST_STATE_ COLUMN DYNAMIC_ SUPERSEDED SINGLE TABLE
PROVINCE           SAMPLING            CARDINALITY
MISESTIMATE
1484026771529551585  SH CUSTOMERS               TABLE DYNAMIC_ SUPERSEDED SINGLE TABLE
SAMPLING            CARDINALITY
MISESTIMATE

例10-9 実行計画

SQL> SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(FORMAT=>'ALLSTATS LAST'));

PLAN_TABLE_OUTPUT
-------------------------------------
SQL_ID  b74nw722wjvy3, child number 0
-------------------------------------
select /*+gather_plan_statistics*/ * from customers where
CUST_STATE_PROVINCE='CA' and country_id='US'

Plan hash value: 1683234692

-----------------------------------------------------------------------------------------
| Id  | Operation         | Name      | Starts | E-Rows | A-Rows |   A-Time   | Buffers |
-----------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |           |      1 |        |     29 |00:00:00.01 |      17 |
|*  1 |  TABLE ACCESS FULL| CUSTOMERS |      1 |     29 |     29 |00:00:00.01 |      17 |
-----------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

1 - filter(("CUST_STATE_PROVINCE"='CA' AND "COUNTRY_ID"='US'))

19 rows selected.

データベースがデータをサンプリングする場合

Oracle Database 12cから、オプティマイザは、すべてのSQL文に対して、動的統計が有用であるかどうか、および使用するサンプル・サイズを自動的に決定するようになりました。以前のリリースでは、動的統計は動的サンプリングと呼ばれていました。

動的統計を使用するかどうかを決める主な要因は、最適な計画を生成するために十分な統計が使用可能かどうかということです。統計が十分でない場合、オプティマイザは動的統計を使用します。

自動動的統計は、OPTIMIZER_DYNAMIC_SAMPLING初期化パラメータが0に設定されていない場合に有効になります。デフォルトでは、動的統計レベルは2に設定されます。

一般に、オプティマイザは、動的統計ではなく、デフォルトの統計を使用して、表、索引および列の最適化時に必要な統計を計算します。オプティマイザは、次のような複数の要素に基づいて、動的統計を使用するかどうかを決定します。

- SQL文でパラレル実行が使用される。

- SQL計画ディレクティブが存在する。

次の図は、動的統計の収集プロセスを示しています。

図10-2 動的統計

図10-2に示されているとおり、オプティマイザは、次の場合に動的統計を自動的に収集します。

- 統計が欠落している
問合せ内の表に統計がない場合、オプティマイザは最適化の前にこれらの表の基本的な統計を収集します。アプリケーションで、統計を収集するためのDBMS_STATSへのフォローアップ・コールなしに新しいオブジェクトが作成された、または統計が収集される前にオブジェクトで統計がロックされたという理由で、統計が欠落することがあります。

この場合、統計はDBMS_STATSパッケージを使用して収集された統計ほど高品質ではなく、完全でもありません。これは、文のコンパイル時間に及ぼす影響を限定的にするために妥協されます。

- 統計が十分でない
オプティマイザが、列間の相関、列データ配分の偏り、式の統計などを考慮に入れずに、述語(フィルタまたは結合)の選択性またはGROUP BY句を見積る場合、統計は常に不十分なものになる可能性があります。

拡張統計により、オプティマイザは複雑な条件式に対して的確な品質のカーディナリティ予測を得ることができます。オプティマイザは、動的統計を使用して拡張統計の欠落を補完したり、たとえば非等価述語に対する拡張統計が使用できないときに動的統計を使用したりすることができます。

注意:

データベースは、AS OF句を含む問合せに対して動的統計を使用しません。

関連項目:

- 「動的統計の制御」

- 「列グループの統計について」

- OPTIMIZER_DYNAMIC_SAMPLING初期化パラメータの詳細は、『Oracle Databaseリファレンス』を参照してください。

データベースがデータをサンプリングする方法

最適化の最初に、表が動的統計の候補であるかどうかを判断する際、オプティマイザは、表に永続SQL計画ディレクティブが存在するかどうかをチェックします。各ディレクティブについて、オプティマイザは、表に関連する述語のカーディナリティを判断するときに計算する統計式を登録します。

図10-2では、データベースにより再帰的SQL文が発行されて、表ブロックの小さなランダム・サンプルがスキャンされます。データベースは、関連する単一表述語および結合を適用して、述語のカーディナリティを見積ります。

データベースでは、動的統計の結果が共有可能な統計として保持されます。データベースでは、1つの問合せのSQLコンパイルの間、同じ問合せの再コンパイルと結果を共有できます。データベースでは、同じパターンを持つ問合せの結果を再利用することもできます。

関連項目:

- 動的統計レベルの設定方法については、「動的統計の制御」を参照してください

- OPTIMIZER_DYNAMIC_SAMPLING初期化パラメータの詳細は、『Oracle Databaseリファレンス』を参照してください。

11 ヒストグラム

ヒストグラムは、表の列のデータ分布に関する詳細な情報を提供する特殊なタイプの列統計です。ヒストグラムでは、コインをバケツに分けるように、値をバケットに分類します。

NDVおよびデータの分布に基づいて、作成するヒストグラムのタイプが選択されます。(場合によっては、ヒストグラムを作成する際、データベースで、内部的に事前定義された数の行がサンプリングされます。)ヒストグラムのタイプは次のとおりです。

- 頻度ヒストグラムおよび上位頻度ヒストグラム

- 高さ調整済ヒストグラム(レガシー)

- ハイブリッド・ヒストグラム

この項の内容は次のとおりです。

- ヒストグラムの目的

- ヒストグラムが作成される場合

- Oracle Databaseによるヒストグラム・タイプの選択方法

- ヒストグラム使用時のカーディナリティ・アルゴリズム

- 頻度ヒストグラム

- 上位頻度ヒストグラム

- 高さ調整済ヒストグラム(レガシー)

- ハイブリッド・ヒストグラム

ヒストグラムの目的

デフォルトでは、オプティマイザは、列内の個別値全体で行のデータ配分が均一であると想定します。

列にデータの偏りがある(列内のデータ配分が均一ではない)場合は、ヒストグラムを使用することにより、これらの列を含むフィルタ述語や結合述語に対してオプティマイザが正確なカーディナリティ予測を生成できるようになります。

たとえば、カリフォルニアに拠点を置く書籍店では、書籍の95%をカリフォルニアに、4%をオレゴンに、1%をネバダに出荷しています。書籍注文表には300,000行あります。表の列には、注文の出荷先の州が格納されています。ユーザーが、オレゴンに出荷された書籍の数を問い合せます。ヒストグラムを使用しない場合、オプティマイザは300000/3 (NDVは3)で均一に分布されていると想定し、カーディナリティを100,000行で見積ります。この見積りの場合、オプティマイザは全表スキャンを選択します。ヒストグラムがある場合、オプティマイザは、書籍の4%がオレゴンに出荷されていると計算し、索引スキャンを選択します。

ヒストグラムが作成される場合

DBMS_STATSによって表の統計が収集され、問合せによってこの表の列が参照される場合、これまでの問合せのワークロードに従って、必要に応じて自動的にヒストグラムが作成されます。

基本的なプロセスは次のとおりです。

1. METHOD_OPTパラメータにデフォルトのSIZE AUTOが設定された状態で、表にDBMS_STATSを実行します。

2. ユーザーが、この表に問合せを行います。

3. データベースにより前の問合せの述語が記録され、データ・ディクショナリ表SYS.COL_USAGE$が更新されます。

4. DBMS_STATSを再度実行すると、DBMS_STATSによりSYS.COL_USAGE$に問い合され、前回の問合せのワークロードに基づいて、どの列にヒストグラムが必要かが決定されます。

AUTO機能の結果には次のものが含まれます。

- 問合せが時間の経過とともに変更される場合、DBMS_STATSによって収集される統計の種類が変更される場合があります。たとえば、表のデータに変更がない場合でも、問合せとDBMS_STATSの操作によって、これらの表を参照する問合せの計画が変更される場合があります。

- 表の統計を収集するが問合せは行わない場合、この表の列のヒストグラムは作成されません。データベースに自動でヒストグラムを作成させるには、1つ以上の問合せを実行してSYS.COL_USAGE$の列使用情報に移入する必要があります。

例11-1 ヒストグラムの自動作成

sh.sh_extは、sh.sales表と同じ列を含む外部表だとします。新しい表sales2を作成して、sh_extをソースとして使用してバルク・ロードを実行すると、自動的にsales2の統計が作成されます(「バルク・ロードのためのオンライン統計収集」を参照)。また、次のように索引を作成します。

SQL> CREATE TABLE sales2 AS SELECT * FROM sh_ext;
SQL> CREATE INDEX sh_12c_idx1 ON sales2(prod_id);
SQL> CREATE INDEX sh_12c_idx2 ON sales2(cust_id,time_id);

データ・ディクショナリに問い合せて、sales2列のヒストグラムが存在するかどうか確認します。sales2にはまだ問い合されていないため、ヒストグラムはまだ作成されていません。

SQL> SELECT COLUMN_NAME, NOTES, HISTOGRAM
2  FROM   USER_TAB_COL_STATISTICS
3  WHERE  TABLE_NAME = 'SALES2';

COLUMN_NAME   NOTES          HISTOGRAM
------------- -------------- ---------
AMOUNT_SOLD   STATS_ON_LOAD  NONE
QUANTITY_SOLD STATS_ON_LOAD  NONE
PROMO_ID      STATS_ON_LOAD  NONE
CHANNEL_ID    STATS_ON_LOAD  NONE
TIME_ID       STATS_ON_LOAD  NONE
CUST_ID       STATS_ON_LOAD  NONE
PROD_ID       STATS_ON_LOAD  NONE

sales2に製品42の行数を問い合せた後、GATHER AUTOオプションを使用して表統計を収集します。

SQL> SELECT COUNT(*) FROM sales2 WHERE prod_id = 42;

COUNT(*)
----------
12116

SQL> EXEC DBMS_STATS.GATHER_TABLE_STATS(USER,'SALES2',OPTIONS=>'GATHER AUTO');

データ・ディクショナリに問い合せると、前回の問合せで収集された情報に基づいてprod_id列のヒストグラムが作成されたことがわかります。

SQL> SELECT COLUMN_NAME, NOTES, HISTOGRAM
2  FROM   USER_TAB_COL_STATISTICS
3  WHERE  TABLE_NAME = 'SALES2';

COLUMN_NAME   NOTES          HISTOGRAM
------------- -------------- ---------
AMOUNT_SOLD   STATS_ON_LOAD  NONE
QUANTITY_SOLD STATS_ON_LOAD  NONE
PROMO_ID      STATS_ON_LOAD  NONE
CHANNEL_ID    STATS_ON_LOAD  NONE
TIME_ID       STATS_ON_LOAD  NONE
CUST_ID       STATS_ON_LOAD  NONE
PROD_ID       HISTOGRAM_ONLY FREQUENCY

Oracle Databaseによるヒストグラム・タイプの選択方法

Oracle Databaseでは、複数の基準を使用して、作成するヒストグラム(頻度、上位頻度、高さ調整済またはハイブリッド)を決定します。

ヒストグラム式では、次の変数が使用されます。

- NDV
これは、列内の個別値の数を表します。たとえば、列に値100、200および300のみが含まれている場合、この列のNDVは3です。

- n
この変数は、ヒストグラム・バケットの数を表します。デフォルトは254です。

- p
この変数は、内部割合のしきい値を表し、(1–(1/n)) * 100と等しくなります。たとえば、n = 254の場合、pは99.6です。

追加の基準は、DBMS_STATS統計収集プロシージャでestimate_percentパラメータがAUTO_SAMPLE_SIZE (デフォルト)に設定されているかどうかです。

次の図は、ヒストグラム作成のディシジョン・ツリーを示しています。

図11-1 ヒストグラム作成のディシジョン・ツリー

ヒストグラム使用時のカーディナリティ・アルゴリズム

ヒストグラムを使用する場合、カーディナリティのアルゴリズムは、エンドポイント番号やエンドポイント値、列値がポピュラーか非ポピュラーかなどの要因により異なります。

この項の内容は次のとおりです。

- エンドポイント番号とエンドポイント値

- ポピュラー値と非ポピュラー値

- バケットの圧縮

エンドポイント番号とエンドポイント値

エンドポイント番号は、バケットを一意に識別する数値です。頻度ヒストグラムおよびハイブリッド・ヒストグラムでは、エンドポイント番号は、現在および前のバケットに含まれるすべての値の頻度の累積になります。たとえば、バケットのエンドポイント番号が100の場合、現在およびすべての前のバケットの合計頻度は100です。高さ調整済ヒストグラムでは、オプティマイザはバケットの数を0または1から順に数えます。いずれの場合でも、エンドポイント番号はバケット番号になります。

エンドポイント値は、バケット内の値の範囲で最も高い値です。たとえば、バケットに含まれる値が52794と52795のみの場合、エンドポイント値は52795です。

ポピュラー値と非ポピュラー値

ヒストグラムの値のポピュラリティは、次のようにカーディナリティ予測アルゴリズムに影響します。

- ポピュラー値
ポピュラー値は複数のバケットのエンドポイント値として出現します。オプティマイザは、値がポピュラー値かどうかを判断するために、まずその値がバケットのエンドポイント値かどうかを確認します。エンドポイント値の場合、頻度ヒストグラムでは、オプティマイザは現在のバケットのエンドポイント番号から前のバケットのエンドポイント番号を減算します。ハイブリッド・ヒストグラムでは、エンドポイントごとにすでにこの情報が個別に格納されています。この値が1よりも大きい場合、その値はポピュラーです。

オプティマイザは、次の式を使用してポピュラー値のカーディナリティ予測を計算します。

cardinality of popular value =
(num of rows in table) *
(num of endpoints spanned by this value / total num of endpoints)

- 非ポピュラー値
ポピュラーでない値は、非ポピュラー値です。オプティマイザは、次の式を使用して非ポピュラー値のカーディナリティ予測を計算します。

cardinality of nonpopular value =
(num of rows in table) * density

オプティマイザは、バケット数やNDVなどの要因に基づいて内部アルゴリズムを使用し、密度を計算します。密度は、0から1の間の小数値として表されます。値が1に近いと、述語リストでこの列を参照する問合せによって多くの行が戻されることをオプティマイザが予測していることを示します。値が0に近いと、少ない行が戻されることをオプティマイザが予測していることを示します。

関連項目:

DBA_TAB_COL_STATISTICS.DENSITY列の詳細は、『Oracle Databaseリファレンス』を参照してください。

バケットの圧縮

場合によっては、バケットの合計数を減らすために、オプティマイザが複数のバケットを1つのバケットに圧縮することがあります。たとえば、次の頻度ヒストグラムは、最初のバケット番号が1で、最後のバケット番号が23であることを示しています。

ENDPOINT_NUMBER ENDPOINT_VALUE
--------------- --------------
1          52792
6          52793
8          52794
9          52795
10          52796
12          52797
14          52798
23          52799

いくつかのバケットが欠落しています。当初は2から6の各バケットに、値52793の単一のインスタンスが含まれていました。オプティマイザは、これらのバケットのすべてを最も高いエンドポイント番号(バケット6)のバケットに圧縮しました。これにより、現在このバケットには値52793のインスタンスが5個含まれています。現在のバケット(6)と前のバケット(1)とのエンドポイント番号の差が5であるため、この値はポピュラーです。このように、値52793は、圧縮前は5個のバケットを使用するエンドポイントでした。

次の注釈は、圧縮されたバケットとポピュラー値を示しています。

ENDPOINT_NUMBER ENDPOINT_VALUE
--------------- --------------
1          52792 -> nonpopular
6          52793 -> buckets 2-6 compressed into 6; popular
8          52794 -> buckets 7-8 compressed into 8; popular
9          52795 -> nonpopular
10          52796 -> nonpopular
12          52797 -> buckets 11-12 compressed into 12; popular
14          52798 -> buckets 13-14 compressed into 14; popular
23          52799 -> buckets 15-23 compressed into 23; popular

頻度ヒストグラム

頻度ヒストグラムでは、列の各個別値がヒストグラムの1つのバケットに対応しています。各値には専用のバケットがあるため、多くの値を持つバケットもあり、ほとんど値がないバケットもあります。

頻度ヒストグラムをコインの分類に例えて考えるならば、個々のコインが最初は固有のバケットに入るようにすることです。たとえば、最初のペニーをバケット1に、2番目のペニーはバケット2に、最初のニッケルはバケット3に入れるなどのようにします。続いて、すべてのペニーを1つのペニーのバケットにまとめ、すべてのニッケルを1つのニッケルのバケットにまとめます。残りのコインについても同様に行います。

この項の内容は次のとおりです。

- 頻度ヒストグラムの基準

- 頻度ヒストグラムの生成

頻度ヒストグラムの基準

頻度ヒストグラムは、要求されたヒストグラム・バケットの数に依存します。

「Oracle Databaseによるヒストグラム・タイプの選択方法」の論理図に示すように、次の基準を満たす場合に、データベースは頻度ヒストグラムを作成します。

- NDVがn以下である(nはヒストグラム・バケットの数(デフォルトは254)です)。
たとえば、sh.countries.country_subregion_id列には、52792から52799までの範囲で順番に8個の個別値があります。nがデフォルトの254である場合、8 <= 254であるため、オプティマイザは頻度ヒストグラムを作成します。

- DBMS_STATS統計収集プロシージャのestimate_percentパラメータが、ユーザー指定の値またはAUTO_SAMPLE_SIZEに設定されている。

Oracle Database 12cからは、サンプリング・サイズがデフォルトのAUTO_SAMPLE_SIZEである場合、全表スキャンによって頻度ヒストグラムが作成されます。他のすべてのサンプリング率の指定では、データベースは、サンプルから頻度ヒストグラムを導出します。Oracle Database 12cより前のリリースでは、データベースは、小規模なサンプルに基づいてヒストグラムを収集していました。これは、頻度の低い値は多くの場合、サンプルに出現しないことを意味します。このような場合、密度を使用すると、オプティマイザが選択性を過大に見積ることがありました。

関連項目:

AUTO_SAMPLE_SIZEの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

頻度ヒストグラムの生成

このシナリオでは、サンプル・スキーマを使用して、頻度ヒストグラムを生成する方法を説明します。

前提条件

このシナリオでは、sh.countries.country_subregion_id列に頻度ヒストグラムを生成することを想定しています。この表には23行が含まれています。

次の問合せは、country_subregion_id列には分布が均一ではない8個の個別値が含まれていることを示しています(出力例も示します)。

SELECT country_subregion_id, count(*)
FROM   sh.countries
GROUP BY country_subregion_id
ORDER BY 1;

COUNTRY_SUBREGION_ID   COUNT(*)
-------------------- ----------
52792          1
52793          5
52794          2
52795          1
52796          1
52797          2
52798          2
52799          9

頻度ヒストグラムを生成する手順は次のとおりです。

1. バケット数はデフォルトの254のままで、sh.countriesおよびcountry_subregion_id列の統計を収集します。
たとえば、次のPL/SQL無名ブロックを実行します。

BEGIN
DBMS_STATS.GATHER_TABLE_STATS (
ownname    => 'SH'
,   tabname    => 'COUNTRIES'
,   method_opt => 'FOR COLUMNS COUNTRY_SUBREGION_ID'
);
END;

2. country_subregion_id列のヒストグラム情報を問い合せます。
たとえば、次の問合せを使用します(出力例も示します)。

SELECT TABLE_NAME, COLUMN_NAME, NUM_DISTINCT, HISTOGRAM
FROM   USER_TAB_COL_STATISTICS
WHERE  TABLE_NAME='COUNTRIES'
AND    COLUMN_NAME='COUNTRY_SUBREGION_ID';

TABLE_NAME COLUMN_NAME          NUM_DISTINCT HISTOGRAM
---------- -------------------- ------------ ---------------
COUNTRIES  COUNTRY_SUBREGION_ID            8 FREQUENCY

列の個別値がn以下(nはデフォルトの254)であるため、オプティマイザは頻度ヒストグラムを選択します。

3. country_subregion_id列のエンドポイント番号とエンドポイント値を問い合せます。
たとえば、次の問合せを使用します(出力例も示します)。

SELECT ENDPOINT_NUMBER, ENDPOINT_VALUE
FROM   USER_HISTOGRAMS
WHERE  TABLE_NAME='COUNTRIES'
AND    COLUMN_NAME='COUNTRY_SUBREGION_ID';

ENDPOINT_NUMBER ENDPOINT_VALUE
--------------- --------------
1          52792
6          52793
8          52794
9          52795
10          52796
12          52797
14          52798
23          52799

図11-2に、ヒストグラムの8個のバケットを図示します。それぞれの値は、バケットに入るコインとして表されています。

図11-2 頻度ヒストグラム

図11-2に示したように、それぞれの個別値には固有のバケットがあります。これは頻度ヒストグラムであるため、エンドポイント番号はエンドポイントの頻度の累積です。52793の場合、エンドポイント番号6は、この値が5回(6 - 1)出現することを示しています。52794の場合、エンドポイント番号8は、この値が2回(8 - 6)出現することを示しています。

エンドポイントが2以上で、前のエンドポイントよりも大きいバケットにはすべて、ポピュラー値が含まれます。したがって、バケット6、8、12、14および23にはポピュラー値が含まれます。オプティマイザは、エンドポイント番号に基づいてそれらのカーディナリティを計算します。たとえば、オプティマイザは次の式を使用して、値52799のカーディナリティ(C)を計算します。この場合、表内の行数は23です。

C = 23 * ( 9 / 23 )

バケット1、9および10には非ポピュラー値が含まれます。オプティマイザは、それらのカーディナリティを密度に基づいて見積ります。

関連項目:

- DBMS_STATS.GATHER_TABLE_STATSプロシージャの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

- USER_TAB_COL_STATISTICSビューの詳細は、『Oracle Databaseリファレンス』を参照してください。

- USER_HISTOGRAMSビューの詳細は、『Oracle Databaseリファレンス』を参照してください。

上位頻度ヒストグラム

上位頻度ヒストグラムは頻度ヒストグラムのバリエーションで、統計上重要ではない非ポピュラー値を無視する頻度ヒストグラムです。たとえば、1000枚のコインの山にペニーが1枚しか含まれていない場合、コインをバケットに分類する際に、このペニーは無視できます。上位頻度ヒストグラムでは、高ポピュラー値に対してより適切なヒストグラムを生成できます。

この項の内容は次のとおりです。

- 上位頻度ヒストグラムの基準

- 上位頻度ヒストグラムの生成

上位頻度ヒストグラムの基準

低い数値が行のほとんどを占める場合、この低い値のセットに頻度ヒストグラムを作成すると効果的です。これは、NDVが要求されたヒストグラム・バケットの数よりも大きい場合でも同様です。頻繁に出現する値に関するより高品質なヒストグラムを作成するために、オプティマイザは、非ポピュラー値を無視し、上位頻度ヒストグラムを作成します。

「Oracle Databaseによるヒストグラム・タイプの選択方法」の論理図に示すように、次の基準を満たす場合に、データベースは上位頻度ヒストグラムを作成します。

- NDVがnより大きい(nはヒストグラム・バケットの数(デフォルトは254)です)。

- 上位nの頻出値によって占められている行の割合がしきい値p以上である。ここで、pは(1-(1/n))*100です。

- DBMS_STATS統計収集プロシージャのestimate_percentパラメータがAUTO_SAMPLE_SIZEに設定されている。

関連項目:

AUTO_SAMPLE_SIZEの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

上位頻度ヒストグラムの生成

このシナリオでは、サンプル・スキーマを使用して、上位頻度ヒストグラムを生成する方法を説明します。

前提条件

このシナリオでは、sh.countries.country_subregion_id列に上位頻度ヒストグラムを生成することを想定しています。この表には23行が含まれています。

次の問合せは、country_subregion_id列には分布が均一ではない8個の個別値が含まれていることを示しています(出力例も示します)。

SELECT country_subregion_id, count(*)
FROM   sh.countries
GROUP BY country_subregion_id
ORDER BY 1;

COUNTRY_SUBREGION_ID   COUNT(*)
-------------------- ----------
52792          1
52793          5
52794          2
52795          1
52796          1
52797          2
52798          2
52799          9

上位頻度ヒストグラムを生成する手順は次のとおりです。

1. 個別値よりも少ないバケット数を指定して、sh.countriesおよびcountry_subregion_id列の統計を収集します。
たとえば、次のコマンドを入力して7個のバケットを指定します。

BEGIN
DBMS_STATS.GATHER_TABLE_STATS (
ownname    => 'SH'
,   tabname    => 'COUNTRIES'
,   method_opt => 'FOR COLUMNS COUNTRY_SUBREGION_ID SIZE 7'
);
END;

2. country_subregion_id列のヒストグラム情報を問い合せます。
たとえば、次の問合せを使用します(出力例も示します)。

SELECT TABLE_NAME, COLUMN_NAME, NUM_DISTINCT, HISTOGRAM
FROM   USER_TAB_COL_STATISTICS
WHERE  TABLE_NAME='COUNTRIES'
AND    COLUMN_NAME='COUNTRY_SUBREGION_ID';

TABLE_NAME COLUMN_NAME          NUM_DISTINCT HISTOGRAM
---------- -------------------- ------------ ---------------
COUNTRIES  COUNTRY_SUBREGION_ID            7 TOP-FREQUENCY

sh.countries.country_subregion_id列には8個の個別値が含まれますが、ヒストグラムには7個のバケットのみが含まれ、n=7となります。この場合は、上位頻度ヒストグラムまたはハイブリッド・ヒストグラムのみが作成されます。country_subregion_id列では、上位7個の最頻出値が行数の95.6%を占めています。これは、しきい値である85.7%を上回っているため、上位頻度ヒストグラムが生成されます(「頻度ヒストグラムの基準」を参照)。

3. この列のエンドポイント番号とエンドポイント値を問い合せます。
たとえば、次の問合せを使用します(出力例も示します)。

SELECT ENDPOINT_NUMBER, ENDPOINT_VALUE
FROM   USER_HISTOGRAMS
WHERE  TABLE_NAME='COUNTRIES'
AND    COLUMN_NAME='COUNTRY_SUBREGION_ID';

ENDPOINT_NUMBER ENDPOINT_VALUE
--------------- --------------
1          52792
6          52793
8          52794
9          52796
11          52797
13          52798
22          52799

図11-3に、上位頻度ヒストグラムの7個のバケットを図示します。この図では、値はコインとして表されています。

図11-3 上位頻度ヒストグラム

図11-3で示したように、それぞれの個別値には固有のバケットがあります。ただし52795は例外です。この値は非ポピュラー値であり、統計上重要ではないため、ヒストグラムから除外されます。通常の頻度ヒストグラムの場合と同様に、エンドポイント番号は値の頻度の累積になります。

関連項目:

- DBMS_STATS.GATHER_TABLE_STATSプロシージャの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

- USER_TAB_COL_STATISTICSビューの詳細は、『Oracle Databaseリファレンス』を参照してください。

- USER_HISTOGRAMSビューの詳細は、『Oracle Databaseリファレンス』を参照してください。

高さ調整済ヒストグラム(レガシー)

レガシーの高さ調整済ヒストグラムでは、列値がバケットに分割され、各バケットにほぼ同数の行が存在します。

たとえば、99枚のコインを4つのバケットに分配する場合、それぞれのバケットに入るコインの枚数はおよそ25枚です。ヒストグラムは、値範囲でのエンドポイントの位置を示します。

この項の内容は次のとおりです。

- 高さ調整済ヒストグラムの基準

- 高さ調整済ヒストグラムの生成

高さ調整済ヒストグラムの基準

Oracle Database 12cより前は、NDVがnを超えた場合に、高さ調整済ヒストグラムが作成されていました。このタイプのヒストグラムは、範囲述語、および少なくとも2つのバケットでエンドポイントとして出現する値の等価述語に対して有用でした。

「Oracle Databaseによるヒストグラム・タイプの選択方法」の論理図に示すように、次の基準を満たす場合に、データベースは高さ調整済ヒストグラムを作成します。

- NDVがnより大きい(nはヒストグラム・バケットの数(デフォルトは254)です)。

- DBMS_STATS統計収集プロシージャのestimate_percentパラメータがAUTO_SAMPLE_SIZEに設定されていない。

このため、Oracle Database 12cによって新しいヒストグラムが作成される場合、サンプリング率がAUTO_SAMPLE_SIZEに設定されていると、作成されるヒストグラムは、高さ調整済ヒストグラムではなく、上位頻度ヒストグラムかハイブリッド・ヒストグラムのいずれかになります。

Oracle Database 11gをOracle Database 12cにアップグレードした場合、アップグレード前に作成された高さ調整済ヒストグラムは引き続き使用されます。ただし、ヒストグラムが作成された表の統計をリフレッシュすると、この表の既存の高さ調整済ヒストグラムはデータベースによって置き換えられます。置き換わるヒストグラムのタイプは、NDVと次の基準の両方によって異なります。

- サンプリング率がAUTO_SAMPLE_SIZEである場合は、ハイブリッド・ヒストグラムまたは頻度ヒストグラムが作成されます。

- サンプリング率がAUTO_SAMPLE_SIZEでない場合は、高さ調整済ヒストグラムまたは頻度ヒストグラムが作成されます。

高さ調整済ヒストグラムの生成

このシナリオでは、サンプル・スキーマを使用して、高さ調整済ヒストグラムを生成する方法を説明します。

前提条件

このシナリオでは、sh.countries.country_subregion_id列に高さ調整済ヒストグラムを生成することを想定しています。この表には23行が含まれています。

次の問合せは、country_subregion_id列には分布が均一ではない8個の個別値が含まれていることを示しています(出力例も示します)。

SELECT country_subregion_id, count(*)
FROM   sh.countries
GROUP BY country_subregion_id
ORDER BY 1;

COUNTRY_SUBREGION_ID   COUNT(*)
-------------------- ----------
52792          1
52793          5
52794          2
52795          1
52796          1
52797          2
52798          2
52799          9

高さ調整済ヒストグラムを生成する手順は次のとおりです。

1. 個別値よりも少ないバケット数を指定して、sh.countriesおよびcountry_subregion_id列の統計を収集します。

注意:

高さ調整済ヒストグラムの作成に必要なOracle Database 11gの動作をシミュレートするには、estimate_percentをデフォルト以外の値に設定します。デフォルト以外の値を指定すると、頻度ヒストグラムまたは高さ調整済ヒストグラムが作成されます。

たとえば、次のコマンドを入力します。

BEGIN  DBMS_STATS.GATHER_TABLE_STATS (
ownname          => 'SH'
,   tabname          => 'COUNTRIES'
,   method_opt       => 'FOR COLUMNS COUNTRY_SUBREGION_ID SIZE 7'
,   estimate_percent => 100
);
END;

2. country_subregion_id列のヒストグラム情報を問い合せます。
たとえば、次の問合せを使用します(出力例も示します)。

SELECT TABLE_NAME, COLUMN_NAME, NUM_DISTINCT, HISTOGRAM
FROM   USER_TAB_COL_STATISTICS
WHERE  TABLE_NAME='COUNTRIES'
AND    COLUMN_NAME='COUNTRY_SUBREGION_ID';

TABLE_NAME COLUMN_NAME          NUM_DISTINCT HISTOGRAM
---------- -------------------- ------------ ---------------
COUNTRIES  COUNTRY_SUBREGION_ID            8 HEIGHT BALANCED

個別値の数(8)がバケット数(7)よりも大きく、estimate_percent値がデフォルト以外であるため、オプティマイザは高さ調整済ヒストグラムを選択します。

3. 各個別値が占める行数を問い合せます。
たとえば、次の問合せを使用します(出力例も示します)。

SELECT COUNT(country_subregion_id) AS NUM_OF_ROWS, country_subregion_id
FROM   countries
GROUP BY country_subregion_id
ORDER BY 2;

NUM_OF_ROWS COUNTRY_SUBREGION_ID
----------- --------------------
1                52792
5                52793
2                52794
1                52795
1                52796
2                52797
2                52798
9                52799

4. country_subregion_id列のエンドポイント番号とエンドポイント値を問い合せます。
たとえば、次の問合せを使用します(出力例も示します)。

SELECT ENDPOINT_NUMBER, ENDPOINT_VALUE
FROM   USER_HISTOGRAMS
WHERE  TABLE_NAME='COUNTRIES'
AND    COLUMN_NAME='COUNTRY_SUBREGION_ID';

ENDPOINT_NUMBER ENDPOINT_VALUE
--------------- --------------
0          52792
2          52793
3          52795
4          52798
7          52799

図11-4に、高さ調整済ヒストグラムを図示します。この図では、値はコインとして表されています。

図11-4 高さ調整済ヒストグラム

バケット番号とエンドポイント番号は同じです。オプティマイザはそれぞれのバケットの最後の行の値をエンドポイント値として記録し、最小値が最初のバケットのエンドポイント値であり、最大値が最後のバケットの最大値であることを確認します。この例では、オプティマイザは、最小値52792がバケットのエンドポイントとなるようにバケット0を追加しています。

オプティマイザは、指定された7個のヒストグラム・バケットに23行を均一に配分する必要があります。そのため、それぞれのバケットに入る行数はおよそ3行です。ただし、オプティマイザは同じエンドポイントでバケットを圧縮します。そのため、バケット1には値52793のインスタンスが2つ、バケット2には値52793のインスタンスが3つ含まれます。さらに、オプティマイザは値52793の5つのインスタンスすべてをバケット2に入れます。同様に、オプティマイザは、バケット5、6および7に、各バケットのエンドポイントとして52799を設定してそれぞれ3つの値を入れるかわりに、値52799の9個のインスタンスすべてをバケット7に入れます。

この例では、現在のエンドポイント番号と前のエンドポイント番号との差が1であるため、バケット3および4には非ポピュラー値が含まれます。オプティマイザは、これらの値のカーディナリティを密度に基づいて計算します。残りのバケットにはポピュラー値が含まれます。オプティマイザは、これらの値のカーディナリティをエンドポイント番号に基づいて計算します。

関連項目:

- DBMS_STATS.GATHER_TABLE_STATSプロシージャの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

- USER_TAB_COL_STATISTICSビューの詳細は、『Oracle Databaseリファレンス』を参照してください。

- USER_HISTOGRAMSビューの詳細は、『Oracle Databaseリファレンス』を参照してください。

ハイブリッド・ヒストグラム

ハイブリッド・ヒストグラムは、高さ調整済ヒストグラムと頻度ヒストグラムの両方の特性を組み合せたものです。「両者の長所を活かす」アプローチにより、オプティマイザは、一部の状況で、より適切な選択性の見積りを得ることができます。

高さ調整済ヒストグラムでは、ほぼポピュラーな値について正確ではない見積りが作成される場合があります。たとえば、1つのバケットのみのエンドポイント値として出現するが、2つのバケットをほぼ占めている値は、ポピュラー値とはみなされません。

この問題を解決するため、ハイブリッド・ヒストグラムでは、複数のバケットを占める値がないように値が配分され、エンドポイント繰返しカウント値が格納されます。これは、ヒストグラム内の各エンドポイント(バケット)について、エンドポイント値が繰り返された回数です。繰返しカウントを使用することで、オプティマイザは、ほぼポピュラーな値についての正確な見積りを得ることができます。

この項の内容は次のとおりです。

- エンドポイント繰返しカウントの仕組み

- ハイブリッド・ヒストグラムの基準

- ハイブリッド・ヒストグラムの生成

エンドポイント繰返しカウントの仕組み

バケツに分けられたコインの例えにより、エンドポイント繰返しカウントの仕組みを示します。

次の図は、値が低いものから高いものへ分類されたcoins列を示しています。

図11-5 コイン

DBMS_STATS.GATHER_TABLE_STATSのmethod_opt引数をFOR ALL COLUMNS SIZE 3に設定して、この表の統計を収集します。この場合、オプティマイザはまず、次の図に示すようにcoins列内の値を3つのバケットにグループ化します。

図11-6 値の最初の配分

バケット境界により、値の一部のオカレンスがあるバケットに入り、別のオカレンスが別のバケットに入るように、値が分けられた場合、オプティマイザは、値のすべてのオカレンスが含まれるように、バケット境界(および他のすべての続くバケット境界)を移動します。たとえば、オプティマイザは、値5を、すべてが最初のバケットに入るように移動し、値25を、すべてが2番目のバケットに入るように移動します。

図11-7 値の再配分

エンドポイント繰返しカウントは、対応するバケットのエンドポイント(右のバケット境界にある値)が繰り返される回数を測定します。たとえば、最初のバケットで、値5は3回繰り返されています。したがって、エンドポイント繰返しカウントは3です。

図11-8 エンドポイント繰返しカウント

高さ調整済ヒストグラムでは、ハイブリッド・ヒストグラムほどの情報量は格納されません。繰返しカウントを使用することで、オプティマイザは、エンドポイント値のオカレンスがいくつ存在するかを正確に特定できます。たとえば、オプティマイザは、値5は3回、値25は4回、値100は2回出現していると認識できます。頻度情報は、オプティマイザがより適切なカーディナリティの見積りを生成するのに役立ちます。

ハイブリッド・ヒストグラムの基準

ハイブリッド・ヒストグラムと上位頻度ヒストグラムを区別するための唯一の基準は、上位n個の頻度の値が内部しきい値pより小さいことです。

「Oracle Databaseによるヒストグラム・タイプの選択方法」の論理図に示すように、次の基準を満たす場合に、データベースはハイブリッド・ヒストグラムを作成します。

- NDVがnより大きい(nはヒストグラム・バケットの数(デフォルトは254)です)。

- 上位頻度ヒストグラムの基準が適用されない。
これは、上位nの頻出値によって占められている行の割合がしきい値pより小さいことを示す別の方法です。ここで、pは(1-(1/n))*100です。「上位頻度ヒストグラムの基準」を参照してください。

- DBMS_STATS統計収集プロシージャのestimate_percentパラメータがAUTO_SAMPLE_SIZEに設定されている。
ユーザーが独自の率を指定した場合、データベースでは、頻度ヒストグラムまたは高さ調整済ヒストグラムが作成されます。

関連項目:

「高さ調整済ヒストグラム(レガシー)」

ハイブリッド・ヒストグラムの生成

このシナリオでは、サンプル・スキーマを使用して、ハイブリッド・ヒストグラムを生成する方法を説明します。

前提条件

このシナリオでは、sh.products.prod_subcategory_id列にハイブリッド・ヒストグラムを生成することを想定しています。この表には72行が含まれています。prod_subcategory_id列には、22個の個別値があります。

ハイブリッド・ヒストグラムを生成する手順は次のとおりです。

1. 10個のバケットを指定して、sh.productsおよびprod_subcategory_id列の統計を収集します。
たとえば、次のコマンドを入力します。

BEGIN  DBMS_STATS.GATHER_TABLE_STATS (
ownname     => 'SH'
,   tabname     => 'PRODUCTS'
,   method_opt  => 'FOR COLUMNS PROD_SUBCATEGORY_ID SIZE 10'
);
END;

2. 各個別値が占める行数を問い合せます。
たとえば、次の問合せを使用します(出力例も示します)。

SELECT COUNT(prod_subcategory_id) AS NUM_OF_ROWS, prod_subcategory_id
FROM   products
GROUP BY prod_subcategory_id
ORDER BY 1 DESC;

NUM_OF_ROWS PROD_SUBCATEGORY_ID
----------- -------------------
8                2014
7                2055
6                2032
6                2054
5                2056
5                2031
5                2042
5                2051
4                2036
3                2043
2                2033
2                2034
2                2013
2                2012
2                2053
2                2035
1                2022
1                2041
1                2044
1                2011
1                2021
1                2052

22 rows selected.

この列には22個の個別値があります。バケットの数(10)が22よりも小さいので、オプティマイザは頻度ヒストグラムを作成できません。オプティマイザはハイブリッド・ヒストグラムと上位頻度ヒストグラムの両方を検討します。上位頻度ヒストグラムに該当するには、上位10の頻出値によって占められている行の割合がしきい値p以上である必要があります。この場合、pは(1-(1/10))*100、つまり90%です。しかし、この場合、上位10の頻出値が占めているのは72行のうち54行、つまり全体の75%にしかなりません。したがって、上位頻度ヒストグラムの基準には該当しないため、オプティマイザはハイブリッド・ヒストグラムを選択します。

3. country_subregion_id列のヒストグラム情報を問い合せます。
たとえば、次の問合せを使用します(出力例も示します)。

SELECT TABLE_NAME, COLUMN_NAME, NUM_DISTINCT, HISTOGRAM
FROM   USER_TAB_COL_STATISTICS
WHERE  TABLE_NAME='PRODUCTS'
AND    COLUMN_NAME='PROD_SUBCATEGORY_ID';

TABLE_NAME COLUMN_NAME         NUM_DISTINCT HISTOGRAM
---------- ------------------- ------------ ---------
PRODUCTS   PROD_SUBCATEGORY_ID 22           HYBRID

4. country_subregion_id列のエンドポイント番号、エンドポイント値およびエンドポイント繰返しカウントを問い合せます。
たとえば、次の問合せを使用します(出力例も示します)。

SELECT ENDPOINT_NUMBER, ENDPOINT_VALUE, ENDPOINT_REPEAT_COUNT
FROM   USER_HISTOGRAMS
WHERE  TABLE_NAME='PRODUCTS'
AND    COLUMN_NAME='PROD_SUBCATEGORY_ID'
ORDER BY 1;

ENDPOINT_NUMBER ENDPOINT_VALUE ENDPOINT_REPEAT_COUNT
--------------- -------------- ---------------------
1           2011                     1
13           2014                     8
26           2032                     6
36           2036                     4
45           2043                     3
51           2051                     5
52           2052                     1
54           2053                     2
60           2054                     6
72           2056                     5

10 rows selected.

高さ調整済ヒストグラムでは、オプティマイザは、指定された10個のヒストグラム・バケットに72行を均一に配分する必要があります。そのため、それぞれのバケットに入る行数はおよそ7行です。これはハイブリッド・ヒストグラムなので、オプティマイザは、1つの値が1個より多くのバケットを占めないように値を分配します。たとえば、オプティマイザは値2036の一部のインスタンスを別のバケットに入れることはしません。すべてのインスタンスをバケット36に入れます。

エンドポイント繰返しカウントは、バケット内で最も高い値が繰り返される回数を示します。これらの値のエンドポイント番号と繰返しカウントを使用することによって、オプティマイザはカーディナリティを見積ることができます。たとえば、バケット36には値2033、2034、2035および2036のインスタンスが格納されています。エンドポイント値2036のエンドポイント繰返しカウントは4です。そのため、オプティマイザはこの値に4つのインスタンスが存在することを認識しています。2033など、エンドポイントではない値の場合、オプティマイザは密度を使用してカーディナリティを見積ります。

関連項目:

- DBMS_STATS.GATHER_TABLE_STATSプロシージャの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

- USER_TAB_COL_STATISTICSビューの詳細は、『Oracle Databaseリファレンス』を参照してください。

- USER_HISTOGRAMSビューの詳細は、『Oracle Databaseリファレンス』を参照してください。

12 オプティマイザ統計の管理: 基本的なトピック

この章では、オプティマイザ統計管理に関する基本タスクについて説明します。

この章の内容は次のとおりです。

- オプティマイザ統計プリファレンスの設定

- 自動オプティマイザ統計収集の構成

- オプティマイザ統計の手動収集

- システム統計の手動収集

関連項目:

- オプティマイザ統計に関連する概念およびタスクの詳細は、「オプティマイザ統計の管理: 高度なトピック」を参照してください。

- 「オプティマイザ統計の概念」

- 問合せオプティマイザの概念

オプティマイザ統計収集について

Oracle Databaseでは、オプティマイザ統計収集とは、固定オブジェクトを含む、データベース・オブジェクトのオプティマイザ統計を収集することです。

データベースには、オプティマイザ統計が自動的に収集されます。DBMS_STATSパッケージを使用して、手動で収集することもできます。

オプティマイザ統計収集の目的

表の内容および関連付けられた索引が頻繁に変更されると、オプティマイザによって最適ではない問合せの実行計画が選択される可能性があります。パフォーマンスの問題が発生する可能性を回避するには、統計を最新に保つ必要があります。

DBAの介入を最小化するために、Oracleデータベースでは、様々なタイミングでオプティマイザ統計が自動収集されます。AutoTaskを有効化してDBMS_STATSを実行するなど、一部の自動オプションは構成が可能です。

オプティマイザ統計管理のユーザー・インタフェース

Oracle Enterprise Manager Cloud Control(Cloud Control)またはコマンドラインのPL/SQLのいずれかを使用してオプティマイザ統計を管理できます。

オプティマイザ統計管理のグラフィカル・インタフェース

Cloud Controlの「オプティマイザ統計の管理」ページは、オプティマイザ統計の管理が可能なGUIです。

Cloud Controlのデータベース・ホーム・ページへのアクセス

Oracle Enterprise Manager Cloud Controlでは、GUIベースの単一フレームワーク内で複数のデータベースを管理できます。

Cloud Controlを使用してデータベース・ホーム・ページにアクセスする手順は次のとおりです。

1. 適切な資格証明を使用してCloud Controlにログインします。

2. 「ターゲット」メニューの下で、「データベース」を選択します。

3. データベース・ターゲットのリストで、管理対象のOracle Databaseインスタンスのターゲットを選択します。

4. データベースの資格証明の入力を求められた場合は、実行するタスクに必要な最小限の資格証明を入力します。

関連項目:

Cloud Controlオンライン・ヘルプ

「オプティマイザ統計コンソール」へのアクセス

オプティマイザ統計コンソール・ページでリンクされているページを使用してオプティマイザ統計に関連する最も必要なタスクを実行できます。

Cloud Controlを使用してオプティマイザ統計を管理するには:

1. 「データベース・ホーム」ページにアクセスします。

2. 「パフォーマンス」メニューから、「SQL」→「オプティマイザ統計」を選択します。
「オプティマイザ統計コンソール」が表示されます。

関連項目:

Oracle Enterprise Manager Cloud Controlのオンライン・ヘルプを参照してください。

オプティマイザ統計管理のコマンドライン・インタフェース

DBMS_STATSパッケージは、オプティマイザ統計タスクのほとんどを実行します。自動統計収集を有効化および無効化するには、DBMS_AUTO_TASK_ADMIN PL/SQLパッケージを使用します。

関連項目:

DBMS_STATSおよびDBMS_AUTO_TASK_ADMINの使用方法の詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

自動オプティマイザ統計収集の構成

このトピックでは、オプティマイザ統計を自動的に収集するようにOracle Databaseを構成する方法について説明します。

この項の内容は次のとおりです。

- 自動オプティマイザ統計収集について

- Cloud Controlを使用した自動オプティマイザ統計収集の構成

- コマンドラインからの自動オプティマイザ統計収集の構成

自動オプティマイザ統計収集について

自動化メンテナンス・タスク・インフラストラクチャ(AutoTask)は、メンテナンス・ウィンドウと呼ばれるOracle Schedulerウィンドウで自動的に実行するタスクをスケジュールします。

デフォルトでは、1つのウィンドウが週の各曜日にスケジュールされます。自動オプティマイザ統計収集はAutoTaskの一部として実行されます。この収集は、デフォルトでは事前に定義されたすべてのメンテナンス・ウィンドウで実行されます。

注意:

自動オプティマイザ統計収集をプラガブル・データベースとともに使用すると、データの可視性と権限の要件が一致しない場合があります。

オプティマイザ統計を収集する場合、データベースで内部プロシージャがコールされます。このプロシージャは、GATHER_DATABASE_STATSプロシージャをGATHER AUTOオプションを指定して実行する場合と同様に動作します。自動統計収集はデータベース内のすべてのプリファレンス・セットに従います。

手動収集と自動収集の主な違いは、自動収集では統計が必要となるデータベース・オブジェクトが優先される点です。自動収集では、メンテナンス・ウィンドウがクローズされる前にすべてのオブジェクトが評価され、統計がないか、非常に古い統計があるオブジェクトが優先されます。

注意:

手動で統計を収集する場合は、自動収集のオブジェクト優先付けをDBMS_AUTO_TASK_IMMEDIATEパッケージを使用して再現できます。このパッケージでは、自動夜間統計収集ジョブで実行されるものと同じ統計収集ジョブが実行されます。

関連項目:

コンテナ・データベース(CDB)内での管理機能の動作をまとめた表が記載されている『Oracle Database管理者ガイド』を参照してください

Cloud Controlを使用した自動オプティマイザ統計収集の構成

Cloud Controlを使用して、自動オプティマイザ統計収集など、すべての自動メンテナンス・タスクを有効化および無効化できます。

ほとんどの場合、デフォルトのウィンドウ・タイミングで問題なく機能します。しかし、バルク・ロードなどの操作を、ウィンドウ内で行うことも考えられます。そのような場合、自動統計収集と同時に操作を行うことにより競合が発生するのを回避するには、必要に応じてウィンドウを変更することをお薦めします。

Cloud Controlを使用して自動オプティマイザ統計収集を管理する手順は次のとおりです。

1. 「Cloud Controlのデータベース・ホーム・ページへのアクセス」の説明に従って、「データベース・ホーム」ページにアクセスします。

2. 「管理」メニューから、「Oracle Scheduler」を選択し、「自動化メンテナンス・タスク」を選択します。
自動化メンテナンス・タスク・ページが表示されます。

このページには、事前定義されたタスクが表示されます。各タスクに関する情報を取得するには、タスクに対応するリンクをクリックします。

3. 「構成」をクリックします。
「自動化メンテナンス・タスク構成」ページが表示されます。

デフォルトでは、自動オプティマイザ統計収集はMAINTENANCE_WINDOW_GROUP内の事前に定義されたすべてのメンテナンス・ウィンドウで実行されます。

4. 次の手順を実行します。

a. 「オプティマイザ統計の収集」の「タスク設定」セクションで、「有効」または「無効」のいずれかを選択して自動化タスクを有効化または無効化します。

注意:

自動統計収集は、ディクショナリ・オブジェクトおよびユーザー・オブジェクトに対する問合せの最適な計画をオプティマイザが生成する上で重要であるため、無効にしないことを強くお薦めします。自動収集を無効にする場合は、ディクショナリ・スキーマおよびユーザー・スキーマに対して適切な自動統計収集の方針を立てるようにしてください。

b. 週の特定の日に統計収集を無効化するには、ウィンドウ名の横にある該当するチェック・ボックスを選択します。

c. ウィンドウ・グループの特性を変更するには、「ウィンドウ・グループの編集」をクリックします。

d. ウィンドウの時間を変更するには、ウィンドウの名前(「MONDAY_WINDOW」など)をクリックし、「スケジュール」セクションで「編集」をクリックします。
ウィンドウの編集ページが表示されます。

このページでは、ウィンドウ実行の期間や開始時間などのパラメータを変更できます。

e. 「適用」をクリックします。

関連項目:

Oracle Enterprise Manager Cloud Controlのオンライン・ヘルプを参照してください。

コマンドラインからの自動オプティマイザ統計収集の構成

Cloud Controlを使用せずに自動オプティマイザ統計収集を構成する場合は、コマンドラインを使用する必要があります。

次の選択肢があります。

- DBMS_AUTO_TASK_ADMIN PL/SQLパッケージに含まれるENABLEまたはDISABLEプロシージャを実行します。
コマンドラインで使用する手法としては、このパッケージをお薦めします。ENABLEおよびDISABLEプロシージャのどちらに対しても、window_nameパラメータを使用して特定のメンテナンス・ウィンドウを指定できます。

- STATISTICS_LEVEL(初期化レベル)をBASICに設定して、自動化SQLチューニング・アドバイザなどすべてのアドバイザおよび統計の収集を無効化します。

注意:

監視機能と多くの自動機能が無効になるため、STATISTICS_LEVELはBASICに設定しないことを強くお薦めします。

DBMS_AUTO_TASK_ADMINを使用して自動統計収集を管理する手順は次のとおりです。

1. 管理者権限でデータベースにSQL*Plusを接続し、次のいずれかを実行します。

- 自動タスクを有効にするには、次のPL/SQLブロックを実行します。

BEGIN
DBMS_AUTO_TASK_ADMIN.ENABLE (
client_name  => 'auto optimizer stats collection'
,   operation    => NULL
,   window_name  => NULL
);
END;
/

- 自動タスクを無効にするには、次のPL/SQLブロックを実行します。

BEGIN
DBMS_AUTO_TASK_ADMIN.DISABLE (
client_name  => 'auto optimizer stats collection'
,   operation    => NULL
,   window_name  => NULL
);
END;
/

2. データ・ディクショナリを問い合せて、変更を確認します。
たとえば、次のようにDBA_AUTOTASK_CLIENTを問い合せます。

COL CLIENT_NAME FORMAT a31

SELECT CLIENT_NAME, STATUS
FROM   DBA_AUTOTASK_CLIENT
WHERE  CLIENT_NAME = 'auto optimizer stats collection';

出力例は次のように表示されます。

CLIENT_NAME                     STATUS
------------------------------- --------
auto optimizer stats collection ENABLED

自動統計収集のウィンドウ属性を変更する手順は次のとおりです。

1. 管理者権限でSQL*Plusをデータベースに接続します。

2. 必要に応じてメンテナンス・ウィンドウの属性を変更します。
たとえば、月曜日のメンテナンス・ウィンドウが午前5時に開始されるように変更するには、次のPL/SQLプログラムを実行します。

BEGIN
DBMS_SCHEDULER.SET_ATTRIBUTE (
'MONDAY_WINDOW'
,   'repeat_interval'
,   'freq=daily;byday=MON;byhour=05;byminute=0;bysecond=0'
);
END;
/

関連項目:

- DBMS_AUTO_TASK_ADMINパッケージの詳細は、Oracle Database PL/SQLパッケージおよびタイプ・リファレンスを参照してください

- STATISTICS_LEVEL初期化パラメータの詳細は、Oracle Databaseリファレンスを参照してください

オプティマイザ統計プリファレンスの設定

このトピックでは、DBMS_STATS.SET_*_PREFSプロシージャを使用してオプティマイザ統計のデフォルトを設定する方法について説明します。

この項の内容は次のとおりです。

- オプティマイザ統計プリファレンスについて

- Cloud Controlを使用したグローバル・オプティマイザ統計プリファレンスの設定

- Cloud Controlを使用したオブジェクト・レベルのオプティマイザ統計プリファレンスの設定

- コマンドラインからのオプティマイザ統計プリファレンスの設定

オプティマイザ統計プリファレンスについて

オプティマイザ統計プリファレンスでは、自動統計収集およびDBMS_STATS統計収集プロシージャで使用されるパラメータのデフォルト値が設定されます。

表、スキーマ、データベース(すべての表)およびグローバル・レベルでオプティマイザ統計プリファレンスを設定できます。グローバル・プリファレンスは、プリファレンスなしの表および将来作成される表を示します。SET_*_PREFS形式の後にプロシージャ名が続きます。

統計プリファレンスを設定するDBMS_STATSプロシージャ

DBMS_STATS.SET_*_PREFSプロシージャは、DBMS_STATS.GATHER_*_STATSプロシージャで使用されるパラメータのデフォルト値を変更します。現在のプリファレンスを問い合せるには、DBMS_STATS.GET_PREFSファンクションを使用します。

統計プリファレンスを設定すると、優先順位は次のようになります。

1. 表プリファレンス(特定の表、スキーマ内のすべての表、またはデータベース内のすべての表に設定)

2. グローバル・プリファレンス

3. デフォルト・プリファレンス

次の表は、関連するDBMS_STATSプロシージャをまとめたものです。

表12-1 オプティマイザ統計プリファレンスを設定するDBMS_STATSプロシージャ

プロシージャ

有効範囲

SET_TABLE_PREFS

指定された表のみ。

SET_SCHEMA_PREFS

指定されたスキーマのすべての既存の表。

このプロシージャは、指定されたスキーマの各表でSET_TABLE_PREFSをコールします。SET_SCHEMA_PREFSをコールすることで、その実行後に作成されたどの新規の表にも影響が及ぶことはありません。新しい表は、GLOBAL_PREF値をすべてのパラメータで使用します。

SET_DATABASE_PREFS

データベースでユーザーが定義したすべてのスキーマ。ADD_SYSパラメータをtrueに設定すると、SYSおよびSYSTEMなどのシステム所有のスキーマを含めることができます。

このプロシージャは、指定されたスキーマの各表でSET_TABLE_PREFSをコールします。SET_DATABASE_PREFSをコールすることで、その実行後に作成されたどの新規オブジェクトにも影響が及ぶことはありません。新しいオブジェクトは、GLOBAL_PREF値をすべてのパラメータで使用します。

SET_GLOBAL_PREFS

既存の表プリファレンスを持たないすべての表。

表プリファレンスが設定されているか、DBMS_STATS.GATHER_*_STATS文でパラメータを明示的に設定しないかぎり、すべてのパラメータのデフォルトはグローバル設定です。SET_GLOBAL_PREFSで変更が行われると、その実行後に作成されたすべての新規オブジェクトに影響が及びます。新しいオブジェクトは、SET_GLOBAL_PREFS値をすべてのパラメータで使用します。

SET_GLOBAL_PREFSを使用して、AUTOSTATS_TARGETパラメータのデフォルト値を設定できます。この追加のパラメータは、夜間のメンテナンス・ウィンドウで実行される自動統計収集ジョブによって影響を受けるオブジェクトを制御します。AUTOSTATS_TARGETに使用できる値は、ALL、ORACLEおよびAUTO (デフォルト)です。

グローバル・レベルでCONCURRENTプリファレンスのみを設定できます。SET_GLOBAL_PREFSを使用してプリファレンスINCREMENTAL_LEVELを設定することはできません。

関連項目:

- 「同時統計収集について」

- オプティマイザ統計の設定に関するDBMS_STATSプロシージャの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください

統計プリファレンスの設定: 例

この例は、SET_TABLE_PREFS、SET_SCHEMA_STATSおよびSET_DATABASE_PREFSの関係を示しています。

表12-2 統計収集プロシージャのプリファレンスの変更

アクション

説明

SQL> SELECT DBMS_STATS.GET_PREFS
('incremental', 'sh','costs')
AS "STAT_PREFS" FROM DUAL;

STAT_PREFS
----------
TRUE

costsのINCREMENTALプリファレンスを問い合せて、このプリファレンスがtrueに設定されているかどうかを確認します。

SQL> EXEC DBMS_STATS.SET_TABLE_PREFS
('sh', 'costs', 'incremental', 'false');

PL/SQL procedure successfully completed.

SET_TABLE_PREFSを使用して、costs表に対してのみINCREMENTALプリファレンスをfalseに設定します。

SQL> SELECT DBMS_STATS.GET_PREFS
('incremental', 'sh', 'costs')
AS "STAT_PREFS" FROM DUAL;

STAT_PREFS
----------
FALSE

costsのINCREMENTALプリファレンスを問い合せて、このプリファレンスがfalseに設定されているかどうかを確認します。

SQL> EXEC DBMS_STATS.SET_SCHEMA_PREFS
('sh', 'incremental', 'true');

PL/SQL procedure successfully completed.

SET_SCHEMA_PREFSを使用して、shスキーマ内のすべての表(costsなど)のINCREMENTALプリファレンスをtrueに設定します。

SQL> SELECT DBMS_STATS.GET_PREFS
('incremental', 'sh', 'costs')
AS "STAT_PREFS" FROM DUAL;

STAT_PREFS
----------
TRUE

costsのINCREMENTALプリファレンスを問い合せて、このプリファレンスがtrueに設定されているかどうかを確認します。

SQL> EXEC DBMS_STATS.SET_DATABASE_PREFS
('incremental', 'false');

PL/SQL procedure successfully completed.

SET_DATABASE_PREFSを使用して、すべてのユーザー定義スキーマのすべての表のINCREMENTALプリファレンスをfalseに設定します。

SQL> SELECT DBMS_STATS.GET_PREFS
('incremental', 'sh', 'costs')
AS "STAT_PREFS" FROM DUAL;

STAT_PREFS
----------
FALSE

costsのINCREMENTALプリファレンスを問い合せて、このプリファレンスがfalseに設定されているかどうかを確認します。

Cloud Controlを使用したグローバル・オプティマイザ統計プリファレンスの設定

グローバル・プリファレンスは、既存の表プリファレンスを持たないデータベース内のすべてのオブジェクトに適用されます。Cloud Controlを使用してグローバル・レベルでオプティマイザ統計プリファレンスを設定できます。

Cloud Controlを使用してグローバル・オプティマイザ統計プリファレンスを設定する手順は次のとおりです。

1. 「オプティマイザ統計コンソール」へのアクセスの説明に従って、オプティマイザ統計コンソール・ページに移動します。

2. 「グローバル統計の採取オプション」をクリックします。
「グローバル統計の採取オプション」ページが表示されます。

3. 必要な変更を行い、「適用」をクリックします。

関連項目:

Oracle Enterprise Manager Cloud Controlのオンライン・ヘルプを参照してください。

Cloud Controlを使用したオブジェクト・レベルのオプティマイザ統計プリファレンスの設定

Cloud Controlを使用してデータベース、スキーマおよび表の各レベルでオプティマイザ統計プリファレンスを設定できます。

Cloud Controlを使用してオブジェクト・レベルのオプティマイザ統計プリファレンスを設定する手順は次のとおりです。

1. 「オプティマイザ統計コンソール」へのアクセスの説明に従って、オプティマイザ統計コンソールに移動します。

2. 「オブジェクト・レベルの統計採取プリファレンス」をクリックします。
「オブジェクト・レベルの統計採取プリファレンス」が表示されます。

3. 表レベルのプリファレンス・セットがある表のプリファレンスを変更するには、次を行います(変更しない場合は次のステップにスキップします)。

a. 「スキーマ」および「表名」に値を入力します。スキーマ内のすべての表を表示するには、「表名」を空白のままにします。
ページが表の名前で更新されます。

b. 必要な表を選択して、「プリファレンスの編集」をクリックします。
「プリファレンスの編集」ページの「一般」サブページが表示されます。

c. 必要に応じてプリファレンスを変更し、「適用」をクリックします。

4. 表レベルのプリファレンス・セットがない表のプリファレンスを設定するには、次を実行します(設定しない場合は次のステップにスキップします)。

a. 「表のプリファレンスの追加」をクリックします。
「表のプリファレンスの追加」ページの「一般」サブページが表示されます。

b. 「表名」でスキーマと表名を入力します。

c. 必要に応じてプリファレンスを変更し、「OK」をクリックします。

5. スキーマのプリファレンスを設定するには、次を実行します。

a. 「スキーマ表のプリファレンスの設定」をクリックします。
「スキーマ・プリファレンスの編集」ページの「一般」サブページが表示されます。

b. 「スキーマ」でスキーマ名を入力します。

c. 必要に応じてプリファレンスを変更し、「OK」をクリックします。

関連項目:

Oracle Enterprise Manager Cloud Controlのオンライン・ヘルプを参照してください。

コマンドラインからのオプティマイザ統計プリファレンスの設定

オプティマイザ統計プリファレンスの設定にCloud Controlを使用しない場合は、表12-1で説明したDBMS_STATSプロシージャを呼び出すことができます。

前提条件

このタスクには次の前提条件があります。

- グローバル・プリファレンスまたはデータベース・プリファレンスを設定するには、SYSDBA権限、またはANALYZE ANY DICTIONARYシステム権限およびANALYZE ANYシステム権限の両方を所有している必要があります。

- スキーマ・プリファレンスを設定するには、所有者として接続するか、またはSYSDBA権限、あるいはANALYZE ANYシステム権限を所有している必要があります。

- 表プリファレンスを設定するには、表の所有者として接続するか、またはANALYZE ANYシステム権限を所有している必要があります。

コマンドラインからオプティマイザ統計プリファレンスを設定する手順は次のとおりです。

1. 必要な権限でSQL*Plusをデータベースに接続します。

2. オプションで、DBMS_STATS.GET_PREFSプロシージャをコールして、オブジェクト・レベルで設定されているプリファレンスを確認します。特定の表が設定されていない場合は、グローバル・レベルで設定されているプリファレンスを確認します。
たとえば、sh.sales表のSTALE_PERCENTパラメータ設定を次のように取得します。

SELECT DBMS_STATS.GET_PREFS('STALE_PERCENT', 'SH', 'SALES')
FROM   DUAL;

3. 表12-1の適切なプロシージャを、次のパラメータを指定して実行します。

- ownname - スキーマ名の設定(SET_TAB_PREFSおよびSET_SCHEMA_PREFSのみ)

- tabname - 表名の設定(SET_TAB_PREFSのみ)

- pname - パラメータ名の設定

- pvalue - パラメータ値の設定

- add_sys - システム表の追加(オプションでSET_DATABASE_PREFSのみ)

次の例では、表の統計が失効しているとみなされる前に、sh.salesの行の13%が変更される必要があることを指定しています。

EXEC DBMS_STATS.SET_TABLE_PREFS('SH', 'SALES', 'STALE_PERCENT', '13');

4. オプションで、*_TAB_STAT_PREFSビューを問い合せて変更を確認します。
たとえば、次のようにDBA_TAB_STAT_PREFSを問い合せます。

COL OWNER FORMAT a5
COL TABLE_NAME FORMAT a15
COL PREFERENCE_NAME FORMAT a20
COL PREFERENCE_VALUE FORMAT a30
SELECT * FROM DBA_TAB_STAT_PREFS;

出力例は次のように表示されます。

OWNER TABLE_NAME      PREFERENCE_NAME      PREFERENCE_VALUE
----- --------------- -------------------- ------------------------------
OE    CUSTOMERS       NO_INVALIDATE        DBMS_STATS.AUTO_INVALIDATE
SH    SALES           STALE_PERCENT        13

関連項目:

プログラム・ユニットのパラメータ名およびパラメータ値の説明は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

オプティマイザ統計の手動収集

自動統計収集の代替または補足として、DBMS_STATSパッケージを使用し、統計を手動で収集できます。

この項の内容は次のとおりです。

- DBMS_STATSを使用した手動統計収集について

- オプティマイザ統計の手動収集のガイドライン

- オプティマイザ統計が失効するタイミングの判別

- スキーマ統計および表統計の収集

- 固定オブジェクトの統計情報の収集

- 動的統計を使用した変化しやすい表の統計の収集

- オプティマイザ統計の同時収集

- パーティション・オブジェクトの増分統計の収集

関連項目:

- 「自動オプティマイザ統計収集の構成」

- DBMS_STATSパッケージの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください

DBMS_STATSを使用した手動統計収集について

DBMS_STATSパッケージを使用してオプティマイザ統計を操作します。オブジェクト、スキーマおよびデータベースなどの様々なレベルに細分化してオブジェクトおよび列の統計を収集できます。また、物理システムの統計を収集できます。

次の表では、オプティマイザ統計収集のDBMS_STATSプロシージャの概要が示されています。このパッケージでは、表クラスタの統計は収集されません。ただし、表クラスタの個々の表の統計は収集できます。

表12-3 オプティマイザ統計収集のDBMS_STATSプロシージャ

プロシージャ

説明

GATHER_INDEX_STATS

索引統計を収集します。

GATHER_TABLE_STATS

表、列および索引の各統計を収集します。

GATHER_SCHEMA_STATS

スキーマのすべてのオブジェクトの統計を収集します。

GATHER_DICTIONARY_STATS

SYSやSYSTEMなどのすべてのシステム・スキーマのほか、CTXSYSやDRSYSなどのオプション・スキーマの統計を収集します。

GATHER_DATABASE_STATS

データベース内ですべてのオブジェクトの統計を収集します。

OPTIONSパラメータがGATHER STALEまたはGATHER AUTOに設定されている場合は、失効した統計を含むすべての表および統計がないすべての表の統計がGATHER_SCHEMA_STATSプロシージャおよびGATHER_DATABASE_STATSプロシージャで収集されます。監視対象の表の変更が10%を超えた場合は、これらの統計が失効していると判断され、再び統計が収集されます。

注意:

「自動オプティマイザ統計収集の構成」の説明に従って、夜間に統計を自動収集するジョブを構成できます。

関連項目:

- 「システム統計の手動収集」

- DBMS_STATSパッケージの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください

オプティマイザ統計の手動収集のガイドライン

適度な速度で変更されるデータベース・オブジェクトに対しては、ほとんどの場合、自動収集で十分です。

次のような場合、自動収集が不適当または使用できないことがあります。

- 特定のタイプのバルク・ロードを実行する際に、問合せを即座に実行する必要があるために、統計収集のメンテナンス・ウィンドウを待機できない場合。「バルク・ロードのためのオンライン統計収集」を参照してください。

- 代表的ではないワークロードを実行しているときに、固定表の統計を自動統計収集で収集する場合。「固定オブジェクトの統計情報の収集」を参照してください。

- 自動統計収集はシステム統計を収集しません。「システム統計の手動収集」を参照してください。

- 日中に削除または切り捨てられて再作成される変化しやすい表。「動的統計を使用した変化しやすい表の統計の収集」を参照してください。

この項では、手動での統計収集を選択することになる一般的な状況に対してガイドラインを提供します。

- サンプル・サイズの設定のガイドライン

- パラレル統計収集のガイドライン

- パーティション・オブジェクトのガイドライン

- 変更頻度の高いオブジェクトのガイドライン

- 外部表のガイドライン

サンプル・サイズの設定のガイドライン

オプティマイザ統計において、サンプリングとは表の行のランダムなサブセットから統計を収集することです。サンプリングでは、データベースによる全表スキャンと表全体のソートを避けることができるため、統計収集に必要なリソースが最小化されます。

データベースでは、表内のすべての表が処理される場合、つまり100%のサンプルが取得される場合に最も正確な統計が収集されます。ただし、サンプル・サイズが大きくなるほど、統計収集操作にかかる時間も長くなります。課題は、妥当な時間で正確な統計を取得できるようなサンプル・サイズを決定することです。

DBMS_STATSでは、サンプリングする表内の行の割合を制御するESTIMATE_PERCENTパラメータをユーザーが指定した場合にサンプリングが使用されます。パフォーマンスの向上を最大化するとともに必要な統計の正確性を達成するには、ESTIMATE_PERCENTパラメータでデフォルト設定のDBMS_STATS.AUTO_SAMPLE_SIZEを使用することをお薦めします。この場合、Oracle Databaseは、サンプル・サイズを自動的に選択します。この設定により、次の使用が有効になります。

- サンプリングよりはるかに高速なハッシュ・ベースのアルゴリズム
このアルゴリズムではすべての行が読み取られ、100%のサンプルから生成された統計と同じぐらい正確な統計が生成されます。この手法を使用して計算された統計は確定的です。

- 増分統計

- 同時統計

- 新規ヒストグラム・タイプ(「ハイブリッド・ヒストグラム」を参照)

DBA_TABLES.SAMPLE_SIZE列は、統計を収集するために使用される実際のサンプル・サイズを示します。

パラレル統計収集のガイドライン

デフォルトでは、表または索引レベルに指定された並列度で統計が収集されます。この設定は、DBMS_STATS収集プロシージャのdegree引数で上書きできます。

degreeをDBMS_STATS.AUTO_DEGREEに設定することをお薦めします。この設定を使用すると、オブジェクト・サイズおよびパラレル化関連の初期化パラメータに基づいて適切な並列度が選択されます。

データベースでは、ほとんどの統計をシリアルまたはパラレルで収集できます。ただし、クラスタ索引、ドメイン索引およびビットマップ結合索引などの一部の索引統計は、データベースによってパラレルで収集されることはありません。データベースでは、パラレルでの統計収集時にサンプリングを使用できます。

注意:

統計のパラレル収集と同時収集を混同しないでください。「同時統計収集について」を参照してください。

パーティション・オブジェクトのガイドライン

パーティション表および索引に対して、DBMS_STATSは、各パーティションの個別の統計を収集できます。また、全表または全索引のグローバル統計も収集できます。コンポジット・パーティションについても同様に、DBMS_STATSはサブパーティション、パーティション、全表および全索引の個別の統計を収集できます。

DBMS_STATSプロシージャに対してgranularity引数を使用して、収集されるパーティション統計のタイプを決定します。granularityをデフォルト値のAUTOに設定し、パーティションのタイプに応じてサブパーティション統計、パーティション統計またはグローバル統計を収集することをお薦めします。ALL設定では、すべてのタイプの統計が収集されます。

関連項目:

「パーティション・オブジェクトの増分統計の収集」

変更頻度の高いオブジェクトのガイドライン

表の変更が頻繁に行われる場合は、表が失効しないように十分な回数の統計を収集しますが、収集のオーバーヘッドでパフォーマンスが低下しない回数にします。新しい統計の収集が週に一度または月に一度しか必要がない場合もあります。ベスト・プラクティスは、スクリプトまたはジョブ・スケジューラを使用して、DBMS_STATS.GATHER_SCHEMA_STATSプロシージャおよびDBMS_STATS.GATHER_DATABASE_STATSプロシージャを定期的に実行することです。

外部表のガイドライン

外部表に対するデータ操作は許可されないため、データベースで外部表の統計が失効としてマークされることはありません。たとえば基礎となるデータファイルが変更されたなどの理由で、外部表に新しい統計が必要な場合は、統計を再収集します。

通常の表で使用するプロシージャと同じプロシージャで外部表の統計を手動で収集します。

オプティマイザ統計が失効するタイミングの判別

表に失効した統計があるということは、表のデータを正確に反映していないということになります。データベースでは、データベース・オブジェクトに新しい統計が必要となるタイミングの判別に役立つ表監視機能が提供されます。

監視では、最新の統計収集以降の、表でのDML操作の概数と、表が切り捨てられたかどうかが追跡されます。DBMS_STATS.FLUSH_DATABASE_MONITORING_INFOを実行することで、メモリーに保持されている未処理の監視情報をただちに反映できます。このプロシージャの実行後に、DBA_TAB_STATISTICSおよびDBA_IND_STATISTICSのSTALE_STATS列を問い合せて、統計が失効しているかどうかを確認します。この列は、DBA_TAB_MODIFICATIONSビューおよびDBMS_STATSのSTALE_PERCENTプリファレンスのデータに基づきます。

STALE_STATS列の値は、次のとおりです。

- YES
統計が失効しています。

- NO
統計は失効していません。

- NULL
統計が収集されていません。

GATHER AUTOオプションを指定してGATHER_SCHEMA_STATSまたはGATHER_DATABASE_STATSを実行すると、統計がないか失効しているオブジェクトのみの統計が収集されます。

前提条件

このチュートリアルでは、次のことが前提となっています。

- 表監視がsh.salesに対して有効化されています。STATISTICS_LEVEL初期化パラメータがTYPICALまたはALLに設定されている場合はデフォルトで有効化されています。

- ANALYZE_ANYシステム権限があり、DBMS_STATS.FLUSH_DATABASE_MONITORING_INFOプロシージャを実行できます。

失効した統計を判別する手順は次のとおりです。

1. 必要な権限でSQL*Plusをデータベースに接続します。

2. オプションで、データベース監視情報をメモリーからディスクに書き込みます。
たとえば、次のプロシージャを実行します。

BEGIN
DBMS_STATS.FLUSH_DATABASE_MONITORING_INFO;
END;
/

3. データ・ディクショナリを問い合せて失効している統計を確認します。
次の例では、sh.sales表で失効している統計を問い合せます(出力の一部を含む)。

COL PARTITION_NAME FORMAT a15

SELECT PARTITION_NAME, STALE_STATS
FROM   DBA_TAB_STATISTICS
WHERE  TABLE_NAME = 'SALES'
AND    OWNER = 'SH'
ORDER BY PARTITION_NAME;

PARTITION_NAME  STA
--------------- ---
SALES_1995      NO
SALES_1996      NO
SALES_H1_1997   NO
SALES_H2_1997   NO
SALES_Q1_1998   NO
SALES_Q1_1999   NO
.
.
.

関連項目:

- DBA_TAB_MODIFICATIONSビューの詳細は、『Oracle Databaseリファレンス』を参照してください

- DBMS_STATS.FLUSH_DATABASE_MONITORING_INFOプロシージャの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

スキーマ統計および表統計の収集

表統計を収集するにはGATHER_TABLE_STATSを使用し、スキーマ内のすべてのオブジェクトの統計を収集するにはGATHER_SCHEMA_STATSを使用します。

DBMS_STATSを使用してスキーマ統計を収集する手順は次のとおりです。

1. SQL*Plusを起動し、実行するプロシージャに対する適切な権限でデータベースに接続します。

2. GATHER_TABLE_STATSプロシージャまたはGATHER_SCHEMA_STATSプロシージャを実行して、必要なパラメータを指定します。
一般的には次のパラメータがあります。

- 所有者 - ownname

- オブジェクト名 - tabname、indname、partname

- 並列度 - degree

関連項目:

GATHER_TABLE_STATSプロシージャの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

例12-1 表統計の収集

この例では、DBMS_STATSパッケージを使用して、並列設定が2のsh.customers表の統計を収集します。

BEGIN
DBMS_STATS.GATHER_TABLE_STATS (
ownname => 'sh'
,   tabname => 'customers'
,   degree  => 2
);
END;
/

固定オブジェクトの統計情報の収集

固定オブジェクトとは、動的パフォーマンス表とその索引です。これらのオブジェクトは、現在のデータベース・アクティビティを記録します。

他のデータベース表とは異なり、オプティマイザ統計が見つからない場合にX$表を参照するSQL文の動的統計が自動的に使用されることはありません。かわりに、オプティマイザは事前定義されたデフォルト値を使用します。このデフォルト値は代表的なものではない場合があり、最適ではない実行計画につながる可能性があります。したがって、固定オブジェクトの統計を最新のものにしておくことが重要です。

Oracle Databaseは、以前に収集されていない場合、自動統計収集の一部として自動的に固定オブジェクトの統計を収集します(「自動オプティマイザ統計収集の制御」を参照)。DBMS_STATS.GATHER_FIXED_OBJECTS_STATSをコールして手動で固定オブジェクトの統計を収集することもできます。統計は、代表的なアクティビティがデータベースで行われているときに収集することをお薦めします。

前提条件

このプロシージャを実行するには、SYSDBAまたはANALYZE ANY DICTIONARYシステム権限が必要です。

GATHER_FIXED_OBJECTS_STATSを使用してスキーマ統計を収集する手順は次のとおりです。

1. SQL*Plusを起動し、実行するプロシージャに対する適切な権限でデータベースに接続します。

2. 必要なパラメータを指定して、DBMS_STATS.GATHER_FIXED_OBJECTS_STATSプロシージャを実行します。
一般的には次のパラメータがあります。

- 現在の統計情報の保存場所を示す表の識別子: stattab

- stattab内の統計情報を関連付ける識別子(オプション): statid

- stattabを含んだスキーマ(現在のスキーマと異なる場合): statown

関連項目:

GATHER_TABLE_STATSプロシージャの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

例12-2 表統計の収集

この例では、DBMS_STATSパッケージを使用して固定オブジェクトの統計を収集します。

BEGIN
DBMS_STATS.GATHER_FIXED_OBJECTS_STATS;
END;
/

動的統計を使用した変化しやすい表の統計の収集

変化しやすい表(日中の間に著しく変更される表)の統計はすぐに失効します。たとえば、表は削除または切捨てが行われたり、再構築されたりする可能性があります。

変化しやすいオブジェクトの統計をNULLに設定した場合は、Oracle Databaseでは動的統計を使用して最適化中に必要な統計が動的に収集されます。OPTIMIZER_DYNAMIC_SAMPLING初期化パラメータでこの機能を制御します。

注意:

オプティマイザ統計のロックおよびロック解除の説明のように、代表的な統計を収集してロックすることは、変化しやすい表の統計を失効しないようにする代替の手法です。

前提条件

このチュートリアルでは、次のことが前提となっています。

- oe.orders表は非常に変化しやすい表です。

- orders表の統計を削除した上でロックし、データベースでその表の統計が収集されないようにします。この方法では、データベースによって、必要な統計を問合せ最適化の一部として動的に収集できます。

- oeユーザーは、DBMS_XPLAN.DISPLAY_CURSORの問合せに必要な権限を持っています。

オプティマイザ統計を削除およびロックする手順は次のとおりです。

1. oeユーザーとしてデータベースに接続した上でoe表の統計を削除します。
たとえば、次のプロシージャを実行します。

BEGIN
DBMS_STATS.DELETE_TABLE_STATS('OE','ORDERS');
END;
/

2. oe表の統計をロックします。
たとえば、次のプロシージャを実行します。

BEGIN
DBMS_STATS.LOCK_TABLE_STATS('OE','ORDERS');
END;
/

3. orders表を問い合せます。
たとえば、次の文を使用します。

SELECT COUNT(order_id) FROM orders;

4. カーソル内の計画を問い合せます。
次のコマンドを実行します(出力の一部を含む)。

SET LINESIZE 150
SET PAGESIZE 0

SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR);

SQL_ID  aut9632fr3358, child number 0
-------------------------------------
SELECT COUNT(order_id) FROM orders

Plan hash value: 425895392

---------------------------------------------------------------------
| Id  | Operation          | Name   | Rows  | Cost (%CPU)| Time     |
---------------------------------------------------------------------
|   0 | SELECT STATEMENT   |        |       |     2 (100)|          |
|   1 |  SORT AGGREGATE    |        |     1 |            |          |
|   2 |   TABLE ACCESS FULL| ORDERS |   105 |     2   (0)| 00:00:01 |
---------------------------------------------------------------------

Note
-----
- dynamic statistics used for this statement (level=2)

前述の実行計画の注意には、データベースでSELECT文の動的統計を使用したことが示されています。

関連項目:

「動的統計の制御」

オプティマイザ統計の同時収集

Oracle Databaseでは複数の表またはパーティションの統計を同時に収集できます。

Oracle Databaseでは複数の表またはパーティションの統計を同時に収集できます。この項の内容は次のとおりです。

- 同時統計収集について

- 同時統計収集の有効化

- パラレル実行および同時統計収集のためのシステムの構成

- 統計収集操作の監視

同時統計収集について

デフォルトでは、パーティション表の各パーティションは順に収集されます。

同時統計収集モードを有効にすると、スキーマ内の複数の表、表内の複数のパーティションまたはサブパーティションに対して、オプティマイザ統計をデータベースで同時に収集できます。データベースで複数のプロセッサをすべて使用可能にすることで、同時性により、統計の収集に必要な全体の時間を減らすことができます。

注意:

同時統計収集モードはパラレル問合せ処理に依存しませんが、その使用は可能です。

DBMS_STATSによる統計の同時収集の方法

Oracle Databaseでは、複数のツールおよびテクノロジを使用して、複数の統計収集ジョブを同時に作成および管理します。

データベースでは次のものが使用されます。

- Oracle Scheduler

- Oracle Database Advanced Queuing(AQ)

- Oracle Database Resource Manager(Resource Manager)

DBMS_STATS.SET_GLOBAL_PREFを使用してCONCURRENTプリファレンスを設定することで同時統計収集を有効化します。

データベースでは可能なかぎり多くの同時ジョブが実行されます。Job Schedulerは、同時に実行するジョブの数およびキューに入れるジョブの数を決定します。ジョブの実行が完了すると、データベースですべての表、パーティションおよびサブパーティションの統計の収集が完了するまで、スケジューラによってさらにジョブがデキューされ実行されます。ジョブの最大数は、JOB_QUEUE_PROCESSES初期化パラメータと使用可能なシステム・リソースによる制約を受けます。

ほとんどの場合、DBMS_STATSプロシージャによって表のパーティションまたはサブパーティションごとに別のジョブが作成されます。ただし、パーティションまたはサブパーティションが空または非常に小さい場合には、ジョブ・メンテナンスのオーバーヘッドを減らすために、データベースで自動的にそのオブジェクトと他の小さなオブジェクトを1つのジョブに一括する場合があります。

次の図には異なるレベルでのジョブの作成が示されています。表3はパーティション化された表で、その他の表はパーティション化されていません。ジョブ3は、表3のコーディネータ・ジョブとして動作し、その表のパーティションごとにジョブを作成するほか、表3のグローバル統計用に別のジョブを作成します。次の例では、増分統計収集が有効化されていることを前提としています。無効化されている場合、パーティションのジョブの完了後にグローバル統計パーティション・レベルの統計からグローバル統計が導出されます。

図12-1 同時統計収集ジョブ

関連項目:

- 同時統計収集の有効化

- DBMS_STATSパッケージの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください

- JOB_QUEUE_PROCESSES初期化パラメータの詳細は、『Oracle Databaseリファレンス』を参照してください。

同時統計収集とリソースの管理

DBMS_STATSパッケージでは、ユーザーが開始した統計収集コールの一部である同時統計収集ジョブによって使用されるリソースを明示的に管理することはありません。したがって、データベースでは、同時統計収集の間にシステム・リソースをすべて使用する場合があります。この状況に対処するには、Resource Managerを使用して同時統計収集ジョブで消費するリソースに上限を設けます。Resource Managerで同時統計収集を有効にしておく必要があります。

システムによって提供されるコンシューマ・グループであるORA$AUTOTASKには、すべての統計収集ジョブが登録されています。ORA$AUTOTASKに対して適切なリソースが割り当てられているリソース計画を作成して、同時統計収集で使用可能なリソースがすべて消費されることを回避できます。独自のリソース計画が存在せず、かつそれを作成しない場合は、システムによって提供されるDEFAULT_PLANを含むResource Managerのアクティブ化を検討してください。

注意:

ORA$AUTOTASKコンシューマ・グループは、メンテナンス・ウィンドウ中に自動実行されるメンテナンス・タスクと共有されます。したがって、自動統計収集で同時実行性がアクティブ化されている場合は、追加の手順を要することなく、データベースでリソースが自動管理されます。

関連項目:

Resource Managerの詳細は、『Oracle Database管理者ガイド』を参照してください。

同時統計収集の有効化

同時統計収集を有効化するには、DBMS_STATS.SET_GLOBAL_PREFSプロシージャを使用してCONCURRENTプリファレンスを設定します。

次の値があります。

- MANUAL
手動統計収集でのみ、同時実行性が有効化されます。

- AUTOMATIC
自動統計収集でのみ、同時実行性が有効化されます。

- ALL
手動と自動の両方の統計収集で、同時実行性が有効化されます。

- OFF
手動と自動の両方の統計収集で、同時実行性が無効化されます。これはデフォルト値です。

この項のこのチュートリアルでは、同時統計収集を有効化する方法について説明します。

前提条件

このチュートリアルの前提条件は、次のとおりです。

- 統計収集の標準的な権限に加えて、次の権限を所有している必要があります。

- CREATE JOB

- MANAGE SCHEDULER

- MANAGE ANY QUEUE

- SYSAUX表領域をオンラインにする必要があるのは、スケジューラでその内部表とビューをこの表領域に格納するためです。

- JOB_QUEUE_PROCESSES初期化パラメータを少なくとも4に設定する必要があります。

- Resource Managerを有効化する必要があります。
デフォルトでは、Resource Managerは無効になっています。リソース計画がない場合は、システムによって提供されるDEFAULT_PLANを含むResource Managerの有効化を検討してください。

前提条件

このチュートリアルでは、次の操作を行うものとします。

- 同時統計収集の有効化

- shスキーマの統計の収集

- sh統計の収集の監視

同時統計収集を有効化する手順は次のとおりです。

1. 適切な権限でSQL*Plusをデータベースに接続し、Resource Managerを有効化します。
次の例では、Resource Managerのデフォルトの計画が使用されています。

ALTER SYSTEM SET RESOURCE_MANAGER_PLAN = 'DEFAULT_PLAN';

2. JOB_QUEUE_PROCESSES初期化パラメータをCPUのコア数の少なくとも2倍に設定します。
Oracle Real Application Clustersでは、JOB_QUEUE_PROCESSES設定が各ノードに適用されます。

システムに4個のCPUコアがあると想定します。次の例では、パラメータを8(コア数の2倍)に設定します。

ALTER SYSTEM SET JOB_QUEUE_PROCESSES=8;

3. パラメータの変更が有効になったことを確認します。
たとえば、SQL*Plusに次のコマンドを入力します(出力例も示します)。

SHOW PARAMETER PROCESSES;

NAME                             TYPE        VALUE
-------------------------------- ----------- -----
_high_priority_processes         string      VKTM
aq_tm_processes                  integer     1
db_writer_processes              integer     1
gcs_server_processes             integer     0
global_txn_processes             integer     1
job_queue_processes              integer     8
log_archive_max_processes        integer     4
processes                        integer     100

4. 同時統計を有効化します。
たとえば、次のPL/SQL無名ブロックを実行します。

BEGIN
DBMS_STATS.SET_GLOBAL_PREFS('CONCURRENT','ALL');
END;
/

5. 統計が有効化されたことを確認します。
たとえば、次の問合せを実行します(出力例も示します)。

SELECT DBMS_STATS.GET_PREFS('CONCURRENT') FROM DUAL;

DBMS_STATS.GET_PREFS('CONCURRENT')
----------------------------------
ALL

6. SHスキーマの統計を収集します。
たとえば、次のプロシージャを実行します。

EXEC DBMS_STATS.GATHER_SCHEMA_STATS('SH');

7. 別のセッションでは、DBA_OPTSTAT_OPERATION_TASKSを問い合せることでジョブの進行状況を監視します。
たとえば、次の問合せを実行します(出力例も示します)。

SET LINESIZE 1000

COLUMN TARGET FORMAT a8
COLUMN TARGET_TYPE FORMAT a25
COLUMN JOB_NAME FORMAT a14
COLUMN START_TIME FORMAT a40

SELECT TARGET, TARGET_TYPE, JOB_NAME,
TO_CHAR(START_TIME, 'dd-mon-yyyy hh24:mi:ss')
FROM   DBA_OPTSTAT_OPERATION_TASKS
WHERE  STATUS = 'IN PROGRESS'
AND    OPID = (SELECT MAX(ID)
FROM   DBA_OPTSTAT_OPERATIONS
WHERE  OPERATION = 'gather_schema_stats');

TARGET    TARGET_TYPE               JOB_NAME       TO_CHAR(START_TIME,'
--------- ------------------------- -------------- --------------------
SH.SALES  TABLE (GLOBAL STATS ONLY) ST$T292_1_B29  30-nov-2012 14:22:47
SH.SALES  TABLE (COORDINATOR JOB)   ST$SD290_1_B10 30-nov-2012 14:22:08

8. 元のセッションでは、同時統計収集を無効化します。
たとえば、次の問合せを実行します。

EXEC DBMS_STATS.SET_GLOBAL_PREFS('CONCURRENT','OFF');

関連項目:

- 「統計収集操作の監視」

- Oracle Database管理者ガイド

- DBMS_STATS.SET_GLOBAL_PREFSプロシージャの使用方法の詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

パラレル実行および同時統計収集のためのシステムの構成

同時統計収集を有効化すると、各統計収集ジョブをパラレルで実行できます。この組合せは、大きな表、パーティションまたはサブパーティションの分析に役立ちます。このトピックでは、推奨される構成について説明します。

パラレル実行および同時統計収集のためのシステムを構成する手順は次のとおりです。

1. 管理者権限でSQL*Plusをデータベースに接続します。

2. パラレル適応マルチユーザー初期化パラメータを無効化します。
たとえば、次のSQL文を使用します。

ALTER SYSTEM SET PARALLEL_ADAPTIVE_MULTI_USER=false;

3. パラレル・キューイングが有効になっているリソース・プランを使用するようにデータベースを構成します。
次の手順を実行します。

a. Oracle Database Resource Manager(Resource Manager)がアクティブ化されていない場合は、アクティブ化します。デフォルトでは、Resource Managerはメンテナンス・ウィンドウ中にのみアクティブ化されます。

b. コンシューマ・グループOTHER_GROUPSのキューイングが有効になっている一時リソース・プランを作成します。

次のサンプル・スクリプトでは、一時リソース・プラン(pqq_test)の作成方法の1つが示されており、このプランを使用してResource Managerを有効化します。

BEGIN
DBMS_RESOURCE_MANAGER.CREATE_PENDING_AREA();
DBMS_RESOURCE_MANAGER.CREATE_PLAN('pqq_test', 'pqq_test');
DBMS_RESOURCE_MANAGER.CREATE_PLAN_DIRECTIVE(
'pqq_test'
,   'OTHER_GROUPS'
,   'OTHER_GROUPS directive for pqq'
,   parallel_server_limit            => 90
,   max_utilization_limit            => 90
);
DBMS_RESOURCE_MANAGER.SUBMIT_PENDING_AREA();
END;
/
ALTER SYSTEM SET RESOURCE_MANAGER_PLAN = 'pqq_test' SID='*';

関連項目:

- Resource Managerを使用したリソースの管理方法の詳細は、『Oracle Database管理者ガイド』を参照してください

- PARALLEL_ADAPTIVE_MULTI_USER初期化パラメータの詳細は、『Oracle Databaseリファレンス』を参照してください

統計収集操作の監視

データ・ディクショナリ・ビューを使用して、統計収集ジョブを監視できます。

次のビューが関連します。

- DBA_OPTSTAT_OPERATION_TASKS
このビューには、統計収集操作の一部として実行されるまたは現在実行されているタスクの履歴が含まれています(DBA_OPTSTAT_OPERATIONSに記録されます)。各タスクは、親操作に対応して処理されるターゲット・オブジェクトを示します。

- DBA_OPTSTAT_OPERATIONS
このビューには、DBMS_STATSパッケージを使用して表、スキーマおよびデータベース・レベルで実行されるまたは現在実行されている統計操作の履歴が含まれています。

前述のビューのTARGET列には、統計収集ジョブのターゲット・オブジェクトが次の形式で表示されます。

OWNER.TABLE_NAME.PARTITION_OR_SUBPARTITION_NAME

統計収集ジョブの名前はすべて文字列のST$で開始されます。

現在実行されている統計タスクおよびジョブを表示する手順は次のとおりです。

- 現在実行されている統計収集タスクをすべてのユーザー・セッションからリストするには、次のSQL文を使用します(出力例も示します)。

SELECT OPID, TARGET, JOB_NAnME,
(SYSTIMESTAMP - START_TIME) AS elapsed_time
FROM   DBA_OPTSTAT_OPERATION_TASKS
WHERE  STATUS = 'IN PROGRESS';

OPID TARGET                    JOB_NAME      ELAPSED_TIME
---- ------------------------- ------------- --------------------------
981 SH.SALES.SALES_Q4_1998    ST$T82_1_B29  +000000000 00:00:00.596321
981 SH.SALES                  ST$SD80_1_B10 +000000000 00:00:27.972033

完了した統計タスクおよびジョブを表示する手順は次のとおりです。

- 特定の操作の完了したタスクおよびジョブのみをリストするには、まず統計収集操作の名前、ターゲットおよび開始時刻に基づいてDBA_OPTSTAT_OPERATIONSビューで操作IDを特定します。操作IDを特定したら、DBA_OPTSTAT_OPERATION_TASKSビューを問い合せて、その操作で対応するタスクを検索します。
たとえば、ID 981の操作をリストするには、SQL*Plusで次のコマンドを使用します(出力例も示します)。

VARIABLE id NUMBER
EXEC :id := 981

SELECT TARGET, JOB_NAME, (END_TIME - START_TIME) AS ELAPSED_TIME
FROM   DBA_OPTSTAT_OPERATION_TASKS
WHERE  STATUS <> 'IN PROGRESS'
AND    OPID = :id;

TARGET                    JOB_NAME      ELAPSED_TIME
------------------------- ------------- --------------------------
SH.SALES_TRANSACTIONS_EXT               +000000000 00:00:45.479233
SH.CAL_MONTH_SALES_MV     ST$SD88_1_B10 +000000000 00:00:45.382764
SH.CHANNELS               ST$SD88_1_B10 +000000000 00:00:45.307397

失敗した統計収集タスクおよびジョブを表示する手順は次のとおりです。

- 次のSQL文を使用します(出力例の一部も示します)。

SET LONG 10000

SELECT TARGET, JOB_NAME,
(END_TIME - START_TIME) AS ELAPSED_TIME, NOTES
FROM   DBA_OPTSTAT_OPERATION_TASKS
WHERE  STATUS = 'FAILED';

TARGET             JOB_NAME ELAPSED_TIME               NOTES
------------------ -------- -------------------------- ----------------------
SYS.OPATCH_XML_INV          +000000007 02:36:31.130314 <error>ORA-20011:
Approximate NDV failed:
ORA-29913: error in
.
.
.

関連項目:

DBA_SCHEDULER_JOBSビューの詳細は、『Oracle Databaseリファレンス』を参照してください

パーティション・オブジェクトの増分統計の収集

増分統計では、変更されたパーティションのみがスキャンされます。パーティション・レベルの統計からグローバル統計を導出して大規模パーティション表の統計を収集する場合、増分統計メンテナンスによってパフォーマンスが向上します。

この項の内容は次のとおりです。

- 増分統計の目的

- DBMS_STATSによるパーティション表のグローバル統計の導出方法

- 増分統計メンテナンスの考慮事項

- パーティション・メンテナンス操作の増分統計の維持

- 失効したまたはロックされたパーティション統計のある表の増分統計の維持

増分統計の目的

一般的な例では、アプリケーションによってレンジ・パーティション表の新規パーティションにデータがロードされます。アプリケーションで新しいパーティションの追加とデータのロードが行われると、データベースでは、新しいパーティションの統計を収集し、グローバル統計を最新の状態に維持することが必要になります。

通常、データ・ウェアハウス・アプリケーションは、大規模パーティション表にアクセスします。多くの場合、これらの表は日付列でパーティション化され、頻繁なDML変更の影響を受けるのは最近のパーティションのみです。増分統計を使用しない場合、通常は、統計収集で次の2段階アプローチが使用されます。

1. データベースで表をスキャンしてグローバル統計を収集する。
グローバル統計収集のための全表スキャンでは、表のサイズによっては非常に負荷がかかる可能性があります。表にパーティションが追加されるに従い、GATHER_TABLE_STATSの実行時間が長くなります。これは、グローバル統計には全表スキャンが必要になるためです。パーティションの小規模なサブセットのみを変更する場合でも、データベースで表全体のスキャンを実行する必要があります。

2. データベースで変更されたパーティションをスキャンしてパーティション・レベルの統計を収集する。

増分メンテナンスでは、次のためにデータ・ウェアハウス・アプリケーションに大きなパフォーマンス上の利点があります。

- データベースでは、表を1回のみスキャンしてパーティション統計を収集し、パーティション・レベルの統計を集計することによりグローバル統計を導出する必要があります。これにより、データベースは、増分統計を使用しない場合に必要な2つの全スキャン(パーティション・レベルの統計のスキャンとグローバル・レベルの統計のスキャン)を回避します。

- 後続の統計収集で、データベースは、失効したパーティションのスキャンと統計(シノプシスを含む)の更新のみが必要です。データベースは、新しいパーティション統計からグローバル統計を導出できるため、全表スキャンが不要です。

増分統計を使用する場合、データベースは、グローバルまたは表レベルの統計を変更するパーティションで引き続き統計を収集する必要があります。増分統計メンテナンスは、最初からの表統計の収集と同じ統計が得られますが、パフォーマンスが向上します。

DBMS_STATSによるパーティション表のグローバル統計の導出方法

増分統計メンテナンスが有効な場合、DBMS_STATSでは、変更されたパーティションのみの統計を収集し、シノプシスを作成します。また、データベースは、パーティション・レベルのシノプシスをグローバル・シノプシスに自動的にマージし、パーティション・レベルの統計およびグローバル・シノプシスからグローバル統計を導出します。

データベースでパーティション・レベルの統計からグローバル統計を導出して計算する際に全表スキャンが回避されます。たとえば、グローバル・レベルの行数はパーティションの行数の合計です。グローバル・ヒストグラムもパーティションのヒストグラムから導出できます。

ただし、列の NDVなど、パーティション・レベルの統計からすべての統計を導出することはできません。次の例は、表の2つのパーティションのNDVを示しています。

表12-2 4つのパーティションのNDV

オブジェクト

列値

NDV

Partition 1

1,3,3,4,5

4

Partition 2

2,3,4,5,6

5

個々のパーティションのNDVを加算して表のNDVを計算するとNDVは9となりますが、これは正しくありません。したがって、より正確な手法のシノプシスが必要です。

増分統計メンテナンスの考慮事項

増分統計は、データベースが表および索引統計を収集および格納する方法に影響します。

最も重要な結果は次のとおりです。

- SYSAUX表領域では、パーティション表のグローバル統計を維持するために追加の領域が使用されます。

- 表がコンポジット・パーティションを使用する場合は、データベースは変更されたサブパーティションの統計のみを収集します。データベースは、未変更のサブパーティションに対しては、サブパーティション・レベルの統計を収集しません。このようにして、データベースは未変更のパーティションをスキップして作業を減らします。

- 表が増分統計を使用しており、この表にローカルでパーティション化された索引がある場合は、データベースは、変更された索引パーティションに対してグローバル・レベルで索引統計を収集します。データベースは、パーティション・レベルの統計からグローバル索引統計を生成することはしません。そのかわりに、データベースは全索引スキャンを実行してグローバル索引統計を収集します。

関連項目:

DBMS_STATSパッケージの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください

パーティション・メンテナンス操作の増分統計の維持

パーティション・メンテナンス操作は、表パーティションの追加、交換、マージ、分割など、パーティション関連の操作です。

Oracle Databaseにより、増分統計メンテナンスの次のサポートが提供されます。

- パーティション・メンテナンス操作により統計の収集がトリガーされた場合、データベースでは、以前は古いセグメントで削除されていたシノプシスを再利用できるようになりました。

- DBMS_STATSによって非パーティション表にシノプシスを作成できるようになりました。シノプシスによって、データベースでは増分統計をパーティション交換操作の一部として維持できます。パーティション交換後にパーティションの統計を明示的に収集する必要はありません。

表でDBMS_STATSプリファレンスのINCREMENTALをtrueに設定した場合は、INCREMENTAL_LEVELプリファレンスによって、どのシノプシスをいつ収集するのかが制御されます。このプリファレンスの値は、次のいずれかです。

- TABLE
DBMS_STATSによって当該の表にある表レベルのシノプシスが収集されます。INCREMENTAL_LEVELに設定できるのは、表レベルのTABLEのみです。スキーマ、データベースまたはグローバル・レベルには設定できません。

- PARTITION(デフォルト)
DBMS_STATSによってパーティション表のパーティション・レベルのシノプシスのみが収集されます。

パーティション交換の実行時に、交換対象のパーティションを交換した後でシノプシスを使用する場合は、パーティションと交換する表でINCREMENTALをtrueに、INCREMENTAL_LEVELをTABLEに設定することをお薦めします。

前提条件

このチュートリアルでは、次のことが前提となっています。

- 空のパーティションp_sales_01_2010をsales表にロードします。

- ステージング表t_sales_01_2010を作成し、その表に値を移入します。

- データベースで、増分統計をパーティション交換操作の一部として維持します。パーティション交換後にパーティションの統計を明示的に収集する必要はありません。

増分統計をパーティション交換操作の一部として維持する手順は次のとおりです。

1. ステージング表t_sales_01_2010に対する増分統計のプリファレンスを設定します。
たとえば、次の文を実行します。

BEGIN
DBMS_STATS.SET_TABLE_PREFS (
ownname  =>  'sh'
,     tabname  =>  't_sales_01_2010'
,     pname    =>  'INCREMENTAL'
,     pvalue   =>  'true'
);
DBMS_STATS.SET_TABLE_PREFS (
ownname  =>  'sh'
,     tabname  =>  't_sales_01_2010'
,     pname    =>  'INCREMENTAL_LEVEL'
,     pvalue   =>  'table'
);
END;

2. ステージング表t_sales_01_2010の統計を収集します。
たとえば、次のPL/SQLコードを実行します。

BEGIN
DBMS_STATS.GATHER_TABLE_STATS (
ownname  => 'SH'
,     tabname  => 'T_SALES_01_2010'
);
END;
/

DBMS_STATSによってt_sales_01_2010の表レベルのシノプシスが収集されます。

3. sh.sales表でINCREMENTALプリファレンスがtrueになるようにします。
たとえば、次のPL/SQLコードを実行します。

BEGIN
DBMS_STATS.SET_TABLE_PREFS (
ownname  =>  'sh'
,     tabname  =>  'sales'
,     pname    =>  'INCREMENTAL'
,     pvalue   =>  'true'
);
END;
/

4. INCREMENTALをtrueに設定する前にsh.salesの統計を収集していない場合は、交換するパーティションの統計を収集します。
たとえば、次のPL/SQLコードを実行します。

BEGIN
DBMS_STATS.GATHER_TABLE_STATS (
ownname  =>  'sh'
,     tabname  =>  'sales'
,     pname    =>  'p_sales_01_2010'
,     pvalue   =>  granularity=>'partition'
);
END;
/

5. パーティション交換を実行します。
たとえば、次のSQL文を使用します。

ALTER TABLE sales EXCHANGE PARTITION p_sales_01_2010 WITH TABLE t_sales_01_2010;

交換後は、パーティション化された表に、パーティションp_sales_01_2010の統計とシノプシスの両方が存在するようになります。

Oracle Database 12cより前のリリースでは、前述の文によってp_sales_01_2010とt_sales_01_2010のセグメント・データおよび統計を入れ替えていました。データベースでは、t_sales_01_2010などのパーティション化されていない表のシノプシスを維持していませんでした。パーティション化された表のグローバル統計を収集するには、p_sales_01_2010のパーティションを再スキャンしてそのシノプシスを取得する必要がありました。

関連項目:

DBMS_STATS.SET_TABLE_PREFSの詳細は、Oracle Database PL/SQLパッケージおよびタイプ・リファレンスを参照してください

失効したまたはロックされたパーティション統計のある表の増分統計の維持

Oracle Database 12cから、たとえパーティションまたはサブパーティションの統計が失効したりロックされても、パーティション化された表のグローバル統計を増分統計によって自動計算できるようになりました。

Oracle Database 12cより前のリリースで増分統計が有効化されている場合は、パーティションでDMLが実行されると、オプティマイザは、そのパーティションの統計が失効したと判断します。したがって、グローバル統計を正確に集計するには、DBMS_STATSで再び統計を収集する必要があります。さらに、統計がロックされたパーティションでDMLが実行される場合は、DBMS_STATSでそのパーティションの統計を再収集できないため、全表スキャンのみがグローバル統計を収集する手段となります。統計の再収集では、パフォーマンスにオーバーヘッドが生じます。

Oracle Database 12cでは、パーティションまたはサブパーティションの統計が失効しているかどうかを判別する方法が、統計プリファレンスのINCREMENTAL_STALENESSで制御されます。このプリファレンスの値は、次のいずれかです。

- USE_STALE_PERCENT
DMLの変更が表に対して指定したSTALE_PERCENTプリファレンスを下回る場合はパーティションまたはサブパーティションが失効しているとはみなされません。STALE_PERCENTのデフォルト値は10です。これはDMLによって10%を超える行で変更が生じると、その表が失効しているとみなされることを意味します。

- USE_LOCKED_STATS
ロックされたパーティションまたはサブパーティションの統計は、DMLの変更にかかわらず、失効しているとみなされることはありません。

- NULL(デフォルト)
DMLに変更が生じた場合は、パーティションまたはサブパーティションが失効しているとみなされます。この動作はOracle Database 11gの動作と同じです。デフォルト値を使用する場合、増分モードで収集される統計は非増分モードで収集される統計と同じであることが保証されます。デフォルト値以外が使用されると、増分モードで収集された統計は、非増分モードで収集された統計よりも精度が低くなる可能性があります。

USE_STALE_PERCENTとUSE_LOCKED_STATSは合わせて指定できます。たとえば、次のような無名ブロックを記述できます。

BEGIN
DBMS_STATS.SET_TABLE_PREFS (
ownname     => null
,   table_name  => 't'
,   pname       => 'incremental_staleness'
,   pvalue      => 'use_stale_percent,use_locked_stats'
);
END;

前提条件

このチュートリアルでは、次のことが前提となっています。

- パーティション化された表のSTALE_PERCENTが10に設定されています。

- INCREMENTAL値はtrueに設定されています。

- 表には、以前にINCREMENTALモードで収集された統計があります。

- INCREMENTAL_STALENESSの設定や統計のロックの有無、DMLの変更割合に応じて統計収集がどのように変化するのかを確認します。

失効したまたはロックされたパーティション統計のある表をテストする手順は次のとおりです。

1. INCREMENTAL_STALENESSをNULLに設定します。
その後、DMLアクティビティのため、1つのパーティションの5%の行が変更されます。

2. DBMS_STATSを使用して表の統計を収集します。
DBMS_STATSによって、5%のDMLアクティビティが含まれたパーティションの統計が再収集され、グローバル統計が増分的に維持されます。

3. INCREMENTAL_STALENESSをUSE_STALE_PERCENTに設定します。
その後、DMLアクティビティのため、1つのパーティションの5%の行が変更されます。

4. DBMS_STATSを使用して表の統計を収集します。
DBMS_STATSによって、DMLアクティビティが含まれていたパーティションの統計が再収集されることはなく(変更が10%の失効のしきい値を下回るため)、グローバル統計が増分的に維持されます。

5. パーティション統計をロックします。
その後、DMLアクティビティのため、1つのパーティションの20%の行が変更されます。

6. DBMS_STATSを使用して表の統計を収集します。
統計がロックされているため、DBMS_STATSによってパーティションの統計が再収集されることはありません。データベースでは、全表スキャンを使用してグローバル統計が収集されます。

その後、DMLアクティビティのため、1つのパーティションの5%の行が変更されます。

7. DBMS_STATSを使用して表の統計を収集します。
この表の統計が収集される場合は、統計が失効しているとみなされないため、DBMS_STATSではパーティションの統計が再収集されません。データベースでは、このパーティションの既存の統計を使用してグローバル統計が増分的に維持されます。

8. INCREMENTAL_STALENESSをUSE_LOCKED_STATSおよびUSE_STALE_PERCENTに設定します。
その後、DMLアクティビティのため、1つのパーティションの20%の行が変更されます。

9. DBMS_STATSを使用して表の統計を収集します。
USE_LOCKED_STATSが設定されているため、DBMS_STATSは、統計が失効している状態を無視し、ロックされた統計を使用します。データベースでは、このパーティションの既存の統計を使用してグローバル統計が増分的に維持されます。

関連項目:

DBMS_STATS.SET_TABLE_PREFSの詳細は、Oracle Database PL/SQLパッケージおよびタイプ・リファレンスを参照してください

システム統計の手動収集

システム統計は、オプティマイザに対してシステムのハードウェア特性(I/OとCPUのパフォーマンスおよび使用率など)を記述します。システム統計によって、オプティマイザはより効率的な実行計画を選択できるようになります。CPUの高速化やメモリーの増設、ディスク・ストレージの交換など、環境に物理的な変化が生じた場合は、システム統計を収集することをお薦めします。

DBMS_STATSを使用したシステム統計の収集について

システム統計を収集するには、DBMS_STATS.GATHER_SYSTEM_STATSを使用します。データベースでシステム統計を収集する場合は、指定された期間のアクティビティを分析するか(作業負荷統計)、作業負荷をシミュレートします(非作業負荷統計)。DBMS_STATS.GATHER_SYSTEM_STATSへの入力引数には次があります。

- NOWORKLOAD
オプティマイザによって、作業負荷とは無関係に、システムの特性のみに基づいた統計が収集されます。

- INTERVAL
指定された時間(分)が経過すると、オプティマイザによって、データ・ディクショナリまたは代替の表のいずれか(stattabで指定)のシステム統計が更新されます。統計は、指定された時間間隔のシステム・アクティビティに基づきます。

- STARTおよびSTOP
STARTは統計収集を初期化します。STOPは、(START以降の)経過期間の統計を算出し、データ・ディクショナリまたは代替の表(stattabで指定)をリフレッシュします。オプティマイザではINTERVALは無視されます。

- EXADATA
システム統計では、大きなI/Oサイズや高いI/Oスループットなど、Exadataを使用することで提供されるすぐれた機能が考慮されます。オプティマイザでは、CPU速度に加えて、マルチブロック読取りカウントやI/Oスループットの統計が設定されます。

表12-5には、DBMS_STATSで収集されたオプティマイザのシステム統計のほか、特定のシステム統計を収集または手動設定するためのオプションが示されています。

表12-5 DBMS_STATパッケージ内のオプティマイザのシステム統計

パラメータ名

説明

初期化

統計の収集または設定のオプション

単位

cpuspeedNW

作業負荷のない場合のCPU速度を表します。CPU速度は、1秒当たりのCPU平均サイクル数です。

システム起動時

gathering_mode = NOWORKLOADに設定するか、または統計を手動で設定します。

100万/秒

ioseektim

ディスク・ヘッドがデータの読取り位置に移動する時間を表します。I/Oシーク時間は、シーク時間、待機時間およびオペレーティング・システム・オーバーヘッド時間を合計したものです。

システム起動時

10(デフォルト)

gathering_mode = NOWORKLOADに設定するか、または統計を手動で設定します。

ミリ秒

iotfrspeed

1回の読取りリクエストでOracleデータベースによるデータの読取りが可能な速度を表します。

システム起動時

4096(デフォルト)

gathering_mode = NOWORKLOADに設定するか、または統計を手動で設定します。

バイト/ミリ秒

cpuspeed

作業負荷をかけた場合のCPU速度を表します。CPU速度は、1秒当たりのCPU平均サイクル数です。

なし

gathering_mode = NOWORKLOAD、INTERVAL、START|STOPに設定するか、統計を手動で設定します。

100万/秒

maxthr

最大I/Oスループットは、I/Oサブシステムが発揮できる最大スループットです。

なし

gathering_mode = NOWORKLOAD、INTERVAL、START|STOPに設定するか、統計を手動で設定します。

バイト/秒

slavethr

スレーブI/Oスループットは、パラレル実行サーバーの平均I/Oスループットです。

なし

gathering_mode = INTERVALまたはSTART|STOPに設定するか、統計を手動で設定します。

バイト/秒

sreadtim

単一ブロック読取り時間は、単一ブロックをランダムに読み取る平均時間です。

なし

gathering_mode = INTERVALまたはSTART|STOPに設定するか、統計を手動で設定します。

ミリ秒

mreadtim

マルチブロック読取りは、マルチブロックを順に読み取る平均時間です。

なし

gathering_mode = INTERVALまたはSTART|STOPに設定するか、統計を手動で設定します。

ミリ秒

mbrc

マルチブロック・カウントは、平均マルチブロック順次読取りカウントです。

なし

gathering_mode = INTERVALまたはSTART|STOPに設定するか、統計を手動で設定します。

ブロック

関連項目:

システム統計を実装するためのDBMS_STATSパッケージのプロシージャの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

システム統計収集のガイドライン

データベースでは、起動時にシステム統計の基本的な要素が自動収集されます。CPUおよびI/Oの特性は、多くの場合、長期にわたって変わりません。通常、これらの特性は構成でなんらかの状態がアップグレードされた場合にのみ変更されます。このため、CPUの高速化やメモリーの増設、ディスク・ストレージの交換など、環境に物理的な変化が生じた場合にのみ、システム統計を収集することをお薦めします。

次のガイドラインに留意してください。

- 非作業負荷統計は、インスタンスの初回起動時にデフォルト値で初期化されます。他のどの表領域でも使用されていない記憶域に新しい表領域を作成した場合は、非作業負荷統計を収集することをお薦めします。

- システムの作業負荷が最も平均的なときの時間間隔で統計を取得することがベスト・プラクティスです。作業負荷統計の収集には、さらなるオーバーヘッドは発生しません。

作業負荷統計の収集

データベースの作業負荷が最も標準的なときに、DBMS_STATS.GATHER_SYSTEM_STATSを使用して統計を取得します。たとえば、データベースのアプリケーションで日中にOLTPトランザクションを処理し、夜間にOLAPレポートを生成できます。

作業負荷統計について

作業負荷統計では、指定した期間のアクティビティを分析します。

作業負荷統計には、表12-5にリストされている次の統計が含まれています。

- 単一ブロック(sreadtim)およびマルチブロック(mreadtim)の読取り時間

- マルチブロック・カウント(mbrc)

- CPU速度(cpuspeed)

- 最大システム・スループット(maxthr)

- パラレル実行の平均スループット(slavethr)

データベースでは、作業負荷の開始から終了までの間の、物理的な順次およびランダム読取りの数を比較して、sreadtim、mreadtimおよびmbrcを計算します。これらの値は、バッファ・キャッシュが同期読取りリクエストを完了したときに変更されるカウンタを通して実装されます。

このカウンタはバッファ・キャッシュ内にあるため、これらにはI/O遅延のほかに、ラッチの競合およびタスク・スイッチングに関連する待機も含まれます。したがって、作業負荷統計は、作業負荷ウィンドウ中のシステム・アクティビティに依存します。システムがI/Oバウンド(ラッチ競合およびI/Oスループットの両方)の場合は、データベースで統計を使用した後に、統計によってI/O集中を低減化する計画が促進されます。

図12-2に示すように、作業負荷統計を収集する場合には、オプティマイザでは、作業負荷統計のために収集されたmbrc値が使用されて、全表スキャンのコストが見積られます。

図12-2 作業負荷統計カウンタ

作業負荷統計を収集する際に、一連の作業負荷の間に表のスキャンが行われない(OLTPシステムではよく発生します)場合は、mbrc値およびmreadtim値がデータベースで収集されない可能性があります。しかし、全表スキャンはDSSシステムで頻繁に行われています。これらのスキャンは並列に実行され、バッファ・キャッシュを経由しない場合があります。このようなケースでは、索引検索でバッファ・キャッシュを使用するため、データベースでもsreadtimが収集されています。

mbrcまたはmreadtim値を収集できないか、または収集してもそれらを検証できない場合、sreadtimおよびcpuspeed値が収集されていると、sreadtimおよびcpuspeedのみがコスト計算に使用されます。この場合、オプティマイザは初期化パラメータDB_FILE_MULTIBLOCK_READ_COUNTの値を使用して全表スキャンを見積ることができます。ただし、DB_FILE_MULTIBLOCK_READ_COUNTが0であるか、設定されていない場合は、オプティマイザで値8を使用してコストを計算します。

作業負荷統計を収集するには、DBMS_STATS.GATHER_SYSTEM_STATSプロシージャを使用します。GATHER_SYSTEM_STATSプロシージャでは、経過した期間に応じた統計を使用してデータ・ディクショナリまたはステージング表をリフレッシュします。収集する期間を設定するには、次の手法のいずれかを使用します。

- 作業負荷ウィンドウの開始にSTART 指定し、作業負荷ウィンドウの終了にSTOPを指定します。

- 統計収集が自動的に停止する前に、INTERVALとその時間間隔(分単位)を指定します。必要な場合は、GATHER_SYSTEM_STATS (gathering_mode=>'STOP')を使用することでスケジュールよりも早く収集を終了できます。

関連項目:

DB_FILE_MULTIBLOCK_READ_COUNT初期化パラメータの詳細は、『Oracle Databaseリファレンス』を参照してください。

システム統計収集の開始および停止

このチュートリアルでは、GATHER_SYSTEM_STATSのSTARTパラメータとSTOPパラメータを使用した作業負荷の時間間隔を設定する方法について説明します。

前提条件

このチュートリアルでは、次のことが前提となっています。

- 10 a.m.と11 a.m.の間の時間が毎日の作業負荷の標準時間です。

- データ・ディクショナリにあるシステム統計を直接収集します。

STARTおよびSTOPを使用して作業負荷統計を収集する手順は次のとおりです。

1. SQL*Plusを起動し、管理者権限でデータベースに接続します。

2. 統計収集を開始します。
たとえば、10 a.m.に次のプロシージャを実行して収集を開始します。

EXECUTE DBMS_STATS.GATHER_SYSTEM_STATS( gathering_mode => 'START' );

3. 作業負荷を生成します。

4. 統計収集を終了します。
たとえば、11 a.m.に次のプロシージャを実行して収集を終了します。

EXECUTE DBMS_STATS.GATHER_SYSTEM_STATS( gathering_mode => 'STOP' );

ここで、オプティマイザでは、作業負荷統計を使用して、日々の通常の作業負荷の間に有効な実行計画を生成できるようになります。

5. オプションで、システム統計を問い合せます。
たとえば、次の問合せを実行します。

COL PNAME FORMAT a15
SELECT PNAME, PVAL1
FROM   SYS.AUX_STATS$
WHERE  SNAME = 'SYSSTATS_MAIN';

関連項目:

DBMS_STATS.GATHER_SYSTEM_STATSプロシージャの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

指定された間隔でのシステム統計の収集

このチュートリアルでは、GATHER_SYSTEM_STATSのINTERVALパラメータを使用した作業負荷の時間間隔を設定する方法について説明します。

前提条件

このチュートリアルでは、次のことが前提となっています。

- データベースのアプリケーションで日中にOLTPトランザクションを処理し、夜間にOLAPレポートを実行します。代表的な統計を収集するには、日中の2時間と夜間の2時間で収集します。

- workload_statsという名前の表に統計を格納します。

- 収集された統計間の切替えを行います。

INTERVALを使用して作業負荷統計を収集する手順は次のとおりです。

1. SQL*Plusを起動して、本番データベースに管理者dba1として接続します。

2. 本番統計を保持するための表を作成します。
たとえば、次のPL/SQLプログラムを実行して、ユーザー統計表workload_statsを作成します。

BEGIN
DBMS_STATS.CREATE_STAT_TABLE (
ownname  =>  'dba1'
,     stattab  =>  'workload_stats'
);
END;
/

3. JOB_QUEUE_PROCESSESが0でないことを確認して、DBMS_JOBジョブとOracle Schedulerジョブが実行されるようにします。

ALTER SYSTEM SET JOB_QUEUE_PROCESSES = 1;

4. 日中の間に統計を収集します。
たとえば、次のプログラムを使用して2時間分の統計を収集します。

BEGIN
DBMS_STATS.GATHER_SYSTEM_STATS (
interval  =>  120
,     stattab   => 'workload_stats'
,     statid    => 'OLTP'
);
END;
/

5. 夜の間に統計を収集します。
たとえば、次のプログラムを使用して2時間分の統計を収集します。

BEGIN
DBMS_STATS.GATHER_SYSTEM_STATS (
interval  =>  120
,     stattab   => 'workload_stats'
,     statid    => 'OLAP'
);
END;
/

6. 日中または夜に、適切な統計をデータ・ディクショナリにインポートします。
たとえば、日中に次のプログラムを使用して、ステージング表からディクショナリにOLTP統計をインポートできます。

BEGIN
DBMS_STATS.IMPORT_SYSTEM_STATS (
stattab  =>  'workload_stats'
,     statid   =>  'OLTP'
);
END;
/

たとえば、夜の間に次のプログラムを使用して、ステージング表からディクショナリにOLAP統計をインポートできます。

BEGIN
DBMS_STATS.IMPORT_SYSTEM_STATS (
stattab  =>  'workload_stats'
,     statid   =>  'OLAP'
);
END;
/

関連項目:

DBMS_STATS.GATHER_SYSTEM_STATSプロシージャの詳細は、Oracle Database PL/SQLパッケージおよびタイプ・リファレンスを参照してください

非作業負荷統計の収集

非作業負荷統計ではI/Oシステムの特性を取得します。デフォルトでは、Oracle Databaseで非作業負荷統計とCPUコスト・モデルが使用されます。非作業負荷統計の値は、インスタンスの初回起動時にデフォルトで初期化されます。また、DBMS_STATS.GATHER_SYSTEM_STATSプロシージャを使用して、非作業負荷統計を手動で収集できます。

非作業負荷統計には、表12-5にリストされている次のシステム統計が含まれています。

- I/O転送速度(iotfrspeed)

- I/Oシーク時間(ioseektim)

- CPU速度(cpuspeednw)

作業負荷統計と非作業負荷統計の主な違いは、収集方法にあります。非作業負荷統計ではすべてのデータ・ファイルに対してランダムな読取りを実行してデータを収集する一方で、作業負荷統計ではデータベース・アクティビティが発生した際に更新されるカウンタを使用します。作業負荷統計を収集する場合には、Oracle Databaseでは非作業負荷統計ではなく作業負荷統計が使用されます。

非作業負荷統計を収集するには、引数を含まないか、収集モードをnoworkloadに設定した状態でDBMS_STATS.GATHER_SYSTEM_STATSを実行します。非作業負荷統計の収集プロセスの際に、I/Oシステムにオーバーヘッドが発生します。この収集プロセスは、I/Oのパフォーマンスおよびデータベースのサイズによって数秒から数分かかることがあります。

非作業負荷統計を収集した場合は、データベースでその情報が分析され、その整合性が検証されます。場合によっては、非作業負荷統計の値がデフォルト値のままになることがあります。再び統計を収集するか、またはSET_SYSTEM_STATSを使用してその値をI/Oシステムの仕様に手動設定するかのいずれが可能です。

前提条件

このチュートリアルでは、非作業負荷統計を手動で収集するものとします。

非作業負荷統計を手動収集する手順は次のとおりです。

1. SQL*Plusを起動し、管理者権限でデータベースに接続します。

2. 非作業負荷統計を収集します。
たとえば、次の文を実行します。

BEGIN
DBMS_STATS.GATHER_SYSTEM_STATS (
gathering_mode => 'NOWORKLOAD'
);
END;

3. オプションで、システム統計を問い合せます。
たとえば、次の問合せを実行します。

COL PNAME FORMAT a15

SELECT PNAME, PVAL1
FROM   SYS.AUX_STATS$
WHERE  SNAME = 'SYSSTATS_MAIN';

関連項目:

DBMS_STATS.GATHER_SYSTEM_STATSプロシージャの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

システム統計の削除

DBMS_STATS.DELETE_SYSTEM_STATSファンクションを使用してシステム統計を削除します。このプロシージャではINTERVALまたはSTARTおよびSTOPの各オプションを使用して収集された作業負荷統計が削除され、デフォルト値が非作業負荷統計にリセットされます。ただし、stattabパラメータで統計を格納する表が指定されている場合は、サブプログラムによって、関連するstatidを持つすべてのシステム統計が統計表から削除されます。

前提条件

このチュートリアルでは、次のことが前提となっています。

- 特定の集中型の作業負荷の統計を収集しましたが、オプティマイザでそれらの統計が使用されないようにします。

- ユーザーが指定した表ではなく、デフォルトの場所に作業負荷統計が格納されています。

システム統計を削除する手順は次のとおりです。

1. SQL*Plusを起動して、管理権限を持つユーザーとしてデータベースに接続します。

2. システム統計を削除します。
たとえば、次の文を実行します。

EXEC DBMS_STATS.DELETE_SYSTEM_STATS;

関連項目:

DBMS_STATS.DELETE_SYSTEM_STATSプロシージャの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

13 オプティマイザ統計の管理: 高度なトピック

この章では、拡張統計など、オプティマイザ統計の管理に関連する概念およびタスクの詳細について説明します。

この章の内容は次のとおりです。

- 動的統計の制御

- 保留中のオプティマイザ統計の公開

- 拡張統計の管理

- オプティマイザ統計のロックおよびロック解除

- オプティマイザ統計のリストア

- オプティマイザ統計の保存の管理

- オプティマイザ統計のインポートとエクスポート

- レポート作成モードでの統計収集関数の実行

- 過去の統計収集操作のレポート作成

- SQL計画ディレクティブの管理

関連項目:

「オプティマイザ統計の管理: 基本的なトピック」

動的統計の制御

デフォルトでは、オプティマイザ統計が存在しないか、失効したか、不十分な場合に、動的統計によって、解析の間に再帰的SQLが自動実行されて、表ブロックの小さなランダム・サンプルがスキャンされます。

この項の内容は次のとおりです。

- 動的統計レベルについて

- 動的統計レベルの手動設定

- 動的統計の無効化

関連項目:

「補足的な動的統計」

動的統計レベルについて

動的統計レベルでは、データベースで動的統計を収集するタイミングと、統計の収集にオプティマイザが使用するサンプル・サイズの両方が制御されます。

動的統計レベルを設定するには、OPTIMIZER_DYNAMIC_SAMPLING初期化パラメータまたは文ヒントのいずれかを使用します。

注意:

Oracle Database 12c リリース1 (12.1)より前のリリースでは、動的統計は動的サンプリングと呼ばれていました。

次の表は、動的統計のレベルについて説明しています。次の点に注意してください。

- 動的統計が無効化されていない場合、SQL文でパラレル実行が使用されていると、データベースによって動的統計を使用することが選択されることがあります。

- OPTIMIZER_ADAPTIVE_FEATURES初期化パラメータがtrueで、かつ、関連するSQL計画ディレクティブが存在する場合は、オプティマイザによって動的統計が使用されます。結果の統計は、他の問合せで使用できるように、データベースによってサーバーの結果キャッシュに保持されます。

表13-1 動的統計レベル

レベル

オプティマイザで動的統計を使用するタイミング

サンプル・サイズ(ブロック)

0

動的統計を使用しません。

該当なし

1

次の基準を満たす場合のみ、統計を含まないすべての表に動的統計を使用します。

- 問合せに含まれる1つ以上の表が、パーティション化されず、かつ統計がない場合。

- この表に索引がない場合。

- この表の動的統計で使用されるブロック数よりこの表のブロック数が多くある場合。

32

2

文の少なくとも1つの表に統計がない場合は、動的統計を使用します。これはデフォルト値です。

64

3

次のいずれかの条件に当てはまる場合は、動的統計を使用します。

- 文に含まれる1つ以上の表に統計がない場合。

- WHERE SUBSTR(CUSTLASTNAME,1,3)など、WHERE句の述語で使用される1つ以上の式が文にある場合。

64

4

次のいずれかの条件に当てはまる場合は、動的統計を使用します。

- 文に含まれる1つ以上の表に統計がない場合。

- WHERE SUBSTR(CUSTLASTNAME,1,3)など、WHERE句の述語で使用される1つ以上の式が文にある場合。

- 文が複雑な述語を使用している(同じ表で複数の述語をORまたはAND演算子でつないでいる)場合。

64

5

基準はレベル4と同じですが、異なるサンプル・サイズがデータベースによって使用されます。

128

6

基準はレベル4と同じですが、異なるサンプル・サイズがデータベースによって使用されます。

256

7

基準はレベル4と同じですが、異なるサンプル・サイズがデータベースによって使用されます。

512

8

基準はレベル4と同じですが、異なるサンプル・サイズがデータベースによって使用されます。

1024

9

基準はレベル4と同じですが、異なるサンプル・サイズがデータベースによって使用されます。

4086

10

基準はレベル4と同じですが、異なるサンプル・サイズがデータベースによって使用されます。

すべてのブロック

11

オプティマイザによって必要と判断された場合は、自動的に適応動的サンプリングが使用されます。

自動的に決定

関連項目:

- 「データベースがデータをサンプリングする場合」

- OPTIMIZER_DYNAMIC_SAMPLING初期化パラメータの詳細は、『Oracle Databaseリファレンス』を参照してください。

動的統計レベルの手動設定

すべてのSQL文に利点のある、データベースレベルの設定を決定することは容易ではありません。動的統計のレベルを設定する場合は、OPTIMIZER_DYNAMIC_SAMPLING初期化パラメータをセッション・レベルで設定することをお薦めします。

前提条件

このチュートリアルでは、次のことが前提となっています。

- 次の問合せに対して選択性の見積りを修正する場合で、2つの相関列にWHERE句の述語があります。

SELECT *
FROM   sh.customers
WHERE  cust_city='Los Angeles'
AND    cust_state_province='CA';

- 前述の問合せはシリアル処理を使用します。

- sh.customers表は、問合せの条件を満たす932の行を含みます。

- sh.customers表に収集された統計があります。

- cust_city列とcust_state_province列に索引を作成しています。

- OPTIMIZER_DYNAMIC_SAMPLING初期化パラメータが、デフォルト・レベルの2に設定されています。

動的統計レベルを手動設定する手順は次のとおりです。

1. 適切な権限でSQL*Plusをデータベースに接続し、実行計画を次のようにEXPLAINします。

EXPLAIN PLAN FOR
SELECT *
FROM   sh.customers
WHERE  cust_city='Los Angeles'
AND    cust_state_province='CA';

2. その計画を次のように問い合せます。

SET LINESIZE 130
SET PAGESIZE 0
SELECT *
FROM   TABLE(DBMS_XPLAN.DISPLAY);

出力が次のように表示されます(この例はページに収まるように再フォーマットされています)。

-------------------------------------------------------------------------------
|Id| Operation                   | Name             |Rows|Bytes|Cost | Time   |
-------------------------------------------------------------------------------
| 0| SELECT STATEMENT            |                   | 53| 9593|53(0)|00:00:01|
| 1|  TABLE ACCESS BY INDEX ROWID|CUSTOMERS          | 53| 9593|53(0)|00:00:01|
|*2|   INDEX RANGE SCAN          |CUST_CITY_STATE_IND| 53| 9593| 3(0)|00:00:01|
-------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

2 - access("CUST_CITY"='Los Angeles' AND "CUST_STATE_PROVINCE"='CA')

WHERE句の列には実世界の相関関係がありますが、オプティマイザはロサンゼルスがカリフォルニアにあることを認識せず、両方の述語により、戻される行の数が減少すると想定しています。このように、表には条件を満たす932の行が含まれますが、太字で示すようにオプティマイザは53と見積っています。

データベースでこの計画に動的統計を使用したとすれば、計画出力のNoteセクションでこの事実が指摘されることになります。オプティマイザで動的統計が使用されなかった理由は、文がシリアルに実行されたことや、標準統計が存在することのほか、OPTIMIZER_DYNAMIC_SAMPLINGパラメータがデフォルトの2に設定されていることがあげられます。

3. 次の文を使用して、セッションで動的統計レベルを4に設定します。

ALTER SESSION SET OPTIMIZER_DYNAMIC_SAMPLING=4;

4. この計画を再び次のようにEXPLAINします。

EXPLAIN PLAN FOR
SELECT *
FROM   sh.customers
WHERE  cust_city='Los Angeles'
AND    cust_state_province='CA';

この新しい計画では、太字で示されている値932のように、行数の見積りがより正確に示されています。

PLAN_TABLE_OUTPUT
---------------------------------------------------------------------------
Plan hash value: 2008213504

---------------------------------------------------------------------------
| Id  | Operation         | Name      |Rows | Bytes |Cost (%CPU)|Time     |
---------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |           | 932 |   271K|   406 (1)| 00:00:05 |
|*  1 |  TABLE ACCESS FULL| CUSTOMERS | 932 |   271K|   406 (1)| 00:00:05 |
---------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

1 - filter("CUST_CITY"='Los Angeles' AND "CUST_STATE_PROVINCE"='CA')

Note
-----
- dynamic statistics used for this statement (level=4)

計画の一番下のメモは、サンプリング・レベルが4であることを示します。追加された動的統計によって、オプティマイザにcust_city列とcust_state_province列間の実世界の関係を認識させることで、行数が53ではなく932という、より正確な見積りを生成できるようになります。

関連項目:

- DYNAMIC_SAMPLINGヒントを使用したサンプリング・レベルの設定の詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

- OPTIMIZER_DYNAMIC_SAMPLING初期化パラメータの詳細は、『Oracle Databaseリファレンス』を参照してください。

動的統計の無効化

一般的には、繰返しのないOLTP問合せなど、コンパイル時間を可能なかぎり速くすることが必要な問合せに対して、動的統計のコストが発生しないようにすることがベスト・プラクティスです。

セッション・レベルの動的統計を無効化する手順は次のとおりです。

1. 適切な権限でSQL*Plusをデータベースに接続します。

2. 動的統計レベルを0に設定します。
たとえば、次の文を実行します。

ALTER SESSION SET OPTIMIZER_DYNAMIC_SAMPLING=0;

関連項目:

OPTIMIZER_DYNAMIC_SAMPLING初期化パラメータの詳細は、『Oracle Databaseリファレンス』を参照してください。

保留中のオプティマイザ統計の公開

デフォルトでは、統計収集が終了すると、データベースで統計が自動的に公開されます。その一方で、保留中の統計を使用してその統計を保存することで、収集後すぐに公開されないようにできます。この手法は、保留中の統計を使用してセッション内の問合せをテストする際に役立ちます。テストの結果が十分であれば、その統計を公開してデータベース全体で使用することができます。

保留中のオプティマイザ統計について

データベースでは、公開された統計と同様に、データ・ディクショナリに保留中の統計が格納されています。

デフォルトでは、オプティマイザは公開された統計を使用します。OPTIMIZER_USE_PENDING_STATISTICS初期化パラメータをtrue(デフォルトはfalse)に設定することで、デフォルトの動作を変更できます。

次の図の上部には、sh.customers表の統計を収集して、それを保留中の状態でデータ・ディクショナリに格納するオプティマイザが示されています。ダイアグラムの下部には、sh.customersの問合せの処理に、公開された統計のみを使用するオプティマイザが示されています。

図13-1 公開された統計と保留中の統計

場合によっては、オプティマイザが、公開された統計と保留中の統計の組合せを使用することがあります。たとえば、customers表の公開された統計および保留中の統計の両方がデータベースに格納されているとします。orders表については、公開された統計のみがデータベースに格納されているとします。OPTIMIZER_USE_PENDING_STATS = trueの場合、オプティマイザはcustomersには保留中の統計を使用し、ordersには公開された統計を使用します。OPTIMIZER_USE_PENDING_STATS = falseの場合、オプティマイザはcustomersおよびordersに公開された統計を使用します。

関連項目:

OPTIMIZER_USE_PENDING_STATISTICS初期化パラメータの詳細は、『Oracle Databaseリファレンス』を参照してください。

オプティマイザ統計の公開のためのユーザー・インタフェース

DBMS_STATSパッケージを使用して、統計の公開に関する操作を実行できます。表13-2には、関連するプログラム・ユニットがリストされています。

表13-2 オプティマイザ統計の公開に関連するDBMS_STATSプログラム・ユニット

プログラム・ユニット

説明

GET_PREFS

DBMS_STATSで統計が収集されると、すぐにその統計が自動的に公開されているかどうかをチェックします。PUBLISHパラメータがtrueの場合はデータベースで統計を収集した際にその統計を公開する必要があり、falseの場合はデータベースで統計を保留したままにする必要があることを示します。

SET_TABLE_PREFS

PUBLISH設定を表レベルでtrueまたはfalseに設定します。

SET_SCHEMA_PREFS

PUBLISH設定をスキーマ・レベルでtrueまたはfalseに設定します。

PUBLISH_PENDING_STATS

すべてのオブジェクトまたは特定のオブジェクトのみの有効な保留中の統計を公開します。

DELETE_PENDING_STATS

保留中の統計を削除します。

EXPORT_PENDING_STATS

保留中の統計をエクスポートします。

OPTIMIZER_USE_PENDING_STATISTICS初期化パラメータでは、データベースで保留中の統計が使用可能な場合は、その統計を使用するかどうかが決定されます。デフォルト値はfalseで、オプティマイザが公開された統計のみを使用することを意味します。trueに設定した場合は、オプティマイザが既存の保留中の統計を使用するように指定されます。このパラメータをデータベース・レベルではなく、セッション・レベルで設定することがベスト・プラクティスです。

データ・ディクショナリ・ビューでは、公開された統計に関するアクセス情報を使用できます。表13-3には、関連するビューがリストされています。

表13-3 オプティマイザ統計の公開に関連するビュー

ビュー

説明

USER_TAB_STATISTICS

現行ユーザーがアクセス可能な表のオプティマイザ統計を表示します。

USER_TAB_COL_STATISTICS

ALL_TAB_COLUMNSから抽出される列統計情報およびヒストグラム情報を示します。

USER_PART_COL_STATISTICS

現行のユーザーが所有する表パーティションの列統計およびヒストグラム情報を示します。

USER_SUBPART_COL_STATISTICS

現行のユーザーが所有するパーティション・オブジェクトのサブパーティションの列統計およびヒストグラム情報を示します。

USER_IND_STATISTICS

現行ユーザーがアクセス可能な索引のオプティマイザ統計を表示します。

USER_TAB_PENDING_STATS

現行ユーザーがアクセス可能な表、パーティションおよびサブパーティションの保留中の統計を示します。

USER_COL_PENDING_STATS

現行ユーザーがアクセス可能な列の保留中の統計を示します。

USER_IND_PENDING_STATS

現行ユーザーがアクセス可能な表、パーティションおよびサブパーティションの保留中の統計で、DBMS_STATSパッケージを使用して収集されたものを示します。

関連項目:

- DBMS_STATSパッケージの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

- USER_TAB_PENDING_STATSおよび関連するビューの詳細は、『Oracle Databaseリファレンス』を参照してください。

公開された統計と保留中の統計の管理

この項では、DBMS_STATSプログラム・ユニットを使用してオプティマイザ統計の公開動作を変更する方法のほか、これらの統計をエクスポートおよび削除する方法について説明します。

前提条件

このチュートリアルでは、次のことが前提となっています。

- 新しく収集された統計が保留中の状態になるように、sh.customers表およびsh.sales表のプリファレンスを変更します。

- 現行のセッションで保留中の統計を使用します。

- sh.customers表の統計を収集し、保留中の統計を公開します。

- sh.sales表の保留中の統計を収集しますが、それらを公開せずに削除することとします。

- 新しく収集された統計を公開するように、sh.customers表およびsh.sales表のプリファレンスを変更します。

公開された統計と保留中の統計を管理する手順は次のとおりです。

1. SQL*Plusを起動し、ユーザーshとしてデータベースに接続します。

2. グローバル・オプティマイザ統計の公開設定を問い合せます。
次の問合せを実行します(出力例も示します)。

sh@PROD> SELECT DBMS_STATS.GET_PREFS('PUBLISH') PUBLISH FROM DUAL;

PUBLISH
-------
TRUE

値trueは、統計を収集する際に統計がデータベースで公開されることを示します。特定の表プリファレンスが設定されていないかぎり、各表でこの値が使用されます。

GET_PREFSを使用する場合は、スキーマ名または表名も指定できます。この関数は、表のプリファレンスが設定されている場合はそのプリファレンスを戻します。それ以外の場合はグローバル・プリファレンスが戻されます。

3. 保留中の統計を問い合せます。
たとえば、次の問合せを実行します(出力例も示します)。

sh@PROD> SELECT * FROM USER_TAB_PENDING_STATS;

no rows selected

この例では、現在、データベースにshスキーマの保留中の統計が格納されていないことが示されています。

4. sh.customers表の公開プリファレンスを変更します。
たとえば、次のプロシージャを実行することで統計を保留中としてマークします。

BEGIN
DBMS_STATS.SET_TABLE_PREFS('sh', 'customers', 'publish', 'false');
END;
/

その後、customers表で統計を収集する場合は、収集ジョブの完了時にデータベースで統計が自動的に公開されなくなります。かわりに、新規に収集された統計はUSER_TAB_PENDING_STATS表に格納されます。

5. sh.customersの統計を収集します。
たとえば、次のプログラムを実行します。

BEGIN
DBMS_STATS.GATHER_TABLE_STATS('sh','customers');
END;
/

6. 保留中の統計を問い合せます。
たとえば、次の問合せを実行します(出力例も示します)。

sh@PROD> SELECT TABLE_NAME, NUM_ROWS FROM USER_TAB_PENDING_STATS;

TABLE_NAME                       NUM_ROWS
------------------------------ ----------
CUSTOMERS                           55500

この例は、現在、データベースにsh.customers表の保留中の統計が格納されていることを示しています。

7. このセッションで保留中の統計を使用するようにオプティマイザに指示します。
次に示すように、OPTIMIZER_USE_PENDING_STATISTICS初期化パラメータをtrueに設定します。

ALTER SESSION SET OPTIMIZER_USE_PENDING_STATISTICS = true;

8. ワークロードを実行します。
次の例は、Bruce Chalmersという名前のすべての顧客の電子メール・アドレスを変更します。

UPDATE  sh.customers
SET   cust_email='ChalmersB@company.com'
WHERE cust_first_name = 'Bruce'
AND   cust_last_name = 'Chalmers';
COMMIT;

オプティマイザは、このセッションですべてのSQL文をコンパイルする際に、公開された統計ではなく保留中の統計を使用します。

9. sh.customersの保留中の統計を公開します。
たとえば、次のプログラムを実行します。

BEGIN
DBMS_STATS.PUBLISH_PENDING_STATS('SH','CUSTOMERS');
END;
/

10. sh.sales表の公開プリファレンスを変更します。
たとえば、次のプログラムを実行します。

BEGIN
DBMS_STATS.SET_TABLE_PREFS('sh', 'sales', 'publish', 'false');
END;
/

その後、sh.sales表で統計を収集する場合は、収集ジョブの完了時にデータベースで統計が自動的に公開されなくなります。かわりに、データベースではUSER_TAB_PENDING_STATS表に統計が格納されます。

11. sh.salesの統計を収集します。
たとえば、次のプログラムを実行します。

BEGIN
DBMS_STATS.GATHER_TABLE_STATS('sh','sales');
END;
/

12. sh.salesの保留中の統計を削除します。
考えが変わって、sh.salesの保留中の統計を削除することにしたと仮定します。次のプログラムを実行します。

BEGIN
DBMS_STATS.DELETE_PENDING_STATS('sh','sales');
END;
/

13. sh.customers表とsh.sales表の公開プリファレンスを変更してデフォルト設定に戻します。
たとえば、次のプログラムを実行します。

BEGIN
DBMS_STATS.SET_TABLE_PREFS('sh', 'customers', 'publish', null);
DBMS_STATS.SET_TABLE_PREFS('sh', 'sales', 'publish', null);
END;
/

拡張統計の管理

DBMS_STATSでは拡張統計の収集が可能で、複数の述語が1つの表の異なる列に存在する場合や、述語で式を使用する場合に、拡張統計によりカーディナリティ予測を改善できます。拡張は、列グループまたは式のいずれかになります。

Oracle Databaseでは次の種類の拡張統計がサポートされます。

- 列グループの統計
この種類の拡張統計では、同じ表の複数の列が1つのSQL文に同時に存在する場合のカーディナリティ予測を改善できます。たとえば、自動車メーカーと車種、市と都道府県などです。「列グループの統計の管理」を参照してください。

- 式の統計
この種類の拡張統計では、組込みファンクションやユーザー定義ファンクションなどの式を述語で使用する際にオプティマイザの見積りが改善されます。たとえば、従業員の姓に適用されたUPPERファンクションなどです。

注意:

仮想列の拡張統計を作成することはできません。

関連項目:

- 「式の統計の管理」

- 仮想列の制限事項は、『Oracle Database SQL言語リファレンス』を参照してください。

列グループの統計の管理

列グループは1つの単位として扱われる一連の列です。

基本的に、列グループは仮想列です。列グループの統計を収集することで、問合せでそれらの列をグループ化した際に、オプティマイザでカーディナリティ予測をより正確に算出できます。

次の項では、列グループの統計の概要および列グループの統計を手動で管理する方法について説明します。

- 列グループの統計について

- 特定のワークロードに対して有用な列グループの検出

- ワークロードの監視中に検出された列グループの作成

- 手動による列グループの作成および統計の収集

- 列グループ情報の表示

- 列グループの削除

関連項目:

DBMS_STATSパッケージの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください

列グループの統計について

WHERE句で1つの述語の選択性を決定する場合は、個々の列の統計が役に立ちます。ただし、WHERE句に同じ表の異なる列にある複数の述語が含まれている場合は、個々の列の統計では列間の関係が示されません。これは、列グループによって解決される問題です。

オプティマイザでは、述語の選択性を別々に計算してから組み合せることになります。ただし、個々の列間の関係が存在する場合は、オプティマイザでカーディナリティ予測を算出するタイミングを考慮に入れることができず、表の述語ごとの選択性に行数を掛けることで作成します。

次の図は、sh.customers表のcust_state_province列およびcountry_id列で統計を収集する2つの方法を対比しています。この図は、DBMS_STATSによって各列の個別の統計とグループの統計が収集される様子を示しています。列グループにはシステム生成の名前があります。

図13-2 列グループの統計

注意:

オプティマイザでは、等価述語、INリスト述語、さらにGROUP BYカーディナリティの見積りに対して列グループの統計を使用します。

列グループの統計が必要な理由: 例

DBA_TAB_COL_STATISTICS表の次の問合せには、sh.customers表のcust_state_province列とcountry_id列で収集された統計に関する情報が示されています。

COL COLUMN_NAME FORMAT a20
COL NDV FORMAT 999

SELECT COLUMN_NAME, NUM_DISTINCT AS "NDV", HISTOGRAM
FROM   DBA_TAB_COL_STATISTICS
WHERE  OWNER = 'SH'
AND    TABLE_NAME = 'CUSTOMERS'
AND    COLUMN_NAME IN ('CUST_STATE_PROVINCE', 'COUNTRY_ID');

次に出力の例を示します。

COLUMN_NAME                 NDV HISTOGRAM
-------------------- ---------- ---------------
CUST_STATE_PROVINCE         145 FREQUENCY
COUNTRY_ID                   19 FREQUENCY

次の問合せに示すとおり、カリフォルニアには3341人の顧客が居住しています。

SELECT COUNT(*)
FROM   sh.customers
WHERE  cust_state_province = 'CA';

COUNT(*)
----------
3341

州がCAで国のIDが52790(USA)である顧客の問合せに対する実行計画を検討します。

EXPLAIN PLAN FOR
SELECT *
FROM   sh.customers
WHERE  cust_state_province = 'CA'
AND    country_id=52790;

Explained.

sys@PROD> SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);

PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
Plan hash value: 1683234692

-------------------------------------------------------------------------------
| Id  | Operation         | Name      | Rows  | Bytes | Cost (%CPU)| Time     |
-------------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |           |   128 | 24192 |   442   (7)| 00:00:06 |
|*  1 |  TABLE ACCESS FULL| CUSTOMERS |   128 | 24192 |   442   (7)| 00:00:06 |
-------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------

1 - filter("CUST_STATE_PROVINCE"='CA' AND "COUNTRY_ID"=52790)

13 rows selected.

country_id列およびcust_state_province列の単一列統計に基づいて、オプティマイザは、USAのカリフォルニアの顧客の問合せで128行戻されると見積ります。実際には、カリフォルニアには3341の顧客が存在しますが、オプティマイザは、カリフォルニアがUSAにあることを把握していないため、両方の述語により、戻される行数が減少すると想定して、カーディナリティが大幅に過小評価されます。

列グループの統計を収集することで、country_idとcust_state_provinceの値の間に実世界での関連があることをオプティマイザに認識させることができます。これらの統計によって、オプティマイザは、より正確なカーディナリティ予測を行うことが可能になります。

関連項目:

- 「特定のワークロードに対して有用な列グループの検出」

- 「ワークロードの監視中に検出された列グループの作成」

- 「手動による列グループの作成および統計の収集」

列グループの統計のユーザー・インタフェース

いくつかのDBMS_STATSプログラム・ユニットには、列グループに関連するプリファレンスがあります。

表13-4 DBMS_STATS列グループのプログラム・ユニット

プログラム・ユニット

説明

SEED_COL_USAGE

指定されたワークロードでSQL文を繰り返し、それらをコンパイルした上で、その文に表示される列の列使用情報をシードします。

適切な列グループを決定するには、データベースで代表的なワークロードを監視する必要があります。監視期間中は問合せ自体を実行する必要はありません。かわりに、ワークロードで長時間実行される一部の問合せに対してEXPLAIN PLANを実行することで、それらの問合せの列グループ情報がデータベースで記録されていることを確認できます。

REPORT_COL_USAGE

ワークロード内のフィルタ述語、結合述語およびGROUP BY句にあった列をリストするレポートが生成されます。

このファンクションを使用して、特定の表に記録された列使用情報を確認できます。

CREATE_EXTENDED_STATS

拡張機能(列グループまたは式のいずれか)を作成します。ユーザー生成の統計収集ジョブまたは自動の統計収集ジョブのいずれかで表の統計を収集した場合、データベースでは拡張機能の統計が収集されます。

関連項目:

DBMS_STATSパッケージの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください

特定のワークロードに対して有用な列グループの検出

DBMS_STATS.SEED_COL_USAGEおよびREPORT_COL_USAGEを使用して、指定のワークロードに基づいて表で必要な列グループを決定できます。この手法は、作成する拡張統計がわからない場合に役に立ちます。この手法は、式の統計に対しては機能しません。

注意:

SQLチューニング・セットの列使用はシードできます(「SQLチューニング・セットの管理」を参照)。

前提条件

このチュートリアルでは、次のことが前提となっています。

- country_id列およびcust_state_province列を参照する述語を使用するsh.customers_test表(customers表から作成)の問合せに対して、カーディナリティ予測が正しくありません。

- データベースでワークロードを5分間(300秒間)監視します。

- データベースで必要な列グループを自動的に決定します。

列グループを検出する手順は次のとおりです。

1. SQL*Plusをユーザーshとしてデータベースに接続した上で、customers_test表を作成し、その統計を収集します。

CONNECT SH/SH
DROP TABLE customers_test;
CREATE TABLE customers_test AS SELECT * FROM customer;
EXEC DBMS_STATS.GATHER_TABLE_STATS(user, 'customers_test');

2. ワークロード監視を有効化します。
別のSQL*Plusセッションでは、SYSとして接続して次のPL/SQLプログラムを実行し、300秒間の監視を有効化します。

BEGIN
DBMS_STATS.SEED_COL_USAGE(null,null,300);
END;
/

3. ユーザーshとして、ワークロード内の2つの問合せの実行計画を実行します。
次の例では、customers_test表の2つの問合せの実行計画が示されています。

EXPLAIN PLAN FOR
SELECT *
FROM   customers_test
WHERE  cust_city = 'Los Angeles'
AND    cust_state_province = 'CA'
AND    country_id = 52790;

SELECT PLAN_TABLE_OUTPUT
FROM   TABLE(DBMS_XPLAN.DISPLAY('plan_table', null,'basic rows'));

EXPLAIN PLAN FOR
SELECT   country_id, cust_state_province, count(cust_city)
FROM     customers_test
GROUP BY country_id, cust_state_province;

SELECT PLAN_TABLE_OUTPUT
FROM   TABLE(DBMS_XPLAN.DISPLAY('plan_table', null,'basic rows'));

出力例は次のように表示されます。

PLAN_TABLE_OUTPUT
---------------------------------------------------------------------------
Plan hash value: 4115398853

----------------------------------------------------
| Id  | Operation         | Name           | Rows  |
----------------------------------------------------
|   0 | SELECT STATEMENT  |                |     1 |
|   1 |  TABLE ACCESS FULL| CUSTOMERS_TEST |     1 |
----------------------------------------------------

8 rows selected.

PLAN_TABLE_OUTPUT
---------------------------------------------------------------------------
Plan hash value: 3050654408

-----------------------------------------------------
| Id  | Operation          | Name           | Rows  |
-----------------------------------------------------
|   0 | SELECT STATEMENT   |                |  1949 |
|   1 |  HASH GROUP BY     |                |  1949 |
|   2 |   TABLE ACCESS FULL| CUSTOMERS_TEST | 55500 |
-----------------------------------------------------

9 rows selected.

最初の計画では、932行を戻す問合せの1行のカーディナリティが示されています。2番目の計画では、145行を戻す問合せの1949行のカーディナリティが示されています。

4. オプションで、表に記録された列使用情報を確認します。
DBMS_STATS.REPORT_COL_USAGEファンクションを呼び出してレポートを生成します。

SET LONG 100000
SET LINES 120
SET PAGES 0
SELECT DBMS_STATS.REPORT_COL_USAGE(user, 'customers_test')
FROM   DUAL;

レポートは次のように表示されます。

LEGEND:
.......

EQ         : Used in single table EQuality predicate
RANGE      : Used in single table RANGE predicate
LIKE       : Used in single table LIKE predicate
NULL       : Used in single table is (not) NULL predicate
EQ_JOIN    : Used in EQuality JOIN predicate
NONEQ_JOIN : Used in NON EQuality JOIN predicate
FILTER     : Used in single table FILTER predicate
JOIN       : Used in JOIN predicate
GROUP_BY   : Used in GROUP BY expression
...........................................................................

###########################################################################

COLUMN USAGE REPORT FOR SH.CUSTOMERS_TEST
.........................................

1. COUNTRY_ID                          : EQ
2. CUST_CITY                           : EQ
3. CUST_STATE_PROVINCE                 : EQ
4. (CUST_CITY, CUST_STATE_PROVINCE,
COUNTRY_ID)                        : FILTER
5. (CUST_STATE_PROVINCE, COUNTRY_ID)   : GROUP_BY
###########################################################################

前述のレポートでは、最初の3つの列が最初に監視された問合せの等価述語で使用されていました。

...
WHERE  cust_city = 'Los Angeles'
AND    cust_state_province = 'CA'
AND    country_id = 52790;

3つの列がすべて同じWHERE句に表示されていたため、レポートではそれらを1つのグループ・フィルタとして示しています。2番目の問合せでは、2つの列がGROUP BY句で表示されていたため、レポートではそれらをGROUP_BYとしてラベル付けしています。FILTERおよびGROUP_BYレポートにある列のセットは列グループの候補になります。

関連項目:

DBMS_STATSパッケージの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

ワークロードの監視中に検出された列グループの作成

表13-4に説明されているように、DBMS_STATS.CREATE_EXTENDED_STATSファンクションを使用して、DBMS_STATS.SEED_COL_USAGEの実行によって以前に検出された列グループを作成できます。

前提条件

このチュートリアルでは、「特定のワークロードに対して有用な列グループの検出」の手順が実行済であることが前提となっています。

列グループを作成する手順は次のとおりです。

1. ウィンドウの監視中に取得された使用情報に基づいて、customers_test表の列グループを作成します。
たとえば、次の問合せを実行します。

SELECT DBMS_STATS.CREATE_EXTENDED_STATS(user, 'customers_test') FROM DUAL;

出力例は次のように表示されます。

###########################################################################
EXTENSIONS FOR SH.CUSTOMERS_TEST
................................
1. (CUST_CITY, CUST_STATE_PROVINCE,
COUNTRY_ID)                     :SYS_STUMZ$C3AIHLPBROI#SKA58H_N created
2. (CUST_STATE_PROVINCE, COUNTRY_ID):SYS_STU#S#WF25Z#QAHIHE#MOFFMM_ created
###########################################################################

データベースでは、フィルタ述語の列グループとGROUP BY操作のグループというcustomers_testの2つの列グループが作成されました。

2. 表の統計を再収集します。
GATHER_TABLE_STATSを実行してcustomers_testの統計を再収集します。

EXEC DBMS_STATS.GATHER_TABLE_STATS(user,'customers_test');

3. ユーザーshとして、ワークロード内の2つの問合せの実行計画を実行します。
USER_TAB_COL_STATISTICSビューをチェックして、データベースで作成された追加の統計を判別します。

SELECT COLUMN_NAME, NUM_DISTINCT, HISTOGRAM
FROM   USER_TAB_COL_STATISTICS
WHERE  TABLE_NAME = 'CUSTOMERS_TEST'
ORDER BY 1;

出力例の一部を次に示します。

CUST_CITY                               620 HEIGHT BALANCED
...
SYS_STU#S#WF25Z#QAHIHE#MOFFMM_          145 NONE
SYS_STUMZ$C3AIHLPBROI#SKA58H_N          620 HEIGHT BALANCED

この例では、DBMS_STATS.CREATE_EXTENDED_STATSファンクションから戻された2つの列グループ名が示されています。CUST_CITY、CUST_STATE_PROVINCEおよびCOUNTRY_IDで作成された列グループには高さ調整済ヒストグラムがあります。

4. 再び計画をEXPLAINします。
次の例では、customers_test表の2つの問合せの実行計画が示されています。

EXPLAIN PLAN FOR
SELECT *
FROM   customers_test
WHERE  cust_city = 'Los Angeles'
AND    cust_state_province = 'CA'
AND    country_id = 52790;

SELECT PLAN_TABLE_OUTPUT
FROM   TABLE(DBMS_XPLAN.DISPLAY('plan_table', null,'basic rows'));

EXPLAIN PLAN FOR
SELECT   country_id, cust_state_province, count(cust_city)
FROM     customers_test
GROUP BY country_id, cust_state_province;

SELECT PLAN_TABLE_OUTPUT
FROM   TABLE(DBMS_XPLAN.DISPLAY('plan_table', null,'basic rows'));

新しい計画では、より正確なカーディナリティ予測が示されます。

----------------------------------------------------
| Id  | Operation         | Name           | Rows  |
----------------------------------------------------
|   0 | SELECT STATEMENT  |                |  1093 |
|   1 |  TABLE ACCESS FULL| CUSTOMERS_TEST |  1093 |
----------------------------------------------------

8 rows selected.

Plan hash value: 3050654408

-----------------------------------------------------
| Id  | Operation          | Name           | Rows  |
-----------------------------------------------------
|   0 | SELECT STATEMENT   |                |   145 |
|   1 |  HASH GROUP BY     |                |   145 |
|   2 |   TABLE ACCESS FULL| CUSTOMERS_TEST | 55500 |
-----------------------------------------------------
9 rows selected.

関連項目:

DBMS_STATSパッケージの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

手動による列グループの作成および統計の収集

場合によっては、作成が必要な列グループがわかっていることがあります。DBMS_STATS.GATHER_TABLE_STATSファンクションのMETHOD_OPT引数では、列グループの統計を自動的に作成および収集できます。FOR COLUMNSを使用して列のグループを指定することで、新しい列グループを作成できます。

前提条件

このチュートリアルでは、次のことが前提となっています。

- shスキーマのcustomers表にあるcust_state_province列およびcountry_id列の列グループを作成します。

- 表全体および新しい列グループで統計(ヒストグラムを含む)を収集します。

列グループを作成し、そのグループの統計を収集する手順は次のとおりです。

1. SQL*Plusを起動し、ユーザーshとしてデータベースに接続します。

2. 列グループを作成して統計を収集します。
たとえば、次のPL/SQLプログラムを実行します。

BEGIN
DBMS_STATS.GATHER_TABLE_STATS( 'sh','customers',
METHOD_OPT => 'FOR ALL COLUMNS SIZE SKEWONLY ' ||
'FOR COLUMNS SIZE SKEWONLY (cust_state_province,country_id)' );
END;
/

関連項目:

DBMS_STATS.GATHER_TABLE_STATSプロシージャの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

列グループ情報の表示

列グループの名前を取得するには、DBMS_STATS.SHOW_EXTENDED_STATS_NAMEファンクションまたはデータベース・ビューを使用します。また、ビューを使用して、個別値の数や列グループでのヒストグラムの有無などの情報を取得できます。

前提条件

このチュートリアルでは、次のことが前提となっています。

- shスキーマのcustomers表にあるcust_state_province列およびcountry_id列の列グループは作成済です。

- 列グループ名、個別値の数のほか、列グループに対してヒストグラムが作成済であるかどうかを判別します。

列グループを監視する手順は次のとおりです。

1. SQL*Plusを起動し、ユーザーshとしてデータベースに接続します。

2. 列グループ名を判別するには、次のうちの1つを実行します。

- SHOW_EXTENDED_STATS_NAMEファンクションを実行します。
たとえば、次のPL/SQLプログラムを実行します。

SELECT SYS.DBMS_STATS.SHOW_EXTENDED_STATS_NAME( 'sh','customers',
'(cust_state_province,country_id)' ) col_group_name
FROM   DUAL;

出力は、次のようなものです。

COL_GROUP_NAME
----------------
SYS_STU#S#WF25Z#QAHIHE#MOFFMM_

- USER_STAT_EXTENSIONSビューを問い合せます。
たとえば、次の問合せを実行します。

SELECT EXTENSION_NAME, EXTENSION
FROM   USER_STAT_EXTENSIONS
WHERE  TABLE_NAME='CUSTOMERS';

EXTENSION_NAME                     EXTENSION
-----------------------------------------------------------------------
SYS_STU#S#WF25Z#QAHIHE#MOFFMM_     ("CUST_STATE_PROVINCE","COUNTRY_ID")

3. 個別値の数と、列グループに対してヒストグラムが作成済かどうかを問い合せます。
たとえば、次の問合せを実行します。

SELECT e.EXTENSION col_group, t.NUM_DISTINCT, t.HISTOGRAM
FROM   USER_STAT_EXTENSIONS e, USER_TAB_COL_STATISTICS t
WHERE  e.EXTENSION_NAME=t.COLUMN_NAME
AND    e.TABLE_NAME=t.TABLE_NAME
AND    t.TABLE_NAME='CUSTOMERS';

COL_GROUP                             NUM_DISTINCT        HISTOGRAM
-------------------------------------------------------------------
("COUNTRY_ID","CUST_STATE_PROVINCE")  145                 FREQUENCY

関連項目:

DBMS_STATS.SHOW_EXTENDED_STATS_NAMEファンクションの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

列グループの削除

DBMS_STATS.DROP_EXTENDED_STATSファンクションを使用して、表から列グループを削除します。

前提条件

このチュートリアルでは、次のことが前提となっています。

- shスキーマのcustomers表にあるcust_state_province列およびcountry_id列の列グループは作成済です。

- 列グループを削除します。

列グループを削除する手順は次のとおりです。

1. SQL*Plusを起動し、ユーザーshとしてデータベースに接続します。

2. 列グループを削除します。
たとえば、次のPL/SQLプログラムでcustomers表から列グループを削除します。

BEGIN
DBMS_STATS.DROP_EXTENDED_STATS( 'sh', 'customers',
'(cust_state_province, country_id)' );
END;
/

関連項目:

DBMS_STATS.DROP_EXTENDED_STATSファンクションの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

式の統計の管理

式の統計と呼ばれる拡張統計の種類は、WHERE句に式を使用する述語がある場合にオプティマイザの見積りを改善します。

この項の内容は次のとおりです。

- 式の統計について

- 式の統計の作成

- 式の統計の表示

- 式の統計の削除

式の統計について

WHERE句列に適用されたフォーム(function(col)=constant)内の式については、ファンクション索引が存在しないかぎり、オプティマイザではこのファンクションが述語のカーディナリティに及ぼす影響を認識しません。ただし、式function(col)自体に対する式の統計を収集できます。

次の図は、ファンクションを使用する問合せの計画を生成するために統計を使用するオプティマイザを示しています。上部には、列の統計をチェックするオプティマイザが示されています。下部には、問合せで使用される式に対応する統計をチェックするオプティマイザが示されています。式の統計によってより正確な見積りが生成されます。

図13-3 式の統計

図13-3に示すとおり、式の統計が利用できない場合、オプティマイザは最適ではない計画を生成する可能性があります。

関連項目:

SQL関数の詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

式の統計が有用なタイミング: 例

sh.customers表の次の問合せでは、カリフォルニア州に3341人の顧客がいることが示されています。

sys@PROD> SELECT COUNT(*) FROM sh.customers WHERE cust_state_province='CA';

COUNT(*)
----------
3341

LOWER()ファンクションを適用して同じ問合せの計画を検討します。

sys@PROD> EXPLAIN PLAN FOR
2  SELECT * FROM sh.customers WHERE LOWER(cust_state_province)='ca';
Explained.

sys@PROD> select * from table(dbms_xplan.display);

PLAN_TABLE_OUTPUT
-------------------------------------------------------------------------------
Plan hash value: 2008213504

-------------------------------------------------------------------------------
| Id  | Operation         | Name      | Rows  | Bytes | Cost (%CPU)| Time     |
-------------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |           |   555 |   108K|   406   (1)| 00:00:05 |
|*  1 |  TABLE ACCESS FULL| CUSTOMERS |   555 |   108K|   406   (1)| 00:00:05 |
-------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

1 - filter(LOWER("CUST_STATE_PROVINCE")='ca')

LOWER(cust_state_province)='ca'の式の統計が存在しないため、オプティマイザの見積りが大幅にずれています。DBMS_STATSプロシージャを使用することで、この見積りを修正できます。

式の統計の作成

DBMS_STATSを使用して、ユーザー指定の式の統計を作成できます。

次のプログラム・ユニットのいずれかを使用できます。

- GATHER_TABLE_STATSプロシージャ

- CREATE_EXTENDED_STATISTICSファンクションに続くGATHER_TABLE_STATSプロシージャ

前提条件

このチュートリアルでは、次のことが前提となっています。

- UPPER(cust_state_province)ファンクションを使用するsh.customersの問合せに対する選択性の見積りが間違っています。

- UPPER(cust_state_province)式の統計を収集します。

式の統計を作成する手順は次のとおりです。

1. SQL*Plusを起動し、ユーザーshとしてデータベースに接続します。

2. 表の統計を収集します。
たとえば、次のコマンドを実行して、method_opt引数に関数を指定します。

BEGIN
DBMS_STATS.GATHER_TABLE_STATS(
'sh'
,   'customers'
,   method_opt => 'FOR ALL COLUMNS SIZE SKEWONLY ' ||
'FOR COLUMNS (LOWER(cust_state_province)) SIZE SKEWONLY'
);
END;

関連項目:

DBMS_STATS.GATHER_TABLE_STATSプロシージャの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

式の統計の表示

データベース・ビューの DBA_STAT_EXTENSIONSとDBMS_STATS.SHOW_EXTENDED_STATS_NAMEファンクションを使用して、式の統計に関する情報を取得します。また、ビューを使用して、個別値の数や列グループでのヒストグラムの有無などの情報を取得できます。

前提条件

このチュートリアルでは、次のことが前提となっています。

- LOWER(cust_state_province)式の拡張統計が作成されています。

- 列グループ名、個別値の数のほか、列グループに対してヒストグラムが作成済であるかどうかを判別します。

式の統計を監視する手順は次のとおりです。

1. SQL*Plusを起動し、ユーザーshとしてデータベースに接続します。

2. 統計の拡張の名前と定義を問い合せます。
たとえば、次の問合せを実行します。

COL EXTENSION_NAME FORMAT a30
COL EXTENSION FORMAT a35

SELECT EXTENSION_NAME, EXTENSION
FROM   USER_STAT_EXTENSIONS
WHERE  TABLE_NAME='CUSTOMERS';

出力例は次のように表示されます。

EXTENSION_NAME                 EXTENSION
------------------------------ ------------------------------
SYS_STUBPHJSBRKOIK9O2YV3W8HOUE (LOWER("CUST_STATE_PROVINCE"))

3. 個別値の数を問い合せ、式に対してヒストグラムが作成済かどうかを判別します。
たとえば、次の問合せを実行します。

SELECT e.EXTENSION expression, t.NUM_DISTINCT, t.HISTOGRAM
FROM   USER_STAT_EXTENSIONS e, USER_TAB_COL_STATISTICS t
WHERE  e.EXTENSION_NAME=t.COLUMN_NAME
AND    e.TABLE_NAME=t.TABLE_NAME
AND    t.TABLE_NAME='CUSTOMERS';

EXPRESSION                            NUM_DISTINCT        HISTOGRAM
-------------------------------------------------------------------
(LOWER("CUST_STATE_PROVINCE"))        145                 FREQUENCY

関連項目:

- DBMS_STATS.SHOW_EXTENDED_STATS_NAMEプロシージャの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

- DBA_STAT_EXTENSIONSビューの詳細は、『Oracle Databaseリファレンス』を参照してください。

式の統計の削除

DBMS_STATS.DROP_EXTENDED_STATSファンクションを使用して、表から列グループを削除します。

前提条件

このチュートリアルでは、次のことが前提となっています。

- LOWER(cust_state_province)式の拡張統計が作成されています。

- 式の統計を削除します。

式の統計を削除する手順は次のとおりです。

1. SQL*Plusを起動し、ユーザーshとしてデータベースに接続します。

2. 列グループを削除します。
たとえば、次のPL/SQLプログラムでcustomers表から列グループを削除します。

BEGIN
DBMS_STATS.DROP_EXTENDED_STATS(
'sh'
,   'customers'
,   '(LOWER(cust_state_province))'
);
END;
/

関連項目:

DBMS_STATS.DROP_EXTENDED_STATSプロシージャの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

オプティマイザ統計のロックおよびロック解除

統計はロックして変更されないようにできます。統計をロックすると、ロックを解除するまで統計を変更できません。

統計および生成される計画が変化しないことを保証する必要がある場合に、ロック・プロシージャは静的環境において役に立ちます。たとえば、非常に変化しやすい表など、ある表またはスキーマで、DBMS_STATS_JOBプロセスによって新しい統計が収集されないようにすることが必要な場合もあります。

表の統計をロックすると、依存するすべての統計がロックされます。ロックされる統計には、表の統計、列の統計、ヒストグラムおよび依存する索引統計が含まれます。ロックされている統計を上書きするには、DELETE_*_STATSおよびRESTORE_*_STATSをtrueに設定するなど、様々なDBMS_STATSプロシージャのFORCE引数の値を設定できます。

統計のロック

DBMS_STATSパッケージには、LOCK_SCHEMA_STATSおよびLOCK_TABLE_STATSという、統計をロックするための2つのプロシージャが用意されています。

前提条件

このチュートリアルでは、次のことが前提となっています。

- oe.orders表およびhrスキーマの統計が収集済です。

- oe.orders表の統計とhrスキーマの統計が変更されないようにします。

統計をロックする手順は次のとおりです。

1. SQL*Plusを起動し、oeユーザーとしてデータベースに接続します。

2. oe.ordersの統計をロックします。
たとえば、次のPL/SQLプログラムを実行します。

BEGIN
DBMS_STATS.LOCK_TABLE_STATS('OE','ORDERS');
END;
/

3. hrユーザーとしてデータベースに接続します。

4. hrスキーマ内の統計をロックします。
たとえば、次のPL/SQLプログラムを実行します。

BEGIN
DBMS_STATS.LOCK_SCHEMA_STATS('HR');
END;
/

関連項目:

DBMS_STATS.LOCK_TABLE_STATSプロシージャの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

統計のロック解除

DBMS_STATSパッケージには、UNLOCK_SCHEMA_STATSおよびUNLOCK_TABLE_STATSという、統計をロック解除するための2つのプロシージャが用意されています。

前提条件

このチュートリアルでは、次のことが前提となっています。

- oe.orders表およびhrスキーマの統計がロックされています。

- これらの統計をロック解除します。

統計をロック解除する手順は次のとおりです。

1. SQL*Plusを起動し、oeユーザーとしてデータベースに接続します。

2. oe.ordersの統計をロック解除します。
たとえば、次のPL/SQLプログラムを実行します。

BEGIN
DBMS_STATS.UNLOCK_TABLE_STATS('OE','ORDERS');
END;
/

3. hrユーザーとしてデータベースに接続します。

4. hrスキーマ内の統計をロック解除します。
たとえば、次のPL/SQLプログラムを実行します。

BEGIN
DBMS_STATS.UNLOCK_SCHEMA_STATS('HR');
END;
/

関連項目:

DBMS_STATS.UNLOCK_TABLE_STATSプロシージャの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

オプティマイザ統計のリストア

この項の内容は次のとおりです。

- オプティマイザ統計のリストア操作について

- オプティマイザ統計のリストアのガイドライン

- オプティマイザ統計のリストアの制限

- DBMS_STATSを使用したオプティマイザ統計のリストア

オプティマイザ統計のリストア操作について

データ・ディクショナリ内の統計を変更する場合は常に、データベースで古いバージョンの統計が自動的に保存されます。新しく収集した統計によって最適ではない実行計画が作成される場合は、以前の統計に戻すことが必要な場合もあります。

オプティマイザ統計をリストアすることが、最適ではない計画のトラブルシューティングに役立つ可能性があります。次の図は、統計のリストアを時系列で示しています。このグラフでは、統計の収集が8月10日と8月20日に行われます。8月24日に、現行の統計がオプティマイザで最適ではない計画が生成される原因となっている可能性があるとDBAで判定されています。8月25日に、管理者は8月10日に収集された統計をリストアしています。

図13-4 オプティマイザ統計のリストア

オプティマイザ統計のリストアのガイドライン

統計のリストアは、統計のインポートおよびエクスポートに類似しています。次のような状況では通常、統計のエクスポートではなく統計のリストアを行います。

- 統計の古いバージョンをリカバリする場合。たとえば、オプティマイザ動作を以前の日付までリストアすることが必要な場合があります。

- データベースで統計履歴の保存および消去を管理する場合。

次のような場合は、統計をリストアするのではなく、エクスポートします。

- 複数の統計セットを試験的に使用して値を増減させる場合。

- データベース間で統計を移動する場合。たとえば、本番システムからテスト・システムに統計を移動する場合などです。

- 既知の統計セットを統計のリストアに必要な保存日数よりも長期間にわたって保存する場合。

関連項目:

統計をリストアおよびインポートするためのプロシージャの概要については、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

オプティマイザ統計のリストアの制限

前のバージョンの統計をリストアする場合は、次の制限が適用されます。

- DBMS_STATS.RESTORE_*_STATSプロシージャでは、ユーザー定義統計はリストアできません。

- 統計の収集にANALYZEコマンドが使用された場合、古いバージョンの統計は格納されません。

- 表を削除すると、自動ヒストグラム収集機能が使用するワークロード情報と、RESTORE_*_STATSプロシージャが使用する保存された統計履歴が消失します。このデータなしでは、これらの機能は適切に動作しません。表からすべての行を削除し、DBMS_STATSを使用してこれらの統計をリストアするには、同じ表を削除して再作成するかわりにTRUNCATEを使用します。

DBMS_STATSを使用したオプティマイザ統計のリストア

DBMS_STATS.RESTORE_*_STATSプロシージャを使用して統計をリストアできます。表13-5にリストされたプロシージャでは、引数としてタイムスタンプを受け入れ、指定された日時(as_of_timestamp)の統計をリストアします。

表13-5 DBMS_STATSリストア・プロシージャ

プロシージャ

説明

RESTORE_DICTIONARY_STATS

指定されたタイムスタンプですべてのディクショナリ表(SYS、SYSTEMおよびRDBMSの各コンポーネント・スキーマの表)の統計をリストアします。

RESTORE_FIXED_OBJECTS_STATS

指定されたタイムスタンプですべての固定表の統計をリストアします。

RESTORE_SCHEMA_STATS

指定されたタイムスタンプでスキーマのすべての表の統計情報をリストアします。

RESTORE_SYSTEM_STATS

指定されたタイムスタンプのシステム統計をリストアします。

RESTORE_TABLE_STATS

指定されたタイムスタンプの表の統計をリストアします。また、このプロシージャでは、関連付けられた索引と列の統計がリストアされます。指定されたタイムスタンプで表の統計がロックされていた場合は、プロシージャでその統計がロックされます。

ディクショナリ・ビューには統計の変更日時が表示されています。次のビューを使用して、リストア操作に使用するタイムスタンプを決定できます。

- DBA_OPTSTAT_OPERATIONSビューには、DBMS_STATSを使用してスキーマ・レベルとデータベース・レベルで実行された統計操作の履歴が含まれます。

- DBA_TAB_STATS_HISTORYビューには表の統計の変更履歴が含まれます。

前提条件

このチュートリアルでは、次のことが前提となっています。

- oe.orders表に最新の統計を収集した後に、オプティマイザは、その表の問合せに最適ではない計画の選択を開始しました。

- 計画が改善されたかどうかを確認するために、最新の統計収集より前の統計をリストアします。

オプティマイザ統計をリストアする手順は次のとおりです。

1. SQL*Plusを起動し、管理者権限でデータベースに接続します。

2. oe.ordersの統計履歴を問い合せます。
たとえば、次の問合せを実行します。

COL TABLE_NAME FORMAT a10
SELECT TABLE_NAME,
TO_CHAR(STATS_UPDATE_TIME,'YYYY-MM-DD:HH24:MI:SS') AS STATS_MOD_TIME
FROM   DBA_TAB_STATS_HISTORY
WHERE  TABLE_NAME='ORDERS'
AND    OWNER='OE'
ORDER BY STATS_UPDATE_TIME DESC;

次に出力の例を示します。

TABLE_NAME STATS_MOD_TIME
---------- -------------------
ORDERS     2012-08-20:11:36:38
ORDERS     2012-08-10:11:06:20

3. オプティマイザ統計を以前の変更時にリストアします。
たとえば、oe.orders表の統計を2012年8月10日にリストアします。

BEGIN
DBMS_STATS.RESTORE_TABLE_STATS( 'OE','ORDERS',
TO_TIMESTAMP('2012-08-10:11:06:20','YYYY-MM-DD:HH24:MI:SS') );
END;
/

DBMS_STATSによって指定された日時の統計がリストアされるので、8/10から8/20までの間で任意の日付を指定できます。

関連項目:

DBMS_STATS.RESTORE_TABLE_STATSプロシージャの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

オプティマイザ統計の保存の管理

デフォルトでは、データベースは、31日間オプティマイザ統計を保存し、その日数より後の統計は消去するようにスケジュールされています。DBMS_STATSパッケージを使用して、保存期間を決定したり、保存期間を変更したり、古い統計を手動で消去したりすることができます。

この項の内容は次のとおりです。

- オプティマイザ統計の履歴の取得

- オプティマイザ統計の保存期間の変更

- オプティマイザ統計の消去

オプティマイザ統計の履歴の取得

DBMS_STATSプロシージャを使用して、オプティマイザ統計の履歴情報を取得できます。この情報は、データベースでオプティマイザ統計を保存する期間やその後に統計のリストアが可能な期間を決定する必要がある場合に役に立ちます。

オプティマイザ統計の履歴に関する情報を取得するには次のプロシージャを使用できます。

- GET_STATS_HISTORY_RETENTION
このファンクションでは、現行の統計履歴の保存値を取得できます。

- GET_STATS_HISTORY_AVAILABILITY
このファンクションでは、統計履歴が使用可能な場合に最も古いタイムスタンプを取得します。ユーザーが統計情報をリストアする場合、最も古いタイムスタンプよりさらに前のタイムスタンプにはできません。

オプティマイザ統計の履歴情報を取得する手順は次のとおりです。

1. SQL*Plusを起動し、必要な権限でデータベースに接続します。

2. 次のPL/SQLプログラムを実行します。

DECLARE
v_stats_retn  NUMBER;
v_stats_date  DATE;
BEGIN
v_stats_retn := DBMS_STATS.GET_STATS_HISTORY_RETENTION;
DBMS_OUTPUT.PUT_LINE('The retention setting is ' || v_stats_retn || '.');
v_stats_date := DBMS_STATS.GET_STATS_HISTORY_AVAILABILITY;
DBMS_OUTPUT.PUT_LINE('Earliest restore date is ' || v_stats_date || '.');
END;
/

関連項目:

DBMS_STATS.GET_STATS_HISTORY_RETENTIONプロシージャの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

オプティマイザ統計の保存期間の変更

デフォルトでは、データベースは、31日間オプティマイザ統計を保存します。DBMS_STATS.ALTER_STATS_HISTORY_RETENTIONプロシージャを使用して保存期間を構成できます。

前提条件

このプロシージャを実行するには、SYSDBA権限、またはANALYZE ANY DICTIONARYとANALYZE ANYの両方のシステム権限のいずれかを所有している必要があります。

前提条件

このチュートリアルでは、次のことが前提となっています。

- オプティマイザ統計の現行の保存期間は31日です。

- 年次報告書の一環として年に1回問合せを実行します。(現在、最適ではない計画が作成されている場合に)前年の計画にアクセスできるように、統計履歴を366日以上保持しておくには、保存期間を366日に設定します。

- オプティマイザ統計の保存期間の変更に使用できるPL/SQLプロシージャset_opt_stats_retentionを作成します。

オプティマイザ統計の保存期間を変更する手順は次のとおりです。

1. SQL*Plusを起動し、必要な権限でデータベースに接続します。

2. 保存期間を変更するプロシージャを作成します。
たとえば、次のプロシージャを作成します。

CREATE OR REPLACE PROCEDURE set_opt_stats_retention
( p_stats_retn   IN NUMBER )
IS
v_stats_retn NUMBER;
BEGIN
v_stats_retn := DBMS_STATS.GET_STATS_HISTORY_RETENTION;
DBMS_OUTPUT.PUT_LINE('Old retention setting is ' ||v_stats_retn|| '.');
DBMS_STATS.ALTER_STATS_HISTORY_RETENTION(p_stats_retn);
v_stats_retn := DBMS_STATS.GET_STATS_HISTORY_RETENTION;
DBMS_OUTPUT.PUT_LINE('New retention setting is ' ||v_stats_retn|| '.');
END;
/

3. 保存期間を366日に変更します。
たとえば、前の手順で作成したプロシージャを実行します(出力例も示します)。

SQL> EXECUTE set_opt_stats_retention(366)

The old retention setting is 31.
The new retention setting is 366.

PL/SQL procedure successfully completed.

関連項目:

DBMS_STATS.ALTER_STATS_HISTORY_RETENTIONプロシージャの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

オプティマイザ統計の消去

自動消去は、STATISTICS_LEVEL初期化パラメータをTYPICALまたはALLに設定した場合に有効になります。(現在の時間 - ALTER_STATS_HISTORY_RETENTION設定)と(最新の統計情報収集の時間 - 1)よりも古い履歴はすべて消去されます。

PURGE_STATSプロシージャを使用すると、古い統計を手動で消去できます。引数を指定しない場合、このプロシージャでは、自動消去ポリシーが使用されます。before_timestampパラメータを指定する場合は、指定されたタイムスタンプより前に保存された統計がデータベースで消去されます。

前提条件

このプロシージャを実行するには、SYSDBA権限、またはANALYZE ANY DICTIONARYとANALYZE ANYの両方のシステム権限のいずれかを所有している必要があります。

前提条件

このチュートリアルでは、1週間より前の統計を消去するものとします。

オプティマイザ統計を消去する手順は次のとおりです。

1. SQL*Plusを起動し、必要な権限でデータベースに接続します。

2. DBMS_STATS.PURGE_STATSプロシージャを実行します。
たとえば、プロシージャを次のように実行します。

EXEC DBMS_STATS.PURGE_STATS( SYSDATE-7 );

関連項目:

DBMS_STATS.PURGE_STATSプロシージャの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

オプティマイザ統計のインポートとエクスポート

データ・ディクショナリとユーザー定義の統計表間でオプティマイザ統計をエクスポートおよびインポートできます。また、データベース間で統計のコピーもできます。

インポートとエクスポートは、本番統計を使用したアプリケーションのテストを行う場合に特に役立ちます。DBMS_STATSを使用して本番データベースからテスト・データベースにスキーマの統計をエクスポートすることで、開発者は、アプリケーションのデプロイ前に実行計画を実際の環境に合せることができます。

オプティマイザ統計の転送について

データベース間でオプティマイザ統計を転送する場合は、DBMS_STATSを使用してステージング表間で統計をコピーし、ツールを使用して表のコンテンツに宛先データベースがアクセスできるようにする必要があります。

インポートとエクスポートは、本番統計を使用したアプリケーションのテストを行う場合に特に役立ちます。DBMS_STATS.EXPORT_SCHEMA_STATSを使用して本番データベースからテスト・データベースにスキーマの統計をエクスポートすることで、開発者は、アプリケーションのデプロイ前に実行計画を実際の環境に合せることができます。

次の図は、Oracle Data Pumpおよびftpを使用したプロセスを示しています。

図13-5 オプティマイザ統計の転送

図13-5に示すとおり、基本的な手順は次のようになります。

1. 本番データベースで、DBMS_STATS.EXPORT_SCHEMA_STATSを使用してデータ・ディクショナリからステージング表に統計をコピーします。

2. Oracle Data Pumpを使用してステージング表から.dmpファイルに統計をエクスポートします。

3. ftpなどの転送ツールを使用して本番ホストからテスト・ホストに.dmpファイルを転送します。

4. テスト・データベースで、Oracle Data Pumpを使用して.dmpファイルからステージング表に統計をインポートします。

5. DBMS_STATS.IMPORT_SCHEMA_STATSを使用してステージング表からデータ・ディクショナリに統計をコピーします。

テスト・データベースへのオプティマイザ統計の転送

DBMS_STATS.EXPORT_SCHEMA_STATSプロシージャを使用して統計を転送します。

前提条件と制限

オプティマイザ統計のエクスポートの準備をする際は、次のことに注意してください。

- 統計をエクスポートする前に、統計を保持するための表を作成する必要があります。統計表は、DBMS_STATS.CREATE_STAT_TABLEプロシージャで作成します。

- オプティマイザでは、ユーザー所有の表に格納された統計は使用されません。オプティマイザで使用されるのは、データ・ディクショナリに格納されている統計のみです。オプティマイザにユーザー定義の表の統計を使用させるには、DBMS_STATSインポート・プロシージャを使用してデータ・ディクショナリにこれらの統計をインポートします。

- データ・ポンプ・エクスポートとインポート・ユーティリティは、データベースから表とともにオプティマイザ統計をエクスポートおよびインポートします。列にシステム生成の名前が付けられている場合、元のエクスポート(exp)では統計をデータとともにエクスポートできませんが、この制限はデータ・ポンプのエクスポートには適用されません。

注意:

DBMS_STATSを使用した統計のエクスポートおよびインポートは、データ・ポンプ・エクスポートおよびインポートの使用とは異なる操作になります。

前提条件

このチュートリアルでは、次のことが前提となっています。

- 本番データベースで代表的なshスキーマの統計を生成し、DBMS_STATSを使用してそれらをテスト・データベースにインポートします。

- 管理ユーザーのdba1は、本番データベースとテスト・データベースの両方に存在します。

- opt_stats表を作成してスキーマ統計を格納します。

- Oracle Data Pumpを使用してopt_stats表をエクスポートおよびインポートします。

スキーマ統計を生成してそれらを別のデータベースにインポートする手順は次のとおりです。

1. 本番ホストで、SQL*Plusを起動して、管理者dba1として本番データベースに接続します。

2. 本番統計を保持するための表を作成します。
たとえば、次のPL/SQLプログラムを実行して、ユーザー統計表opt_statsを作成します。

BEGIN
DBMS_STATS.CREATE_STAT_TABLE (
ownname => 'dba1'
,   stattab => 'opt_stats'
);
END;
/

3. スキーマ統計を収集します。
たとえば、スキーマ統計を次のように手動で収集します。

-- generate representative workload
EXEC DBMS_STATS.GATHER_SCHEMA_STATS('SH');

4. DBMS_STATSを使用して統計をエクスポートします。
たとえば、スキーマ統計を取得してそれらを以前に作成したopt_stats表に格納します。

BEGIN
DBMS_STATS.EXPORT_SCHEMA_STATS (
ownname => 'dba1'
,   stattab => 'opt_stats'
);
END;
/

5. Oracle Data Pumpを使用して、統計表のコンテンツをエクスポートします。
たとえば、オペレーティング・スキーマ・プロンプトでexpdpコマンドを実行します。

expdp dba1 DIRECTORY=dpump_dir1 DUMPFILE=stat.dmp TABLES=opt_stats

6. dumpファイルをテスト・データベースのホストに転送します。

7. テスト・ホストにログインし、Oracle Data Pumpを使用して統計表のコンテンツをインポートします。
たとえば、オペレーティング・スキーマ・プロンプトでimpdpコマンドを実行します。

impdp dba1 DIRECTORY=dpump_dir1 DUMPFILE=stat.dmp TABLES=opt_stats

8. テスト・ホストで、SQL*Plusを起動して、管理者dba1としてテスト・データベースに接続します。

9. DBMS_STATSを使用してユーザー統計表から統計をインポートし、それらをデータ・ディクショナリに格納します。
次のPL/SQLプログラムでは、opt_stats表からデータ・ディクショナリにスキーマ統計をインポートします。

BEGIN
DBMS_STATS.IMPORT_SCHEMA_STATS(
ownname => 'dba1'
,   stattab => 'opt_stats'
);
END;
/

関連項目:

- DBMS_STATS.CREATE_STAT_TABLEファンクションの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

- 統計転送機能の概要は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

- Oracle Data Pumpの詳細は、『Oracle Databaseユーティリティ』を参照してください。

レポート作成モードでの統計収集関数の実行

DBMS_STATS統計収集プロシージャをレポート作成モードで実行できます。この場合、オプティマイザは、実際には統計を収集せずに、指定された統計収集関数を使用した場合に処理されるオブジェクトをレポートします。

表13-6には、DBMS_STATS.REPORT_GATHER_*_STATSファンクションがリストされています。追加パラメータのdetail_levelとformatを使用すると、すべてのファンクションで、入力パラメータが、対応するGATHER_*_STATSプロシージャと同じものになります。サポートされている形式は、XML、HTMLおよびTEXTです。

表13-6 DBMS_STATSレポート作成モード・ファンクション

ファンクション

説明

REPORT_GATHER_TABLE_STATS

レポート作成モードでGATHER_TABLE_STATSを実行します。このプロシージャでは統計は収集されませんが、GATHER_TABLE_STATSを起動することで影響を受ける可能性があるすべてのオブジェクトがレポートされます。

REPORT_GATHER_SCHEMA_STATS

レポート作成モードでGATHER_SCHEMA_STATSを実行します。このプロシージャでは実際に統計は収集されませんが、GATHER_SCHEMA_STATSを起動することで影響を受ける可能性があるすべてのオブジェクトがレポートされます。

REPORT_GATHER_DICTIONARY_STATS

レポート作成モードでGATHER_DICTIONARY_STATSを実行します。このプロシージャでは実際に統計は収集されませんが、GATHER_DICTIONARY_STATSを起動することで影響を受ける可能性があるすべてのオブジェクトがレポートされます。

REPORT_GATHER_DATABASE_STATS

レポート作成モードでGATHER_DATABASE_STATSを実行します。このプロシージャでは実際に統計は収集されませんが、GATHER_DATABASE_STATSを起動することで影響を受ける可能性があるすべてのオブジェクトがレポートされます。

REPORT_GATHER_FIXED_OBJ_STATS

レポート作成モードでGATHER_FIXED_OBJ_STATSを実行します。このプロシージャでは実際に統計は収集されませんが、GATHER_FIXED_OBJ_STATSを起動することで影響を受ける可能性があるすべてのオブジェクトがレポートされます。

REPORT_GATHER_AUTO_STATS

レポート作成モードで自動統計収集ジョブを実行します。このプロシージャでは実際に統計は収集されませんが、ジョブを実行することで影響を受ける可能性があるすべてのオブジェクトがレポートされます。

前提条件

このチュートリアルでは、oeスキーマのGATHER_SCHEMA_STATSを実行することで影響を受ける可能性があるオブジェクトのHTMLレポートを生成するものとします。

GATHER_SCHEMA_STATSの実行によって影響を受けるオブジェクトのレポートを作成する手順は次のとおりです。

1. SQL*Plusを起動し、管理者権限でデータベースに接続します。

2. DBMS_STATS.REPORT_GATHER_SCHEMA_STATSファンクションを実行します。
たとえば、SQL*Plusで次のコマンドを実行します。

SET LINES 200 PAGES 0
SET LONG 100000
COLUMN REPORT FORMAT A200

VARIABLE my_report CLOB;
BEGIN
:my_report :=DBMS_STATS.REPORT_GATHER_SCHEMA_STATS(
ownname      => 'OE'       ,
detail_level => 'TYPICAL'  ,
format       => 'HTML'     );
END;
/

次の図は、サンプル・レポートの一部を示しています。

関連項目:

DBMS_STATSの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください

過去の統計収集操作のレポート作成

DBMS_STATS関数を使用して、特定の統計収集操作または特定の日時の間に発生した操作のレポートを作成できます。

表13-7にはファンクションがリストされています。

表13-7 DBMS_STATSレポート作成ファンクション

ファンクション

説明

REPORT_STATS_OPERATIONS

2つの時点間で発生したすべての統計操作のレポートを生成します。自動統計収集の実行のみを含めることで、レポートの範囲を絞り込むことができます。また、プラガブル・データベース(PDB)IDのセットを指定することで、指定されたPDBの統計操作のみのレポートがデータベースで作成されます。

REPORT_SINGLE_STATS_OPERATION

指定された操作のレポートを生成します。オプションで、コンテナ・データベース(CDB)内の特定のPDB IDを指定できます。

前提条件

このチュートリアルでは、次のHTMLレポートを生成するものとします。

- 過去1日以内のすべての統計収集操作

- 最新の統計収集操作

過去1日のすべての操作のレポートを作成する手順は次のとおりです。

1. SQL*Plusを起動し、管理者権限でデータベースに接続します。

2. DBMS_STATS.REPORT_STATS_OPERATIONSファンクションを実行します。
たとえば、次のコマンドを実行します。

SET LINES 200 PAGES 0
SET LONG 100000
COLUMN REPORT FORMAT A200

VARIABLE my_report CLOB;
BEGIN
:my_report := DBMS_STATS.REPORT_STATS_OPERATIONS (
since        => SYSDATE-1
,    until        => SYSDATE
,    detail_level => 'TYPICAL'
,    format       => 'HTML'
);
END;
/

次の図は、サンプル・レポートを示しています。

3. 個々の操作についてDBMS_STATS.REPORT_SINGLE_STATS_OPERATIONファンクションを実行します。
たとえば、次のプログラムを実行して、操作848のレポートを生成します。

BEGIN
:my_report :=DBMS_STATS.REPORT_SINGLE_STATS_OPERATION (
OPID    => 848
,    FORMAT  => 'HTML'
);
END;

次の図は、サンプル・レポートを示しています。

関連項目:

- 統計管理用Cloud Control GUIの詳細は、「オプティマイザ統計管理のグラフィカル・インタフェース」を参照してください

- DBMS_STATSの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください

SQL計画ディレクティブの管理

SQL計画ディレクティブは、データベースによって自動的に管理されます。ディレクティブは、53週間使用されない場合、自動的に消去されます。

DBMS_SPDのプロシージャおよびファンクションを使用してディレクティブを手動で管理できます。

表13-8に、一般的に使用されるプロシージャおよびファンクションの一部を示します。DBMS_SPDパッケージの完全な構文およびセマンティクスは、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

表13-8 DBMS_SPDのプロシージャ

プロシージャ

説明

FLUSH_SQL_PLAN_DIRECTIVE

ディレクティブをメモリーからSYSAUX表領域の永続記憶域に強制的に書き込みます。

DROP_SQL_PLAN_DIRECTIVE

SQL計画ディレクティブを削除します。

前提条件

DBMS_SPDのAPIを実行するには、ADMINISTER SQL MANAGEMENT OBJECT権限が必要です。

前提条件

このチュートリアルでは、次の操作を行うものとします。

- shスキーマのすべてのディレクティブを永続記憶域に書き込みます。

- shスキーマのすべてのディレクティブを削除します。

shスキーマのすべての計画ディレクティブを書き込んでから削除する手順は次のとおりです。

1. SQL*Plusを起動し、管理者権限でデータベースにログインします。

2. SQL計画ディレクティブを強制的にディスクに書き込みます。
たとえば、次のDBMS_SPDプログラムを実行します。

BEGIN
DBMS_SPD.FLUSH_SQL_PLAN_DIRECTIVE;
END;
/

3. データ・ディクショナリを問い合せて、shスキーマの既存のディレクティブに関する情報を確認します。
例13-1では、ディレクティブに関する情報をデータ・ディクショナリに問い合せます。

4. shスキーマの既存のSQL計画ディレクティブを削除します。
次のPL/SQLプログラム・ユニットでは、ID 1484026771529551585を指定してSQL計画ディレクティブを削除します。

BEGIN
DBMS_SPD.DROP_SQL_PLAN_DIRECTIVE ( directive_id => 1484026771529551585 );
END;
/

例13-1 shスキーマのディレクティブの表示

SELECT TO_CHAR(d.DIRECTIVE_ID) dir_id, o.OWNER, o.OBJECT_NAME,
o.SUBOBJECT_NAME col_name, o.OBJECT_TYPE, d.TYPE, d.STATE, d.REASON
FROM   DBA_SQL_PLAN_DIRECTIVES d, DBA_SQL_PLAN_DIR_OBJECTS o
WHERE  d.DIRECTIVE_ID=o.DIRECTIVE_ID
AND    o.OWNER IN ('SH')
ORDER BY 1,2,3,4,5;

DIR_ID              OWN OBJECT_NA COL_NAME   OBJECT  TYPE     STATE      REASON
------------------- --- --------- ---------- ------- -------- ---------- ------------
1484026771529551585  SH CUSTOMERS COUNTRY_ID  COLUMN DYNAMIC_ SUPERSEDED SINGLE TABLE
SAMPLING            CARDINALITY
MISESTIMATE
1484026771529551585  SH CUSTOMERS CUST_STATE_ COLUMN DYNAMIC_ SUPERSEDED SINGLE TABLE
PROVINCE           SAMPLING            CARDINALITY
MISESTIMATE
1484026771529551585  SH CUSTOMERS              TABLE DYNAMIC_ SUPERSEDED SINGLE TABLE
SAMPLING            CARDINALITY
MISESTIMATE

関連項目:

- 「SQL計画ディレクティブ」

- DBA_SQL_PLAN_DIRECTIVESの詳細は、『Oracle Databaseリファレンス』を参照してください。

- DBMS_SPD.FLUSH_SQL_PLAN_DIRECTIVEプロシージャの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

第VI部 オプティマイザの制御

ヒントと初期化パラメータを使用すると、オプティマイザの判断と動作を誘導できます。

この部には次の章が含まれます:

- オプティマイザへの影響

- カーソル共有によるReal-World Performanceの改善

14 オプティマイザへの影響

オプティマイザのデフォルト設定はほとんどの操作に適していますが、すべての操作に適しているわけではありません。

オプティマイザにとって不明な情報が含まれている場合や、特定の種類の文またはワークロードに合うようにオプティマイザをチューニングする必要がある場合もあります。そのような場合は、オプティマイザに与える影響によりパフォーマンスを改善できることがあります。

この章の内容は次のとおりです。

- オプティマイザに影響を与える手法

- 初期化パラメータによるオプティマイザへの影響

- ヒントによるオプティマイザへの影響

オプティマイザに影響を与える手法

SQLプロファイル、SQL計画管理、初期化パラメータおよびヒントなど、様々な手法を使用してオプティマイザに影響を与えることができます。

次の図には、オプティマイザに影響を与える主な手法が示されています。

図14-1 オプティマイザに影響を与える手法

この図の四角形の重なりは、SQL計画管理によって、初期化パラメータとヒントの両方が使用されることを示しています。また、SQLプロファイルにも技術的にはヒントが含まれています。

次の手法を使用してオプティマイザに影響を与えることができます。

- 初期化パラメータ
パラメータは、オプティマイザの多くの種類の動作にデータベース・インスタンスやセッション・レベルで影響を与えます。最も重要なパラメータについては、「初期化パラメータによるオプティマイザへの影響」で説明します。

- ヒント
ヒントは、SQL文でコメント化された命令です。ヒントで広範囲の動作が制御されます。「ヒントによるオプティマイザへの影響」を参照してください。

- DBMS_STATS
このパッケージではオプティマイザ統計を更新および管理します。統計をより正確にすることで、オプティマイザの見積りもより改善されます。

この章では、DBMS_STATSについては扱いません。「オプティマイザ統計の管理: 基本的なトピック」を参照してください。

- SQLプロファイル
SQLプロファイルは、SQL文に固有の補足統計を含むデータベース・オブジェクトです。概念上、SQL文に対するSQLプロファイルの役割は、表または索引に対するオブジェクト・レベルの統計情報の役割と同じです。SQLプロファイルにより、SQLチューニングの間に見つかった最適ではないオプティマイザの見積りを修正できます。

この章では、SQLプロファイルについては扱いません。「SQLプロファイルの管理」を参照してください。

- SQL計画管理とストアド・アウトライン
SQL計画管理は、データベースで既知の計画または確認済の計画のみが使用されるようにオプティマイザで実行計画を自動的に管理する予防的なメカニズムです。

この章では、SQL計画管理については扱いません。「SQL計画ベースラインの管理」を参照してください。

注意:

ストアド・アウトラインは、SQL計画ベースラインとよく似た目的を果たすレガシーな手法です。ストアド・アウトラインのSQL計画ベースラインへの移行方法の詳細は、「ストアド・アウトラインのSQL計画ベースラインへの移行」を参照してください。

場合によっては、複数の手法で同じ動作を最適化します。たとえば、初期化パラメータとヒントの両方を使用してオプティマイザの目標を設定できます。

初期化パラメータによるオプティマイザへの影響

この章では、最適化に影響を与える初期化パラメータ、およびそれらの設定方法について説明します。

この項の内容は次のとおりです。

- オプティマイザの初期化パラメータについて

- オプティマイザ機能の有効化

- オプティマイザの目標の選択

- 適応最適化の制御

オプティマイザの初期化パラメータについて

Oracle Databaseには、オプティマイザ動作に影響を与えることができる様々な初期化パラメータが含まれています。

次の表に、最も重要な初期化パラメータの一部を示します。

表14-1 オプティマイザ動作を制御する初期化パラメータ

初期化パラメータ

説明

CURSOR_SHARING

SQL文のリテラル値をバインド変数に変換します。値を変換するとカーソル共有が改善され、SQL文の実行計画は影響を受けます。オプティマイザは、実際のリテラル値でなくバインド変数の有無に基づいて実行計画を生成します。

FORCEを設定することで、既存のカーソルの共有時、またはカーソル・プランが最適ではない場合に新しいカーソルを作成できます。EXACTに設定すると、同一のテキストを含む文のみで同じカーソルを共有できます。

DB_FILE_MULTIBLOCK_READ_COUNT

全表スキャンまたは高速全索引スキャン時に単一I/Oで読み取られるブロックの個数を指定します。オプティマイザは、このパラメータの値を使用して、全表スキャンと高速全索引スキャンのコストを計算します。値が大きいほど全表スキャンのコストは低くなり、結果として、オプティマイザは索引スキャンより全表スキャンを選択することになります。

このパラメータのデフォルト値は、データベースを効果的に実行できる最大I/Oサイズに対応しています。この値は、プラットフォームに依存し、ほとんどのプラットフォームで1MBになります。このパラメータはブロック単位で表されるため、効率的に実行できる最大I/Oサイズを標準ブロック・サイズで除算した値に設定されます。セッション数が非常に大きい場合は、表スキャン・バッファが多すぎてバッファ・キャッシュがあふれないように、マルチブロック読取りカウントの値が減らされます。

OPTIMIZER_ADAPTIVE_REPORTING_ONLY

自動再最適化と適応計画のレポート作成モードを制御します(「適応問合せ計画」を参照)。デフォルトでは、レポート作成モードはオフ(false)のため、適応最適化が有効になっています。

trueに設定した場合は、レポート作成のみのモードで適応最適化が実行されます。この場合は、データベースで適応最適化に必要な情報が収集されるものの、計画変更のアクションは発生しません。たとえば、適応計画では常にデフォルトの計画が選択されますが、パラメータがfalseに設定されている場合は、データベースで使用する計画に関する情報が収集されます。DBMS_XPLAN.DISPLAY_CURSORを使用することでレポートを表示できます。

OPTIMIZER_MODE

データベース・インスタンスの起動時にオプティマイザ・モードを設定します。ALL_ROWS、FIRST_ROWS_nおよびFIRST_ROWSの値が使用可能です。

OPTIMIZER_INDEX_CACHING

ネステッド・ループとともに索引プローブのコスト分析を制御します。値0-100の範囲はバッファ・キャッシュ内の索引ブロックの割合を示し、これにより、ネステッド・ループおよびINリスト・イテレータの索引キャッシュに関するオプティマイザの前提条件が変更されます。この値が100の場合は、索引ブロックの100%がバッファ・キャッシュに見つかる可能性があるため、それに応じてオプティマイザでは索引プローブまたはネステッド・ループのコストを調整します。実行計画は索引キャッシュを優先して変更される可能性があるため、このパラメータの設定時には注意を払います。

OPTIMIZER_INDEX_COST_ADJ

索引プローブのコストを調整します。値の範囲は、1から10000です。デフォルト値100の場合、オプティマイザは、標準のコスト・モデルに基づいて索引をアクセス・パスとして評価します。値10は、索引アクセス・パスの標準コストの1/10が索引アクセス・パスのコストであることを意味します。

OPTIMIZER_INMEMORY_AWARE

このパラメータでは、インメモリー、表拡張、ブルーム・フィルタなどのコスト・モデルを含むすべてのインメモリー・オプティマイザ機能を有効(TRUE)または無効(FALSE)にします。パラメータをFALSEに設定すると、オプティマイザはSQL文の最適化中に表のインメモリー・プロパティを無視します。

OPTIMIZER_USE_INVISIBLE_INDEXES

非表示の索引の使用を有効化または無効化します。

RESULT_CACHE_MODE

データベースで使用するSQL問合せ結果キャッシュの対象を、すべての問合せにするのか、または結果キャッシュ・ヒントで注釈付けされた問合せのみにするのかを制御します。MANUAL(デフォルト)に設定する場合は、RESULT_CACHEヒントを使用して、特定の結果がキャッシュ内に格納されるように指定する必要があります。FORCEに設定すると、すべての結果がキャッシュに格納されます。

このパラメータを設定する場合は、結果キャッシュでPL/SQLファンクションを処理する方法について検討します。データベースでは、PL/SQLファンクションのデータ依存性を追跡するのと同じメカニズムを使用して結果キャッシュ内の問合せ結果が無効化されますが、それ以外の場合は、PL/SQLファンクションを含む問合せをキャッシュできます。PL/SQLファンクション結果キャッシュの無効化では全種類の依存性(順序、SYSDATE、SYS_CONTEXTおよびパッケージ変数など)が追跡されるわけではないため、このようなファンクションをコールする問合せで無差別に問合せ結果キャッシュを使用すると、結果が変更され、間違った結果になる可能性があります。したがって、結果キャッシュの有効化を選択する場合、特にRESULT_CACHE_MODEをFORCEに設定する場合は正当性やパフォーマンスを考慮に入れます。

RESULT_CACHE_MAX_SIZE

結果キャッシュに割り当てられているメモリーを変更します。このパラメータを0に設定すると、結果キャッシュが無効化されます。このパラメータの値は、指定された値を超えない範囲で32KBの最大倍数まで丸められます。丸め値が0の場合はこの機能が無効化されます。

RESULT_CACHE_MAX_RESULT

すべての単一の結果で使用可能なキャッシュ・メモリーの最大値を指定します。デフォルト値は5%ですが、1から100の任意のパーセント値を指定できます。

RESULT_CACHE_REMOTE_EXPIRATION

リモート・データベース・オブジェクトに依存する結果の有効時間(分単位)を指定します。デフォルトは0です。これは、データベースで、リモート・オブジェクトを使用して結果がキャッシュされないことを示します。このパラメータを0以外の値にすると、結果内で参照される表をリモート・データベースが変更した場合などに、失効した回答が生成される可能性があります。

STAR_TRANSFORMATION_ENABLED

オプティマイザはスター・クエリーのスター型変換のコストを計算できます(trueの場合)。スター型変換により、様々なファクト表の列でビットマップ索引が結合されます。『Oracle Databaseデータ・ウェアハウス・ガイド』を参照してください。

関連項目:

- 前述の初期化パラメータの詳細は、『Oracle Databaseリファレンス』を参照してください

- 問合せ結果キャッシュのチューニング方法の詳細は、『Oracle Databaseパフォーマンス・チューニング・ガイド』を参照してください

オプティマイザ機能の有効化

OPTIMIZER_FEATURES_ENABLE初期化パラメータ(またはヒント)は一連のオプティマイザ関連機能をデータベース・リリースに応じて制御します。

パラメータによって、11.2.0.4または12.1.0.2など、リリース番号に対応する有効な文字列値のいずれかを受け入れます。このパラメータを使用して、データベースのアップグレード後もオプティマイザの以前の動作を保持できます。たとえば、Oracle Database 11gリリース2 (11.2.0.4)からOracle Database 12c リリース1 (12.1.0.2)にアップグレードすると、OPTIMIZER_FEATURES_ENABLEパラメータのデフォルト値は11.2.0.4から12.1.0.2に変更されます。

下位互換性のため、新規リリースの新しいオプティマイザ機能という理由で実行計画の変更を必要とはしない場合もあります。そのような場合は、OPTIMIZER_FEATURES_ENABLEを以前のバージョンに設定できます。新しいリリースにアップグレードする場合や、新しいリリースの機能を有効化する必要がある場合は、OPTIMIZER_FEATURES_ENABLE初期化パラメータを明示的に設定する必要はありません。

注意:

OPTIMIZER_FEATURES_ENABLE初期化パラメータを以前のリリースに明示的に設定することはお薦めしません。実行計画の変更から生じる可能性があるSQLパフォーマンスの低下を回避するには、かわりに、SQL計画管理の使用を検討してください。「SQL計画ベースラインの管理」を参照してください。

前提条件

このチュートリアルでは、次のことが前提となっています。

- 最近、データベースをOracle Database 11g リリース2 (11.2.0.4)からOracle Database 12c リリース1 (12.1.0.2)にアップグレードしました。

- 以前のリリースのオプティマイザ動作を保持したいと思っています。

特定のリリースの問合せオプティマイザ機能を有効化する手順は次のとおりです。

1. SQL*Plusを起動し、適切な権限でデータベースにログインします。

2. 現在のオプティマイザ機能設定を問い合せます。
たとえば、次のSQL*Plusコマンドを実行します。

SQL> SHOW PARAMETER optimizer_features_enable

NAME                                 TYPE        VALUE
------------------------------------ ----------- --------
optimizer_features_enable            string      11.2.0.4

3. インスタンスまたはセッション・レベルでオプティマイザ機能設定を設定します。
たとえば、次のSQL文を実行してオプティマイザ・バージョンを12.1.0.2に設定します。

SQL> ALTER SYSTEM SET OPTIMIZER_FEATURES_ENABLE='12.1.0.2';

この文では、Oracle Database 12c リリース1 (12.1.0.2)に存在するオプティマイザ機能をリストアします。

関連項目:

OPTIMIZER_FEATURES_ENABLEを異なるリリースの値に設定する際に有効化されるオプティマイザ機能の詳細は、『Oracle Databaseリファレンス』を参照してください。

オプティマイザの目標の選択

オプティマイザの目標は、オプティマイザによるリソース使用を優先順位付けしたものです。

OPTIMIZER_MODE初期化パラメータを使用して、次のオプティマイザの目標を設定できます。

- 最高のスループット(デフォルト)
OPTIMIZER_MODE値をALL_ROWSに設定すると、データベースでは、文がアクセスしたすべての行の処理に必要な最小限のリソース量が使用されます。

Oracle Reportsなどのバッチ・アプリケーションでは、最高のスループットを目標に最適化します。通常、バッチ・アプリケーションでスループットがより重要になるのは、ユーザーが、アプリケーションの完了に必要な時間にのみ関心を持っているためです。アプリケーションの実行中に、ユーザーは個々の文の結果を検証しないため、レスポンス時間はそれほど重要ではありません。

- 最短のレスポンス時間
OPTIMIZER_MODE値をFIRST_ROWS_nに設定すると、データベースでは、最初のn行を戻す最短のレスポンス時間を目標に最適化されます。ここでのnは1、10、100または1000です。

Oracle FormsまたはSQL*Plusの対話型アプリケーションでは、レスポンス時間に対して最適化します。通常、レスポンス時間が重要なのは、文がアクセスした最初の行または数行を確認するために対話型ユーザーが待機しているためです。

前提条件

このチュートリアルでは、次のことが前提となっています。

- プライマリ・アプリケーションが対話型であるため、データベース・インスタンスにオプティマイザの目標を設定してレスポンス時間を最小化します。

- 現行のセッションの場合のみ、レポート作成を実行し、スループットに対して最適化します。

特定のリリースの問合せオプティマイザ機能を有効化する手順は次のとおりです。

1. 適切な権限でSQL*Plusをデータベースに接続し、現行のオプティマイザ・モードを問い合せます。
たとえば、次のSQL*Plusコマンドを実行します。

dba1@PROD> SHOW PARAMETER OPTIMIZER_MODE

NAME                                 TYPE        VALUE
------------------------------------ ----------- --------
optimizer_mode                       string      ALL_ROWS

2. インスタンス・レベルで、レスポンス時間に対して最適化します。
たとえば、次のSQL文を実行して、最初の10行をできるかぎり迅速に取得するようにシステムを構成します。

SQL> ALTER SYSTEM SET OPTIMIZER_MODE='FIRST_ROWS_10';

3. セッション・レベルでのみ、レポート作成を実行する前にスループットに対して最適化します。
たとえば、次のSQL文を実行して、スループットに対して最適化するようにこのセッションのみを構成します。

SQL> ALTER SESSION SET OPTIMIZER_MODE='ALL_ROWS';

関連項目:

OPTIMIZER_MODE初期化パラメータの詳細は、Oracle Databaseリファレンスを参照してください

適応最適化の制御

Oracle Databaseの適応問合せ最適化は、実行時に収集された統計に基づいてオプティマイザで実行計画を採用するためのプロセスです。

適応最適化は次の条件で有効化されます。

- OPTIMIZER_FEATURES_ENABLE初期化パラメータが12.1.0.1以降に設定されている。

- OPTIMIZER_ADAPTIVE_REPORTING_ONLY初期化パラメータがfalse(デフォルト)に設定されている。

OPTIMIZER_ADAPTIVE_REPORTING_ONLYがtrueに設定されている場合は、レポート作成のみのモードで適応最適化が実行されます。この場合は、データベースで適応最適化に必要な情報が収集されるものの、計画は変更されません。適応計画では常にデフォルトの計画が選択されますが、パラメータがfalseに設定されているかのように実行に関する情報がデータベースで収集されます。

前提条件

このチュートリアルでは、次のことが前提となっています。

- OPTIMIZER_FEATURES_ENABLE初期化パラメータが12.1.0.1以降に設定されている。

- OPTIMIZER_ADAPTIVE_REPORTING_ONLY初期化パラメータがfalse(デフォルト)に設定されている。

- テスト目的で適応最適化を無効化し、データベースでレポートのみが生成されるようにします。

適応最適化を無効化し、レポートを表示する手順は次のとおりです。

1. SYSTEMとしてSQL*Plusをデータベースに接続し、現行の設定を問い合せます。
たとえば、次のSQL*Plusコマンドを実行します。

SHOW PARAMETER OPTIMIZER_ADAPTIVE_REPORTING_ONLY

NAME                                 TYPE        VALUE
------------------------------------ ----------- -----
optimizer_adaptive_reporting_only    boolean     FALSE

2. セッション・レベルで、OPTIMIZER_ADAPTIVE_REPORTING_ONLY初期化パラメータをtrueに設定します。
たとえば、SQL*Plusで次のSQL文を実行します。

ALTER SESSION SET OPTIMIZER_ADAPTIVE_REPORTING_ONLY=true;

3. 問合せを実行します。

4. DBMS_XPLAN.DISPLAY_CURSORを実行して、レポートを表示します。

注意:

DBMS_XPLAN.DISPLAY_CURSORに渡す引数の形式には、+REPORTパラメータを含める必要があります。このパラメータが設定されると、自動最適化が有効な場合、オプティマイザが選択する計画がレポートに表示されます。

関連項目:

- 適応問合せ最適化について

- OPTIMIZER_ADAPTIVE_REPORTING_ONLY初期化パラメータの詳細は、『Oracle Databaseリファレンス』を参照してください。

- DBMS_XPLAN.DISPLAY_CURSORのファンクションの+REPORTパラメータの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

ヒントによるオプティマイザへの影響

オプティマイザ・ヒントは、命令をオプティマイザに渡すSQL文の特別なコメントです。オプティマイザは、なんらかの状況に妨害されないかぎり、ヒントを使用して文の実行計画を選択します。

この項の内容は次のとおりです。

- オプティマイザ・ヒントについて

- 結合順序のヒントのガイドライン

注意:

すべてのSQLヒントの完全な詳細は、『Oracle Database SQL言語リファレンス』を参照してください

オプティマイザ・ヒントについて

ヒントは、オプティマイザ・モード、問合せの転送、アクセス・パス、結合順序および結合方法に影響を与えるために使用します。

たとえば、次の図には、ヒントを使用してオプティマイザに特定の索引を使用するよう指示する方法が示されています。

図14-2 オプティマイザ・ヒント

ヒントの利点は、通常はオプティマイザによって行われる決定をユーザーが決定できることです。テスト環境では、特定のアクセス・パスのパフォーマンスをテストする場合にヒントが役に立ちます。たとえば、図14-2のように、ある問合せに対しては、特定の索引を選択する方がよいとわかっている場合もあります。この場合、ヒントによってオプティマイザがより適切な計画を生成できるようになる可能性があります。

ヒントの短所は、管理、チェックおよび制御が必要な追加のコードであることです。ヒントが導入されたのはOracle7からですが、当時は、オプティマイザによって生成された計画が最善ではない場合にユーザーが取れる手段はほとんどありませんでした。データベースやホスト環境内の変更によってヒントが非推奨となるか、負の結果をもたらす可能性があるため、ヒントを使用したテストが望ましいものの、他の手法を使用して実行計画を管理することがあります。

オプティマイザでは解決されないパフォーマンスの問題に対処するために、SQLチューニング・アドバイザ、SQL計画管理、SQLパフォーマンス・アナライザなどの複数のツールが用意されています。これらのツールにはデータやデータベース環境の変更に対応した新しいソリューションが用意されているため、ヒントのかわりにこれらを使用することを強くお薦めします。

関連項目:

機能カテゴリ別の最も一般的なヒントは、『Oracle Database SQL言語リファレンス』を参照してください。

ヒントの型

ヒントを表、問合せブロックおよび文に使用できます。

ヒントは次の型に分類されます。

- 単一表
単一表ヒントは、1つの表またはビュー上で指定します。単一表ヒントの例として、INDEXおよびUSE_NLがあります。次の文では単一表ヒントが使用されています。

SELECT /*+ INDEX (employees emp_department_ix)*/ employee_id, department_id
FROM   employees
WHERE  department_id > 50;

- 複数表
複数表ヒントは単一表ヒントに類似していますが、ヒントで複数の表またはビューを指定できる点が異なります。複数表ヒントの例には、LEADINGがあります。次の文では複数表ヒントが使用されています。

SELECT /*+ LEADING(e j) */ *
FROM   employees e, departments d, job_history j
WHERE  e.department_id = d.department_id
AND    e.hire_date = j.start_date;

注意:

USE_NL(table1 table2)が複数表ヒントとみなされていないのは、USE_NL(table1)とUSE_NL(table2)のショートカットであるためです。

- 問合せブロック
問合せブロック・ヒントでは、単一の問合せブロックが処理されます。問合せブロック・ヒントの例として、STAR_TRANSFORMATIONおよびUNNESTがあります。次の文では問合せブロック・ヒントが使用されています。

SELECT /*+ STAR_TRANSFORMATION */ s.time_id, s.prod_id, s.channel_id
FROM   sales s, times t, products p, channels c
WHERE s.time_id = t.time_id AND s.prod_id = p.prod_id
AND s.channel_id = c.channel_id AND c.channel_desc = 'Tele Sales';

- 文
文ヒントはSQL文全体に適用されます。文ヒントの例には、ALL_ROWSがあります。次の文では文ヒントが使用されています。

SELECT /*+ ALL_ROWS */ * FROM sales;

ヒントの有効範囲

ヒントを指定すると、ヒントに表示される文ブロックのみが最適化され、インスタンス・レベルまたはセッション・レベルのすべてのパラメータが上書きされます。

文ブロックは次のいずれかです。

- 単純なMERGE、SELECT、INSERT、UPDATEまたはDELETE文

- 複合文の親文または副問合せ

- 集合演算子(UNION、MINUS、INTERSECT)を使用した問合せの一部

例14-1 集合演算子を使用した問合せ

次の問合せは、2つのコンポーネント問合せとUNION演算子で構成されます。

SELECT /*+ FIRST_ROWS(10) */ prod_id, time_id FROM 2010_sales
UNION ALL
SELECT /*+ ALL_ROWS */ prod_id, time_id FROM current_year_sales;

前述の文には2つのブロックがあり、それぞれが各コンポーネント問合せに対応しています。最初のコンポーネント問合せのヒントはその最適化のみに適用され、2番目のコンポーネント問合せの最適化には適用されません。たとえば、2015年の第1週に現行年度と昨年度の売上を問い合せるとします。昨年度(2014)の売上の問合せにはFIRST_ROWS(10)を適用し、今年度(2015)の売上の問合せにはALL_ROWSヒントを適用します。

関連項目:

ヒントの概要は、『Oracle Database SQL言語リファレンス』を参照してください

ヒントの考慮事項

SQLコメント内のヒントは囲む必要があります。ヒント・コメントは、SQL文ブロックの最初のキーワードのすぐ後ろに続ける必要があります。スラッシュスター(/*)またはダッシュのペア(--)のいずれかのコメント・スタイルを使用できます。次のフラグメントのように、プラス記号(+)ヒント・デリミタは、コメント・デリミタのすぐ後に続く必要があります。

SELECT /*+ hint_text */ ...

データベースでは、間違って指定されたヒントは無視されます。また、矛盾したヒントの組合せは、たとえそれらが適切に指定されたとしてもデータベースでは無視されます。あるヒントが間違って指定されたものの、同じコメントのヒントが適切に指定されている場合は、データベースで適切なヒントとみなされます。

注意:

データベースでは、無視したヒントに対してエラー・メッセージは発行されません。

文ブロックでは、ヒントを含むコメントは1つしか持つことができませんが、空白区切りのヒントは多数含むことができます。たとえば、複合問合せには複数の表結合が含まれることがあります。指定された表のINDEXヒントのみを指定する場合は、オプティマイザで残りのアクセス・パスと対応する結合方法を決定する必要があります。オプティマイザがINDEXヒントを使用しないことがあるのは、結合方法とアクセス・パスによってそれが妨げられるためです。例14-2では、複数のヒントを使用して正確な結合順序が指定されています。

例14-2 複数のヒント

SELECT   /*+ LEADING(e2 e1) USE_NL(e1) INDEX(e1 emp_emp_id_pk)
USE_MERGE(j) FULL(j) */
e1.first_name, e1.last_name, j.job_id, sum(e2.salary) total_sal
FROM     employees e1, employees e2, job_history j
WHERE    e1.employee_id = e2.manager_id
AND      e1.employee_id = j.employee_id
AND      e1.hire_date = j.start_date
GROUP BY e1.first_name, e1.last_name, j.job_id
ORDER BY total_sal;

関連項目:

コメントおよびヒントの構文ルールの詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

結合順序のヒントのガイドライン

結合順序は、SQL文のパフォーマンスに大きな影響を与えることがあります。場合によっては、結果に影響を及ぼさない行にはアクセスしないように、SQL文で結合順序のヒントを指定することができます。

結合における駆動表は、その他の表が結合された表です。通常、駆動表には、表内を最も高い割合で排除するフィルタ条件が含まれています。

次のガイドラインを考慮してください。

- 索引によって、要求された行がより効率的に取得される場合は、全表スキャンを実行しないでください。

- 少数の行をフェッチする索引を使用できる場合には、駆動表から多数の行をフェッチする索引を使用するようなことは避けてください。

- 結合順序の後ろへ行くほど結合する行が少なくなるように結合順序を選択してください。

次の例は、結合順序を効果的にチューニングする方法を示しています。

SELECT *
FROM   taba a, tabb b, tabc c
WHERE  a.acol BETWEEN   100 AND   200

AND    b.bcol BETWEEN 10000 AND 20000
AND    c.ccol BETWEEN 10000 AND 20000
AND    a.key1 = b.key1
AND    a.key2 = c.key2;

1. 駆動表と駆動索引(存在する場合)を選択します。
前述の例における最初の3つの条件はそれぞれ、1つの表に適用されるフィルタ条件です。最後の2つの条件は結合条件です。

フィルタ条件は、駆動表と駆動索引の選択を左右します。通常、駆動表には、行を最も高い割合で排除するフィルタ条件が含まれています。この例では、100から200の範囲はacolの範囲に比べて狭く、10000から20000の範囲は相対的に大きいため、tabaは駆動表であり、他はすべて同じです。

ネステッド・ループ結合の場合、結合索引を介して結合します。この結合索引は、主キーまたは外部キーに付けられているもので、その表を結合ツリー内のそれより前にある表に結び付けるために使用します。駆動表を除いて、非結合条件にこの結合索引を使用することはほとんどありません。そのため、tabaを駆動表として選択すると、b.key1とc.key2の索引を使用してtabbとtabcをそれぞれ駆動します。

2. 未使用の最適なフィルタを最初に駆動する最適な結合順序を選択します。
最適な未使用フィルタを持つ表に先に結合することで、その後の結合の作業を削減できます。したがって、bcol BETWEEN ...がccol BETWEEN ...よりも限定的な(行をより高い比率で排除する)場合は、tabbをtabcよりも前に結合すると、最後の結合が容易になります(行数が少なくなります)。

3. ORDEREDまたはSTARヒントを使用して、結合順序を強制的に設定できます。

関連項目:

OPTIMIZER_MODEの詳細は、『Oracle Databaseリファレンス』を参照してください

15 カーソル共有によるReal-World Performanceの改善

この章の内容は次のとおりです。

- カーソル共有の概要

- CURSOR_SHARING初期化パラメータ

- 適応カーソル共有

- カーソル共有のためのReal-World Performanceのガイドライン

カーソル共有の概要

Oracle Databaseでは、共有プール内のプライベートSQL領域へのポインタであるカーソルを共有できます。カーソル共有により、データベース・アプリケーションのパフォーマンスを大幅に向上させることができます。

この項の内容は次のとおりです。

- カーソルについて

- カーソルおよび解析について

- リテラルおよびバインド変数について

カーソルについて

プライベートSQL領域には、解析済のSQL文に関する情報と、処理に使用するその他のセッション固有の情報が保持されます。

サーバー・プロセスでSQLまたはPL/SQLのコードが実行される場合、プロセスではプライベートSQL領域を使用してバインド変数値、問合せ実行状態情報、問合せ実行作業領域が格納されます。文の各実行におけるプライベートSQL領域は共有されず、異なる値やデータが含まれている可能性があります。

カーソルは、特定のプライベートSQL領域の名前またはハンドルです。カーソルには、バインド変数の値や結果セットなどのセッション固有の状態の情報が含まれています。

次の図に示すように、カーソルはクライアントから見るとポインタ、サーバーから見ると状態のようなものです。カーソルはプライベートSQL領域と密接に関連しているため、これらの用語は同じ意味で使用されることがあります。

図15-1 カーソル

プライベートSQL領域と共有SQL領域

プライベートSQL領域のカーソルは、ライブラリ・キャッシュの共有SQL領域を指します。セッション状態の情報を含むプライベートSQL領域とは異なり、共有SQL領域には、文の解析ツリーおよび実行計画が含まれています。

たとえば、SELECT * FROM employeesを実行すると、計画および解析ツリーはある共有SQL領域に格納されます。構文的にも意味的にも異なるSELECT * FROM departmentsを実行すると、計画および解析ツリーは別の共有SQL領域に格納されます。

同じセッションまたは異なるセッションにある複数のプライベートSQL領域は、単一の共有SQL領域を参照でき、これはカーソル共有と呼ばれる現象です。たとえば、あるセッションにおけるSELECT * FROM employeesの実行と、別のセッションにおける(同じ表にアクセスする)SELECT * FROM employeesの実行では、同じ解析ツリーおよび計画を使用できます。複数の文によってアクセスされる共有SQL領域は、共有カーソルと呼ばれます。

図15-2 カーソル共有

Oracle Databaseでは、次の手順を使用して、SQL文またはPL/SQLブロックを発行する際に、ライブラリ・キャッシュにテキスト的に同じ文が存在するかどうかを自動的に確認します。

1. 文のテキストがハッシュされます。

2. 共有プール内の既存のSQL文で、一致するハッシュ値が検索されます。次のオプションが可能です。

- 一致するハッシュ値が存在しない場合。
この場合、SQL文は共有プール内に現在存在せず、ハード解析が実行されます。これにより共有プール・チェックが終了されます。

- 一致するハッシュ値が存在する場合。
この場合、データベースは、次の手順であるテキスト一致に進みます。

3. 一致する文のテキストとハッシュ文のテキストが同一であるかどうか比較されます。次のオプションが可能です。

- テキスト一致が失敗した場合。
この場合、テキスト一致プロセスは停止され、ハード解析が実行されます。

- テキスト一致が成功した場合。
この場合、データベースは次の手順に進みます。「親カーソルと子カーソル」で説明されているように、既存の親カーソルをSQLで共有できるかどうかを判別します。

テキスト一致が発生するには、SQL文またはPL/SQLブロックのテキストが空白、大文字小文字の区別、コメントも含めて完全に同一である必要があります。たとえば、次の文は同じ共有SQL領域を使用できません。

SELECT * FROM employees;
SELECT * FROM Employees;
SELECT *  FROM employees;

通常は、リテラルのみ異なるSQL文は同じ共有SQL領域を使用できません。たとえば、次の文は同じSQL領域に変換されません。

SELECT count(1) FROM employees WHERE manager_id = 121;
SELECT count(1) FROM employees WHERE manager_id = 247;

このルールの唯一の例外は、CURSOR_SHARINGパラメータがFORCEに設定されている場合で、このケースでは類似した文でSQL領域を共有できます。CURSOR_SHARINGを使用する場合のコストについては、「CURSOR_SHARING = FORCEを永続的な修正として使用しない」で説明します。

関連項目:

CURSOR_SHARING初期化パラメータの詳細は、『Oracle Databaseリファレンス』を参照してください。

親カーソルと子カーソル

すべての解析済のSQL文には、1つの親カーソルと1つ以上の子カーソルがあります。親カーソルにはSQL文のテキストが格納されます。2つの文のテキストが同一である場合、これらの文は同じ親カーソルを共有します。しかし、テキストが異なる場合、データベースは別の親カーソルを作成します。

例15-1 親カーソル

この例で、最初の2つの文は構文的に異なりますが(文字“c”が最初の文では小文字で、2番目の文では大文字です)、意味的には同じです。構文的に異なるため、これらの文の親カーソルは異なります。3番目の文は最初の文と構文的には同じですが(小文字の“c”)、別のスキーマのcustomers表を参照しているため、意味的には異なります。構文的に同じであるため、3番目の文は最初の文と親カーソルを共有できます。

SQL> CONNECT oe@inst1
Enter password: *******
Connected.
SQL> SELECT COUNT(*) FROM customers;

COUNT(*)
----------
319

SQL> SELECT COUNT(*) FROM Customers;

COUNT(*)
----------
319

SQL> CONNECT sh@inst1
Enter password:  *******
Connected.
SQL> SELECT COUNT(*) FROM customers;

COUNT(*)
----------
155500

次の問合せのV$SQLは、2つの親を示しています。SQL IDが8h916vv2yw400の文(小文字の“c”を含む文)には、1つの親カーソルと2つの子カーソル(子0と子1)があります。SQL IDが5rn2uxjtpz0wdの文(大文字の“c”を含む文)には、異なる親カーソルと1つの子カーソル(子0)のみがあります。

SQL> CONNECT SYSTEM@inst1
Enter password:  *******
Connected.

SQL> COL SQL_TEXT FORMAT a30
SQL> COL CHILD# FORMAT 99999
SQL> COL EXEC FORMAT 9999
SQL> COL SCHEMA FORMAT a6
SQL> SELECT SQL_ID, PARSING_SCHEMA_NAME AS SCHEMA, SQL_TEXT,
2  CHILD_NUMBER AS CHILD#, EXECUTIONS AS EXEC FROM V$SQL
3  WHERE SQL_TEXT LIKE '%ustom%' AND SQL_TEXT NOT LIKE '%SQL_TEXT%' ORDER BY SQL_ID;

SQL_ID        SCHEMA SQL_TEXT                       CHILD# EXEC
------------- ------ ------------------------------ ------ -----
5rn2uxjtpz0wd OE     SELECT COUNT(*) FROM Customers    0     1
8h916vv2yw400 OE     SELECT COUNT(*) FROM customers    0     1
8h916vv2yw400 SH     SELECT COUNT(*) FROM customers    1     1

親カーソルおよびV$SQLAREA

V$SQLAREAビューには、すべての親カーソルに対して1つの行が含まれています。

次の例で、V$SQLAREAの問合せは、それぞれが異なるSQL_IDで識別される2つの親カーソルを示しています。VERSION_COUNTは子カーソルの数を示します。

COL SQL_TEXT FORMAT a30
SELECT SQL_TEXT, SQL_ID, VERSION_COUNT, HASH_VALUE
FROM   V$SQLAREA
WHERE  SQL_TEXT LIKE '%mployee%'
AND    SQL_TEXT NOT LIKE '%SQL_TEXT%';

SQL_TEXT                       SQL_ID        VERSION_COUNT HASH_VALUE
------------------------------ ------------- ------------- ----------
SELECT * FROM Employees        5bzhzpaa0wy9m             1 2483976499
SELECT * FROM employees        4959aapufrm1k             2 1961610290

前述の出力で、SELECT * FROM employeesでのVERSION_COUNTの2は、複数の子カーソルを示しています。文が2つの異なるオブジェクトに対して実行されたため、2つの子カーソルが必要です。これに対して、文SELECT * FROM Employees (大文字の"E")が1回実行されると、親カーソルは1つ、子カーソルは1つ(VERSION_COUNTが1)となります。

子カーソルおよびV$SQL

すべての親カーソルには1つ以上の子カーソルがあります。子カーソルには、実行計画、バインド変数、問合せで参照されるオブジェクトに関するメタデータ、オプティマイザ環境およびその他の情報が含まれています。親カーソルとは異なり、子カーソルにはSQL文のテキストは格納されません。

文で親カーソルを再利用できる場合、既存の子カーソルを再利用できるかどうかがチェックされます。次のような複数のチェックが実行されます。

- 発行された文で参照されたオブジェクトは、共有プール内の文によって参照されたオブジェクトと比較され、それらがすべて同一であるかどうかが確認されます。
SQL文やPL/SQLブロック内でスキーマ・オブジェクトを参照する際には、同じスキーマ内の同じオブジェクトである必要があります。たとえば、2人のユーザーが次のSQL文を発行し、各ユーザーに独自のemployees表がある場合、次の文はユーザーごとに異なるemployees表を参照するので、この文は同一とみなされません。

SELECT * FROM employees;

- オプティマイザ・モードが同一であるかどうかが判定されます。
たとえば、SQL文は同じオプティマイザの目標を使用して最適化する必要があります(「オプティマイザの目標の選択」を参照)。

例15-2 複数の子カーソル

V$SQLは、現在ライブラリ・キャッシュに存在する文を示しています。次の例に示すように、すべての子カーソルに対して1つの行が含まれています。

SELECT SQL_TEXT, SQL_ID, USERNAME AS USR, CHILD_NUMBER AS CHILD#,
HASH_VALUE, PLAN_HASH_VALUE AS PLAN_HASHV
FROM   V$SQL s, DBA_USERS d
WHERE  SQL_TEXT LIKE '%mployee%'
AND    SQL_TEXT NOT LIKE '%SQL_TEXT%'
AND    d.USER_ID = s.PARSING_USER_ID;

SQL_TEXT                SQL_ID        USR CHILD# HASH_VALUE PLAN_HASHV
----------------------- ------------- --- ------ ---------- ----------
SELECT * FROM Employees 5bzhzpaa0wy9m  HR      0 2483976499 1445457117
SELECT * FROM employees 4959aapufrm1k  HR      0 1961610290 1445457117
SELECT * FROM employees 4959aapufrm1k  SH      1 1961610290 1445457117

前述の結果では、下の2つの文は、SQL_IDが同じでも、CHILD#が異なります(0と1)。つまり、これらの文の親カーソルは同じで、子カーソルは異なります。これに対して、SQL_IDが5bzhzpaa0wy9mの文には、1つの親カーソルと1つの子カーソル(CHILD#が0)があります。PLAN_HASH_VALUE列が同一の値で示されているように、3つのすべてのSQL文では、同じ実行計画が使用されています。

カーソルの不一致およびV$SQL_SHARED_CURSOR

親カーソルに複数の子カーソルがある場合、V$SQL_SHARED_CURSORビューは、カーソルが共有されなかった理由に関する情報を提供します。複数のタイプの非互換性について、TRANSLATION_MISMATCH列では値YまたはNで不一致を示します。

例15-3 変換の不一致

この例で、TRANSLATION_MISMATCH列は、2つの文(SELECT * FROM employees)が異なるオブジェクトを参照したことを示しており、最後の文でTRANSLATION_MISMATCHの値がYになります。共有できなかったため、CHILD_NUMBERが0と1で示されているように、それぞれの文には別の子カーソルがあります。

SELECT S.SQL_TEXT, S.CHILD_NUMBER, s.CHILD_ADDRESS,
C.TRANSLATION_MISMATCH
FROM   V$SQL S, V$SQL_SHARED_CURSOR C
WHERE  SQL_TEXT LIKE '%employee%'
AND    SQL_TEXT NOT LIKE '%SQL_TEXT%'
AND S.CHILD_ADDRESS = C.CHILD_ADDRESS;

SQL_TEXT                       CHILD_NUMBER    CHILD_ADDRESS T
------------------------------ ------------ ---------------- -
SELECT * FROM employees                   0 0000000081EE8690 N
SELECT * FROM employees                   1 0000000081F22508 Y

カーソルおよび解析について

アプリケーションが文を発行し、Oracle Databaseがカーソルを再利用できない場合、新しく実行可能なバージョンのアプリケーション・コードを作成する必要があります。この操作はハード解析と呼ばれています。

ソフト解析はハード解析ではない解析で、データベースが既存のコードを再利用できる場合に発生します。ソフト解析には、ハード解析よりもリソース集中型ではないものがあります。たとえば、文の親カーソルがすでに存在する場合、Oracle Databaseは、様々な最適化を実行し、共有SQL領域に子カーソルを格納できます。しかし、親カーソルが存在しない場合、Oracle Databaseは、共有SQL領域に親カーソルも格納する必要があり、追加のメモリー・オーバーヘッドが作成されます。

実質的に、ハード解析では文を実行する前に再コンパイルします。すべての実行前にSQL文をハード解析することは、すべての実行前にCプログラムを再コンパイルすることに似ています。ハード解析では次のような操作を実行します。

- SQL文の構文のチェック

- SQL文のセマンティクスのチェック

- 文を発行するユーザーのアクセス権のチェック

- 実行計画の作成

- データ・ディクショナリをチェックするための、ライブラリ・キャッシュおよびデータ・ディクショナリ・キャッシュへの多くのアクセス

ハード解析の特にリソース集中型の側面は、データ・ディクショナリをチェックするために、ライブラリ・キャッシュおよびデータ・ディクショナリ・キャッシュに何度もアクセスすることです。データベースはこれらの領域にアクセスするとき、チェック中に定義が変更されないように、必要なオブジェクト上にラッチと呼ばれるシリアライズ・デバイスを使用します。ラッチの競合が発生すると、文の実行時間が長くなり、同時実行性が低下します。

前述のすべての理由で、ハード解析のCPUおよびメモリーのオーバーヘッドにより深刻なパフォーマンスの問題が発生します。この問題が特に明白なのは、フォームからユーザー入力を受け入れ、SQL文を動的に生成するWebアプリケーションです。Real-World Performanceグループでは、ハード解析をできるだけ減らすことを強くお薦めします。

Video

例15-4 V$SQLを使用した解析情報の検出

様々な手法を使用して、ハード解析およびソフト解析を監視できます。この例では、セッション統計を問い合せて、DBA_JOBS問合せの繰返し実行がハード解析数を増やすかどうかを判断します。文の最初の実行では、ハード解析数が49に増加しましたが、2回目の実行ではハード解析数が変わりませんでした。これはOracle Databaseがアプリケーション・コードを再利用したことを意味します。

SQL> ALTER SYSTEM FLUSH SHARED_POOL;

System altered.

SQL> COL NAME FORMAT a18

SQL> SELECT s.NAME, m.VALUE
2  FROM   V$STATNAME s, V$MYSTAT m
3  WHERE  s.STATISTIC# = m.STATISTIC#
4  AND    s.NAME LIKE '%(hard%';

NAME                    VALUE
------------------ ----------
parse count (hard)         48

SQL> SELECT COUNT(*) FROM DBA_JOBS;

COUNT(*)
----------
0

SQL> SELECT s.NAME, m.VALUE
2  FROM   V$STATNAME s, V$MYSTAT m
3  WHERE  s.STATISTIC# = m.STATISTIC#
4  AND    s.NAME LIKE '%(hard%';

NAME                    VALUE
------------------ ----------
parse count (hard)         49

SQL> SELECT COUNT(*) FROM DBA_JOBS;

COUNT(*)
----------
0

SQL> SELECT s.NAME, m.VALUE
2  FROM   V$STATNAME s, V$MYSTAT m
3  WHERE  s.STATISTIC# = m.STATISTIC#
4  AND    s.NAME LIKE '%(hard%';

NAME                    VALUE
------------------ ----------
parse count (hard)         49

例15-5 トレース・ファイルを使用した解析情報の検出

この例では、SQLトレースおよびTKPROFユーティリティを使用して、解析情報を検出します。管理者権限でデータベースにログインし、トレース・ファイルのディレクトリの場所を問い合せます(出力例も示します)。

SET LINESIZE 120
COLUMN value FORMAT A80

SELECT value
FROM   v$diag_info
WHERE  name = 'Default Trace File';

VALUE
--------------------------------------------------------------------------------
/disk1/oracle/log/diag/rdbms/orcl/orcl/trace/orcl_ora_23054.trc

トレースを使用可能にし、TRACEFILE_IDENTIFIER初期化パラメータを使用してトレース・ファイルに意味のある名前を付け、hr.employeesを問い合せます。

EXEC DBMS_MONITOR.SESSION_TRACE_ENABLE(waits=>TRUE, binds=>TRUE);
ALTER SESSION SET TRACEFILE_IDENTIFIER = "emp_stmt";
SELECT * FROM hr.employees;
EXIT;

生成したトレース・ファイルのデフォルトのトレース・ファイル・ディレクトリを検索します。

% ls *emp_stmt.trc
orcl_ora_17950_emp_stmt.trc

TKPROFを使用してトレース・ファイルをフォーマットし、フォーマットされたファイルを開きます。

% tkprof orcl_ora_17950_emp_stmt.trc emp.out; vi emp.out

フォーマットされたトレース・ファイルには、hr.employeesの問合せの解析情報が含まれています。

SQL ID: brmjpfs7dcnub Plan Hash: 1445457117

SELECT *
FROM
hr.employees

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.07       0.08          0          0          0           0
Execute      1      0.00       0.00          0          0          0           0
Fetch        9      0.00       0.00          3         12          0         107
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total       11      0.07       0.08          3         12          0         107

Misses in library cache during parse: 1
Optimizer mode: ALL_ROWS
Parsing user id: SYSTEM
Number of plan statistics captured: 1

Rows (1st) Rows (avg) Rows (max)  Row Source Operation
---------- ---------- ----------  ---------------------------------------------------
107        107        107  TABLE ACCESS FULL EMPLOYEES (cr=12 pr=3 pw=0 time=497
us starts=1 cost=2 size=7383 card=107)

ライブラリ・キャッシュ・ミスはハード解析を示しています。同じ文の2回目の実行で同じ手順を実行すると、ライブラリ・キャッシュ・ミスがないことを示す次のトレース出力が生成されます。

SQL ID: brmjpfs7dcnub Plan Hash: 1445457117

SELECT *
FROM
hr.employees

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.00       0.00          0          0          0           0
Execute      1      0.00       0.00          0          0          0           0
Fetch        9      0.00       0.00          3         12          0         107
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total       11      0.00       0.00          3         12          0         107

Misses in library cache during parse: 0
Optimizer mode: ALL_ROWS
Parsing user id: SYSTEM
Number of plan statistics captured: 1

Rows (1st) Rows (avg) Rows (max)  Row Source Operation
---------- ---------- ----------  ---------------------------------------------------
107        107        107  TABLE ACCESS FULL EMPLOYEES (cr=12 pr=3 pw=0 time=961
us starts=1 cost=2 size=7383 card=107)

関連項目:

「共有プール・チェック」

リテラルおよびバインド変数について

この項の内容は次のとおりです。

- リテラルおよびカーソル

- バインド変数およびカーソル

- バインド変数の照合

リテラルおよびカーソル

SQL文を構成する際に、一部のOracleアプリケーションではバインド変数ではなくリテラルを使用します。

たとえば、文SELECT SUM(salary) FROM hr.employees WHERE employee_id < 101では、従業員IDにリテラル値101を使用しています。デフォルトでは、同様の文でバインド変数を使用しない場合、Oracle Databaseではカーソル共有を利用できません。そのため、Oracle Databaseでは、値102や他の任意のランダム値であることを除いて同一な文は、まったく新しい文とみなされ、ハード解析が必要です。

Real-World Performanceグループでは、リテラルを使用するアプリケーションは、パフォーマンス、スケーラビリティおよびセキュリティの問題の原因となることが多いことがわかりました。現状では、カーソル共有を考慮せずにアプリケーションが迅速に書き込まれるのは、よくあることです。典型的な例は、Webフォームからコンテンツをコピーし、文字列を連結してSQL文を動的に構成する、スクリーン・スクレイピング・アプリケーションです。

リテラル値の使用によって生じる主な問題は、次のとおりです。

- エンド・ユーザーによるリテラル入力を連結するアプリケーションは、SQLインジェクション攻撃を受けやすくなります。この脅威をなくす唯一の方法は、バインド変数を使用するようにアプリケーションをリライトすることです。

- すべての文がハード解析された場合、カーソルは共有されないため、データベースはカーソルの作成により多くのメモリーを消費する必要があります。

- ハード解析の際には、Oracle Databaseは共有プールおよびライブラリ・キャッシュをラッチする必要があります。ハード解析の数が増加すると、共有プールのラッチを待機するプロセスの数も増加します。この状況では、同時実行性が低下し、競合が増加します。

Video

例15-6 リテラルおよびカーソル共有

リテラルのみが異なる次の文を実行するアプリケーションを考えてみます。

SELECT SUM(salary) FROM hr.employees WHERE employee_id < 101;
SELECT SUM(salary) FROM hr.employees WHERE employee_id < 120;
SELECT SUM(salary) FROM hr.employees WHERE employee_id < 165;

次の問合せのV$SQLAREAは、3つの文には3つの異なる親カーソルが必要であることを示しています。VERSION_COUNTに示すように、各親カーソルには独自の子カーソルが必要です。

COL SQL_TEXT FORMAT a30
SELECT SQL_TEXT, SQL_ID, VERSION_COUNT, HASH_VALUE
FROM   V$SQLAREA
WHERE  SQL_TEXT LIKE '%mployee%'
AND    SQL_TEXT NOT LIKE '%SQL_TEXT%';

SQL_TEXT                              SQL_ID VERSION_COUNT HASH_VALUE
------------------------------ ------------- ------------- ----------
SELECT SUM(salary) FROM hr.emp b1tvfcc5qnczb             1  191509483
loyees WHERE employee_id < 165
SELECT SUM(salary) FROM hr.emp cn5250y0nqpym             1 2169198547
loyees WHERE employee_id < 101
SELECT SUM(salary) FROM hr.emp au8nag2vnfw67             1 3074912455
loyees WHERE employee_id < 120

関連項目:

SQLインジェクションの詳細は、「CURSOR_SHARING = FORCEを永続的な修正として使用しない」を参照してください

バインド変数およびカーソル

リテラルではなくバインド変数を使用するようにOracleアプリケーションを開発できます。

バインド変数は、問合せ内のプレースホルダです。たとえば、文SELECT SUM(salary) FROM hr.employees WHERE employee_id < :emp_idでは、従業員IDにバインド変数:emp_idを使用しています。

Real-World Performanceグループでは、バインド変数を使用するアプリケーションは、より適切に実行され、スケーラブルかつセキュアであることがわかりました。バインド変数の使用によって生じる主な利点は、次のとおりです。

- バインド変数を使用するアプリケーションは、SQLインジェクション攻撃に対する脆弱性が、リテラルを使用するアプリケーションと同じではありません。

- 同一の文でバインド変数を使用する場合、Oracle Databaseはカーソル共有を利用でき、同じ文に異なる値がバインドされると、計画およびその他の情報を共有します。

- Oracle Databaseでは、ハード解析に必要な共有プールおよびライブラリ・キャッシュのラッチのオーバーヘッドが回避されます。

Video

例15-7 バインド変数および共有カーソル

次の例では、SQL*PlusでVARIABLEコマンドを使用してemp_idバインド変数を作成し、3つの異なるバインド値(101、120および165)を使用して問合せを実行します。

VARIABLE emp_id NUMBER

EXEC :emp_id := 101;
SELECT SUM(salary) FROM hr.employees WHERE employee_id < :emp_id;
EXEC :emp_id := 120;
SELECT SUM(salary) FROM hr.employees WHERE employee_id < :emp_id;
EXEC :emp_id := 165;
SELECT SUM(salary) FROM hr.employees WHERE employee_id < :emp_id;

次の問合せのV$SQLAREAは、1つの一意のSQL文を示しています。

COL SQL_TEXT FORMAT a34
SELECT SQL_TEXT, SQL_ID, VERSION_COUNT, HASH_VALUE
FROM   V$SQLAREA
WHERE  SQL_TEXT LIKE '%mployee%'
AND    SQL_TEXT NOT LIKE '%SQL_TEXT%';

SQL_TEXT                           SQL_ID        VERSION_COUNT HASH_VALUE
---------------------------------- ------------- ------------- ----------
SELECT SUM(salary) FROM hr.employe 4318cbskba8yh             1 615850960
es WHERE employee_id < :emp_id

VERSION_COUNTの値1は、3つの個別の子カーソルを作成するデータベースではなく、同じ子カーソルを再利用したデータベースを示しています。バインド変数を使用して、この再利用が可能になりました。

バインド変数の照合

バインド変数の照合(バインド照合とも呼ばれる)では、オプティマイザはデータベースが文のハード解析を実行しているときにバインド変数の値を参照します。オプティマイザは、すべての解析の前にバインド変数の値を参照しません。かわりに、オプティマイザの照合が行われるのは、オプティマイザが最初に起動されたときのみで、これはハード解析中です。

問合せがリテラルを使用する場合、オプティマイザはリテラル値を使用して最良の計画を見つけることができます。ただし、問合せがバインド変数を使用する場合は、オプティマイザはSQLテキストにリテラルが存在しない状態で最良の計画を選択する必要があります。このタスクは極めて困難になる可能性があります。最初のハード解析中にバインド値を照合することにより、オプティマイザは、まるでリテラルが使用されたかのようにWHERE句条件のカーディナリティを判断することができ、これによって計画が改善されます。

オプティマイザはハード解析中にバインド値でのみ照合するため、計画は可能なすべてのバインド値に対して最適ではない可能性があります。次の例に、この原則を示します。

例15-8 異なる実行計画でのリテラルの結果

次のような文を実行するとします。異なるリテラル(101、120および165)を使用した3つの異なる文を実行し、それぞれの実行計画を表示します。

SET LINESIZE 167
SET PAGESIZE 0
SELECT SUM(salary) FROM hr.employees WHERE employee_id < 101;
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR());
SELECT SUM(salary) FROM hr.employees WHERE employee_id < 120;
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR());
SELECT SUM(salary) FROM hr.employees WHERE employee_id < 165;
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR());

データベースは3つの文(同一ではない)をすべてハード解析しました。わかりやすく編集されたDISPLAY_CURSORの出力では、オプティマイザは、最初の2つの文では同じ索引レンジ・スキャン計画を選択し、リテラル165を使用した文では全表スキャン計画を選択することを示しています。

SQL_ID    cn5250y0nqpym, child number 0
-------------------------------------
SELECT SUM(salary) FROM hr.employees WHERE employee_id < 101

Plan hash value: 2410354593

-------------------------------------------------------------------------------------
|Id| Operation                            | Name         |Rows|Bytes|Cost(%CPU)|Time|
-------------------------------------------------------------------------------------
| 0| SELECT STATEMENT                     |               |  |   |2 (100)|          |
| 1|  SORT AGGREGATE                      |               |1 | 8 |       |          |
| 2|   TABLE ACCESS BY INDEX ROWID BATCHED| EMPLOYEES     |1 | 8 |2 (0)  | 00:00:01 |
|*3|    INDEX RANGE SCAN                  | EMP_EMP_ID_PK |1 |   |1 (0)  | 00:00:01 |
-------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------

3 - access("EMPLOYEE_ID"<101)

SQL_ID    au8nag2vnfw67, child number 0
-------------------------------------
SELECT SUM(salary) FROM hr.employees WHERE employee_id < 120

Plan hash value: 2410354593

-------------------------------------------------------------------------------------
|Id| Operation                            | Name         |Rows|Bytes|Cost(%CPU)|Time|
-------------------------------------------------------------------------------------
| 0| SELECT STATEMENT                     |               |  |   |2 (100)|          |
| 1|  SORT AGGREGATE                      |               |1 | 8 |       |          |
| 2|   TABLE ACCESS BY INDEX ROWID BATCHED| EMPLOYEES     |20|160|2 (0)  | 00:00:01 |
|*3|    INDEX RANGE SCAN                  | EMP_EMP_ID_PK |20|   |1 (0)  | 00:00:01 |
-------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

3 - access("EMPLOYEE_ID"<120)

SQL_ID    b1tvfcc5qnczb, child number 0
-------------------------------------
SELECT SUM(salary) FROM hr.employees WHERE employee_id < 165

Plan hash value: 1756381138

-------------------------------------------------------------------------
| Id  | Operation          | Name      |Rows| Bytes |Cost(%CPU)| Time   |
-------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |           |    |       | 2 (100)|          |
|   1 |  SORT AGGREGATE    |           |  1 |     8 |        |          |
|*  2 |   TABLE ACCESS FULL| EMPLOYEES | 66 |   528 | 2   (0)| 00:00:01 |
-------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

2 - filter("EMPLOYEE_ID"<165)

前述の出力では、多くの行を戻す問合せには、索引スキャンより全表スキャンのほうが効率的であるとオプティマイザがみなしていることを示しています。

例15-9 カーソル再利用でのバインド変数の結果

この例では、例15-8で実行された問合せを、リテラルではなくバインド変数を使用するようにリライトしています。同じ値(101、120および165)をバインド変数:emp_idにバインドし、それぞれの実行計画を表示します。

VAR emp_id NUMBER

EXEC :emp_id := 101;
SELECT SUM(salary) FROM hr.employees WHERE employee_id < :emp_id;
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR());
EXEC :emp_id := 120;
SELECT SUM(salary) FROM hr.employees WHERE employee_id < :emp_id;
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR());
EXEC :emp_id := 165;
SELECT SUM(salary) FROM hr.employees WHERE employee_id < :emp_id;
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR());

DISPLAY_CURSORの出力では、オプティマイザは、3つのすべての文でまったく同じ計画を選択することを示しています。

SELECT SUM(salary) FROM hr.employees WHERE employee_id < :emp_id

Plan hash value: 2410354593

-------------------------------------------------------------------------------------
| Id | Operation                            | Name      |Rows|Bytes|Cost (%CPU)|Time|
-------------------------------------------------------------------------------------
|  0 | SELECT STATEMENT                     |               | |  |2 (100)|          |
|  1 |  SORT AGGREGATE                      |               |1|8 |       |          |
|  2 |   TABLE ACCESS BY INDEX ROWID BATCHED| EMPLOYEES     |1|8 |  2 (0)| 00:00:01 |
|* 3 |    INDEX RANGE SCAN                  | EMP_EMP_ID_PK |1|  |  1 (0)| 00:00:01 |
-------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

3 - access("EMPLOYEE_ID"<:EMP_ID)

これに対して、前述の文がリテラルを使用して実行された場合、従業員IDの値が165のときは、オプティマイザはコストの低い全表スキャンを選択します。これは、適応カーソル共有によって解決される問題です(「適応カーソル共有」を参照)。

CURSOR_SHARINGおよびバインド変数置換

このトピックでは、CURSOR_SHARING初期化パラメータとは何か、このパラメータを異なる値に設定した場合のOracle Databaseによるバインド変数の使用方法への影響について説明します。

この項の内容は次のとおりです。

CURSOR_SHARING初期化パラメータ

CURSOR_SHARING初期化パラメータは、データベースによるバインド変数を使用した文の処理方法を制御します。

Oracle Database 12cでは、このパラメータは次の値をサポートします。

- EXACT
これはデフォルト値です。データベースでは、テキスト的に同じ文のみがカーソルを共有できます。データベースは、リテラル値をシステム生成のバインド変数に置換しようとしません。この場合、オプティマイザは、リテラル値に基づいて各文の計画を生成します。

- FORCE
データベースは、すべてのリテラルをシステム生成のバインド変数に置換します。バインド変数でリテラルが置換された後に同一となった文に対して、オプティマイザは同じ計画を使用します。

注意:

CURSOR_SHARINGのSIMILAR値は非推奨です。

CURSOR_SHARINGはシステム・レベルまたはセッション・レベルで設定でき、CURSOR_SHARING_EXACTヒントは文レベルで使用できます。

関連項目:

「CURSOR_SHARING = FORCEを永続的な修正として使用しない」

CURSOR_SHARING = FORCEの場合の動作の解析

SQL文がバインド変数よりもリテラルを使用する場合、CURSOR_SHARING初期化パラメータをFORCEに設定すると、データベースはリテラルをシステム生成のバインド変数と置き換えることができます。この方法を使用して、データベースは共有SQL領域の親カーソルの数を減らせることがあります。

注意:

文でORDER BY句が使用されている場合、定数列番号をリテラルと解釈することは意味的に正しくないため、データベースはこの句ではリテラル置換を行いません。ORDER BY句の列番号は問合せ計画と実行に影響するため、データベースは異なる列番号を持つ2つのカーソルを共有することはできません。

CURSOR_SHARINGがFORCE,に設定されている場合、データベースは解析中に次の手順を実行します。

1. 文のすべてのリテラルをPGAにコピーし、システム生成のバインド変数に置換します
たとえば、アプリケーションでは次の文を処理できます。

SELECT SUBSTR(last_name, 1, 4), SUM(salary)
FROM   hr.employees
WHERE  employee_id < 101 GROUP BY last_name

次のように、オプティマイザは、SUBSTR関数内のリテラルを含むリテラルを置換します。

SELECT SUBSTR(last_name, :"SYS_B_0", :"SYS_B_1"), SUM(salary)
FROM   hr.employees
WHERE  employee_id < :"SYS_B_2" GROUP BY last_name

2. 共有プールで同一文(同じSQLハッシュ値)を検索します
同一文が見つからない場合は、データベースはハード解析を実行します。そうでない場合は、データベースは次の手順に進みます。

3. 文のソフト解析を実行します

前述の手順に示すように、CURSOR_SHARING初期化パラメータをFORCEに設定しても、解析数は減りません。かわりに、場合によっては、FORCEを使用するとデータベースでハード解析ではなくソフト解析を実行できます。また、インジェクションがすでに発生した後でOracle Databaseで値をバインドするため、FORCEによってSQLインジェクション攻撃が回避されません。

例15-10 システムのバインド変数へのリテラルの置換

この例では、セッション・レベルでCURSOR_SHARINGをFORCEに設定し、リテラルを含む3つの文を実行し、各文の計画を表示します。

ALTER SESSION SET CURSOR_SHARING=FORCE;
SET LINESIZE 170
SET PAGESIZE 0
SELECT SUM(salary) FROM hr.employees WHERE employee_id < 101;
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR());
SELECT SUM(salary) FROM hr.employees WHERE employee_id < 120;
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR());
SELECT SUM(salary) FROM hr.employees WHERE employee_id < 165;
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR());

読みやすく編集された次のDISPLAY_CURSORの出力では、3つの文はすべて同じ計画を使用したことを示しています。オプティマイザはその計画、索引レンジ・スキャンを選択します。これは、システムのバインド変数にバインドされた最初の値(101)を照合し、すべての値に最適なものとしてこの計画を選択したためです。実際には、この計画はすべての値に最適な計画ではありません。値が165の場合、全表スキャンのほうが効率的です。

SQL_ID    cxx8n1cxr9khn, child number 0
-------------------------------------
SELECT SUM(salary) FROM hr.employees WHERE employee_id < :"SYS_B_0"

Plan hash value: 2410354593

-------------------------------------------------------------------------------------
| Id  | Operation                           | Name       |Rows|Bytes|Cost(%CPU)|Time|
-------------------------------------------------------------------------------------
|  0 | SELECT STATEMENT                     |               |  |   |2 (100)|        |
|  1 |  SORT AGGREGATE                      |               |1 | 8 |       |        |
|  2 |   TABLE ACCESS BY INDEX ROWID BATCHED| EMPLOYEES     |1 | 8 |2 (0)  |00:00:01|
|* 3 |    INDEX RANGE SCAN                  | EMP_EMP_ID_PK |1 |   |1 (0)  |00:00:01|
-------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------

3 - access("EMPLOYEE_ID"<101)

問合せのV$SQLAREAは、Oracle Databaseがリテラルをシステムのバインド変数:”SYS_B_0”に置換したこと、および3つのすべての文に1つの親カーソルと1つの子カーソル(VERSION_COUNT=1)を作成した(つまりすべての実行は同じ計画を共有した)ことを確認します。

COL SQL_TEXT FORMAT a36
SELECT SQL_TEXT, SQL_ID, VERSION_COUNT, HASH_VALUE
FROM   V$SQLAREA
WHERE  SQL_TEXT LIKE '%mployee%'
AND    SQL_TEXT NOT LIKE '%SQL_TEXT%';

SQL_TEXT                             SQL_ID        VERSION_COUNT HASH_VALUE
------------------------------------ ------------- ------------- ----------
SELECT SUM(salary) FROM hr.employees cxx8n1cxr9khn             1  997509652
WHERE employee_id < :"SYS_B_0"

関連項目:

- 実行される各種チェックの詳細は、「プライベートSQL領域と共有SQL領域」を参照してください

- CURSOR_SHARING初期化パラメータの詳細は、『Oracle Databaseリファレンス』を参照してください

適応カーソル共有

適応カーソル共有機能により、バインド変数を含む1つの文が複数の実行計画を使用できるようになります。カーソル共有には「適応」機能があります。つまり、データベースが各実行または各バインド変数値に常に同じ計画を使用することがないように、カーソルがその動作を適応させます。

この項の内容は次のとおりです。

- 適応カーソル共有の目的

- 適応カーソル共有の仕組み: 例

- バインド依存カーソル

- バインド対応カーソル

- カーソルのマージ

- 適応カーソル共有のビュー

適応カーソル共有の目的

バインド照合では、オプティマイザは、カーソルの最初の起動時にユーザー定義のバインド変数の値を照合します。オプティマイザは、バインド変数のかわりにまるでリテラルが使用されたかのように、WHERE句条件のカーディナリティを判断します。ただし、WHERE句の列に偏ったデータがある場合、この列にヒストグラムが存在する可能性があります。オプティマイザがユーザー定義のバインド変数の値を照合し、計画を選択したとき、その計画がすべての値にとって最適ではない可能性があります。

適応カーソル共有では、データベースは、様々なバインド値に対して時間の経過とともにアクセスされるデータを監視し、特定のバインド値に対して最適なカーソルを確実に選択できるようにします。たとえば、オプティマイザは、バインド値10とバインド値50に対して、それぞれ異なる計画を選択することもあります。カーソル共有には「適応」機能があります。つまり、オプティマイザが各実行または各バインド変数値に常に同じ計画を選択することがないように、カーソルがその動作を適応させます。そのため、オプティマイザは、文の異なる実行により異なる実行計画の利点を得るタイミングを自動的に検出します。

注意:

適応カーソル共有は、CURSOR_SHARING初期化パラメータとは独立しています。適応カーソル共有は、ユーザー定義のバインド変数やシステム生成のバインド変数を含む文にも同様に適用できます。適応カーソル共有は、リテラルのみを含む文には適用されません。

適応カーソル共有の仕組み: 例

適応カーソル共有では、バインド変数を使用する文を監視して、新しい計画が効率的であるかどうかを判断します。

アプリケーションで、毎回異なる値をバインドする次の文を5回実行するとします。

SELECT * FROM employees WHERE salary = :sal AND department_id = :dept

また、この例では、述語の少なくとも1つの列にヒストグラムが存在するとします。データベースは、この文を次のように処理します。

1. アプリケーションが文を最初に発行すると、ハード解析が行われます。解析中、データベースは次のタスクを実行します。

- バインド変数を照合して初期計画を生成します。

- カーソルをバインド依存とマークします。バインド依存カーソルは、最適な計画がバインド変数の値に依存するカーソルです。別の計画が有効であるかどうかを判断するために、データベースは、別のバインド値を使用するバインド依存カーソルの動作を監視します。

- バインドされた値のカーディナリティなど、述語に関するメタデータを格納します(この例では、5行のみが戻されたとします)。

- 照合された値に基づいて実行計画(この例では索引アクセス)を作成します。

2. データベースはカーソルを実行し、バインド値および実行統計をカーソルに格納します。

3. アプリケーションは、異なるバインド変数を使用して、2回目に文を発行します。データベースはソフト解析を実行し、ライブラリ・キャッシュで一致するカーソルを検出します。

4. データベースはカーソルを実行します。

5. データベースは、次の実行後タスクを実行します。

a. データベースは、2回目の実行の実行統計を1回目の実行統計と比較します。

b. データベースは、前のすべての実行にわたって統計のパターンを監視して、カーソルをバインド対応カーソルとマークするかどうかを判断します。この例では、データベースはカーソルをバインド対応と判断すると仮定します。

6. アプリケーションが異なるバインド変数を使用して3回目に文を発行すると、ソフト解析が行われます。カーソルがバインド対応であるため、データベースは次のことを行います。

- 新しい値のカーディナリティが、格納されたカーディナリティと同じ範囲内にあるかどうかを判断します。この例では、カーディナリティは5行ではなく8行です。

- 既存の子カーソルの実行計画を再利用します。

7. データベースはカーソルを実行します。

8. アプリケーションが異なるバインド変数を使用して4回目に文を発行すると、ソフト解析が行われます。カーソルがバインド対応であるため、データベースは次のことを行います。

- 新しい値のカーディナリティが、格納されたカーディナリティと同じ範囲内にあるかどうかを判断します。この例では、カーディナリティは大きく異なります。5行ではなく102行(107行が含まれる表)です。

- 一致する子カーソルは見つけません。

9. データベースはハード解析を実行します。その結果、データベースは次を行います。

- 2回目の実行計画(この例では全表スキャン)で新しい子カーソルを作成します

- バインドされた値のカーディナリティなど、述語に関するメタデータをカーソルに格納します

10. データベースは新しいカーソルを実行します。

11. データベースは、新しいバインド値および実行統計を新しい子カーソルに格納します。

12. アプリケーションが異なるバインド変数を使用して5回目に文を発行すると、ソフト解析が行われます。カーソルがバインド対応であるため、データベースは次のことを行います。

- 新しい値のカーディナリティが、格納されたカーディナリティと同じ範囲内にあるかどうかを判断します。この例では、カーディナリティは20です。

- 一致する子カーソルは見つけません。

13. データベースはハード解析を実行します。その結果、データベースは次を行います。

a. 3回目の実行計画(この例では索引アクセス)で新しい子カーソルを作成します。

b. この索引アクセスの実行計画は、文の最初の実行に使用された索引アクセスの実行計画と同じであると判断します。

c. 索引アクセスの計画を含む2つの子カーソルをマージします。組み合せたカーディナリティ統計が1つの子カーソルに格納され、もう1つの子カーソルは削除されます。

14. データベースは、索引アクセス実行計画を使用してカーソルを実行します。

バインド依存カーソル

バインド依存カーソルは、最適な計画がバインド変数の値に依存するカーソルです。

データベースは、カーディナリティの計算時にバインド値を調べ、異なるバインド値に基づいた計画変更に対して問合せ依存であるとみなします。データベースは、別の計画が有効であるかどうかを判断するために、別のバインド値を使用するバインド依存カーソルの動作を監視します。

オプティマイザは、次の基準を使用して、カーソルがバインド依存であるかどうかを判断します。

- オプティマイザはバインド値を照合してカーディナリティ予測を生成しました。

- バインドが等価述語または範囲述語で使用されます。

新しいバインド値で問合せを実行するごとに、データベースは新しい値の実行統計を記録し、それらを前の値の実行統計と比較します。実行統計が大幅に異なると、データベースはカーソルをバインド対応としてマークします。

例15-11 大きなデータの偏りがある列

この例で、hr.employees.department_id列には大きなデータの偏りがあるとします。SYSTEMは次の設定コードを実行します。サンプル・スキーマのemployees表に部門50の従業員を100,000人追加し、合計は100,107行になります。その後、表統計を収集します。

DELETE FROM hr.employees WHERE employee_id > 999;

ALTER TABLE hr.employees DISABLE NOVALIDATE CONSTRAINT emp_email_uk;

DECLARE
v_counter NUMBER(7) := 1000;
BEGIN
FOR i IN 1..100000 LOOP
INSERT INTO hr.employees
VALUES (v_counter,null,'Doe','Doe@example.com',null,'07-JUN-02','AC_ACCOUNT',null,null,null,50);
v_counter := v_counter + 1;
END LOOP;
END;
/
COMMIT;

EXEC DBMS_STATS.GATHER_TABLE_STATS ( ownname => 'hr', tabname => 'employees');

ALTER SYSTEM FLUSH SHARED_POOL;

次の問合せでは、employees.department_id列のヒストグラムを示しています。

COL TABLE_NAME FORMAT a15
COL COLUMN_NAME FORMAT a20
COL HISTOGRAM FORMAT a9

SELECT TABLE_NAME, COLUMN_NAME, HISTOGRAM
FROM   DBA_TAB_COLS
WHERE  OWNER = 'HR'
AND    TABLE_NAME = 'EMPLOYEES'
AND    COLUMN_NAME = 'DEPARTMENT_ID';

TABLE_NAME      COLUMN_NAME          HISTOGRAM
--------------- -------------------- ---------
EMPLOYEES       DEPARTMENT_ID        FREQUENCY

例15-12 カーディナリティの低い問合せ

この例は、例15-11の例の続きです。次の問合せでは、列department_idに対する値10は極端にカーディナリティが低く、行数の0.00099%を占めていることを示しています。

VARIABLE dept_id NUMBER
EXEC :dept_id := 10;
SELECT COUNT(*), MAX(employee_id) FROM hr.employees WHERE department_id = :dept_id;

COUNT(*) MAX(EMPLOYEE_ID)
---------- ----------------
1              200

オプティマイザは、このようなカーディナリティの低い問合せの場合に予想されたように、索引レンジ・スキャンを選択します。

SQL> SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR);

PLAN_TABLE_OUTPUT
-------------------------------------
SQL_ID    a9upgaqqj7bn5, child number 0
-------------------------------------
select COUNT(*), MAX(employee_id) FROM hr.employees WHERE department_id = :dept_id

Plan hash value: 1642965905

-------------------------------------------------------------------------------------
| Id| Operation                           | Name       |Rows|Bytes|Cost (%CPU)|Time |
-------------------------------------------------------------------------------------
| 0| SELECT STATEMENT                     |                   |  |  |2(100)|        |
| 1|  SORT AGGREGATE                      |                   |1 |8 |      |        |
| 2|   TABLE ACCESS BY INDEX ROWID BATCHED| EMPLOYEES         |1 |8 |2  (0)|00:00:01|
|*3|    INDEX RANGE SCAN                  | EMP_DEPARTMENT_IX |1 |  |1  (0)|00:00:01|
-------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

3 - access("DEPARTMENT_ID"=:DEPT_ID)

次の問合せのV$SQLは、カーソルに関する情報を取得します。

COL BIND_AWARE FORMAT a10
COL SQL_TEXT FORMAT a22
COL CHILD# FORMAT 99999
COL EXEC FORMAT 9999
COL BUFF_GETS FORMAT 999999999
COL BIND_SENS FORMAT a9
COL SHARABLE FORMAT a9

SELECT SQL_TEXT, CHILD_NUMBER AS CHILD#, EXECUTIONS AS EXEC,
BUFFER_GETS AS BUFF_GETS, IS_BIND_SENSITIVE AS BIND_SENS,
IS_BIND_AWARE AS BIND_AWARE, IS_SHAREABLE AS SHARABLE
FROM   V$SQL
WHERE  SQL_TEXT LIKE '%mployee%'
AND    SQL_TEXT NOT LIKE '%SQL_TEXT%';

SQL_TEXT               CHILD#  EXEC  BUFF_GETS BIND_SENS BIND_AWARE SHARABLE
---------------------- ------ ----- ---------- --------- ---------- --------
SELECT COUNT(*), MAX(e      0     1        196         Y          N        Y
mployee_id) FROM hr.em
ployees WHERE departme
nt_id = :dept_id

前述の出力は、カーディナリティの低い問合せで1回実行された1つの子カーソルを示しています。最適な計画がバインド変数の値に依存することがオプティマイザで認識されているため、カーソルはバインド依存とマークされました。

カーソルがバインド依存とマークされると、別のバインド値には別の計画がより効率的であるかどうかを判断するために、Oracle Databaseは別のバインド値を使用するカーソルの動作を監視します。オプティマイザはdepartment_id列でヒストグラムを使用して述語WHERE department_id = :dept_idの選択性を計算したため、データベースはこのカーソルをバインド依存とマークしました。ヒストグラムの存在は列が偏っていることを示すため、バインド変数の異なる値に異なる計画が必要になる可能性があります。

例15-13 カーディナリティの高い問合せ

この例は、例15-12の例の続きです。次のコードでは、値50 (行数の99.9%を占める)を使用して同じ問合せを再実行します。

EXEC :dept_id := 50;
SELECT COUNT(*), MAX(employee_id) FROM hr.employees WHERE department_id = :dept_id;

COUNT(*) MAX(EMPLOYEE_ID)
---------- ----------------
100045        100999

このような非選択性の問合せは全表スキャンを使用したほうが効率的であっても、オプティマイザは、department_id=10で使用された同じ索引レンジ・スキャンを選択します。理由は、カーソル内の既存の計画を共有できると仮定されているためです。

SQL> SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR);

PLAN_TABLE_OUTPUT
-------------------------------------
SQL_ID    a9upgaqqj7bn5, child number 0
-------------------------------------
SELECT COUNT(*), MAX(employee_id) FROM hr.employees WHERE department_id = :dept_id

Plan hash value: 1642965905

-------------------------------------------------------------------------------------
| Id| Operation                           | Name       |Rows|Bytes|Cost (%CPU)|Time |
-------------------------------------------------------------------------------------
| 0| SELECT STATEMENT                     |                   |  |  |2(100)|        |
| 1|  SORT AGGREGATE                      |                   |1 |8 |      |        |
| 2|   TABLE ACCESS BY INDEX ROWID BATCHED| EMPLOYEES         |1 |8 |2  (0)|00:00:01|
|*3|    INDEX RANGE SCAN                  | EMP_DEPARTMENT_IX |1 |  |1  (0)|00:00:01|
-------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

3 - access("DEPARTMENT_ID"=:DEPT_ID)

問合せのV$SQLは、子カーソルが2回実行されたことを示しています。

SELECT SQL_TEXT, CHILD_NUMBER AS CHILD#, EXECUTIONS AS EXEC,
BUFFER_GETS AS BUFF_GETS, IS_BIND_SENSITIVE AS BIND_SENS,
IS_BIND_AWARE AS BIND_AWARE, IS_SHAREABLE AS SHARABLE
FROM   V$SQL
WHERE  SQL_TEXT LIKE '%mployee%'
AND    SQL_TEXT NOT LIKE '%SQL_TEXT%';

SQL_TEXT               CHILD#  EXEC  BUFF_GETS BIND_SENS BIND_AWARE SHARABLE
---------------------- ------ ----- ---------- --------- ---------- --------
SELECT COUNT(*), MAX(e      0     2       1329         Y          N        Y
mployee_id) FROM hr.em
ployees WHERE departme
nt_id = :dept_id

この段階では、オプティマイザはカーソルをバインド対応とまだマークしていません。

関連項目:

V$SQLの詳細は、『Oracle Databaseリファレンス』を参照してください

バインド対応カーソル

バインド対応カーソルは、バインド値ごとに異なる計画を使用するのに適したバインド依存カーソルです。

カーソルをバインド対応にした後で、オプティマイザは、バインド値とそのカーディナリティの見積りを基に、今後の実行のための計画を選択します。そのため、「バインド対応」は基本的に、現在のバインド値に最適な計画を意味します。

バインド依存カーソルを含む文を実行する場合、オプティマイザは、内部アルゴリズムを使用して、カーソルをバインド対応としてマークするかどうかを判断します。これは、カーソルが生成するデータ・アクセス・パターンが、バインド値によって大幅に異なるかどうかによって判断され、結果としてパフォーマンス・コストが予測とは異なります。

データベースがカーソルをバインド対応としてマークすると、次回そのカーソルが実行されたときに、データベースは次のことを行います。

- バインド値に基づいて、新規計画を生成します

- その文に生成された元のカーソルを共有不可(V$SQL.IS_SHAREABLEがN)としてマークします。元のカーソルは使用できなくなり、ライブラリ・キャッシュからのエージ・アウトの対象となります

同じ問合せが別のバインド値を使用して繰り返し実行されると、データベースは新しいバインド値をSQL文のシグネチャ(オプティマイザ環境、NLS設定などを含む)に追加し、値を分類します。データベースはバインド値を調べ、現在のバインド値のデータ量が大幅に異なるか、または既存の計画が十分であるかを検討します。データベースは、新しい値ごとに新しい計画を作成する必要はありません。

12個の異なるバインド値を含む文を実行するシナリオを考えてみます(それぞれの異なる値を2回実行します)これにより、データベースは5つのハード解析をトリガーし、2つの追加の計画を作成します。データベースは5つのハード解析を実行するため、一部のカーソルに既存のカーソルと同じ実行計画がある場合でも、5つの新しい子カーソルが作成されます。データベースは余分なカーソルを使用不可とマークし、これらのカーソルは最終的にライブラリ・キャッシュからエージ・アウトされます。

最初のハード解析中に、オプティマイザは、基本的にはバインド値と適切な実行計画との間の関係をマップしています。この最初の期間の後、データベースは最終的には安定した状態になります。新しいバインド値で実行すると、ハード解析を必要とせずに、キャッシュ内の最適な子カーソルが選択されます。そのため、解析の数は異なるバインド値の数と対応しません。

例15-14 バインド対応カーソル

この例は、「バインド依存カーソル」の例の続きです。次のコードでは、2番目の問合せemployeesをバインド変数を50に設定して発行します。

EXEC :dept_id := 50;
SELECT COUNT(*), MAX(employee_id) FROM hr.employees WHERE department_id = :dept_id;

COUNT(*) MAX(EMPLOYEE_ID)
---------- ----------------
100045           100999

最初の2つの実行中、データベースは問合せの動作を監視し、異なるバインド値によって問合せのカーディナリティが大幅に異なると判断しました。この違いに基づいて、同じ計画が常にこの問合せに対して共有されることがないように、データベースがその動作を適応させます。そのため、オプティマイザは、現在のバインド値(50)に基づいて新しい計画を生成します。

SQL> SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR);

PLAN_TABLE_OUTPUT
-------------------------------------
SQL_ID    a9upgaqqj7bn5, child number 1
-------------------------------------
SELECT COUNT(*), MAX(employee_id) FROM hr.employees WHERE department_id = :dept_id

Plan hash value: 1756381138

-----------------------------------------------------------------------------
| Id  | Operation          | Name      | Rows  | Bytes | Cost(%CPU)| Time   |
-----------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |           |       |       |254 (100)|          |
|   1 |  SORT AGGREGATE    |           |     1 |     8 |         |          |
|*  2 |   TABLE ACCESS FULL| EMPLOYEES |  100K |  781K |254  (15)| 00:00:01 |
-----------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------

2 - filter("DEPARTMENT_ID"=:DEPT_ID)

次の問合せのV$SQLは、カーソルに関する情報を取得します。

SELECT SQL_TEXT, CHILD_NUMBER AS CHILD#, EXECUTIONS AS EXEC,
BUFFER_GETS AS BUFF_GETS, IS_BIND_SENSITIVE AS BIND_SENS,
IS_BIND_AWARE AS BIND_AWARE, IS_SHAREABLE AS SHAREABLE
FROM   V$SQL
WHERE  SQL_TEXT LIKE '%mployee%'
AND    SQL_TEXT NOT LIKE '%SQL_TEXT%';

SQL_TEXT               CHILD#  EXEC  BUFF_GETS BIND_SENS BIND_AWARE SHAREABLE
---------------------- ------ ----- ---------- --------- ---------- ---------
SELECT COUNT(*), MAX(e      0     2       1329         Y          N         N
mployee_id) FROM hr.em
ployees WHERE departme
nt_id = :dept_id

SELECT COUNT(*), MAX(e      1     1        800         Y          Y         Y
mployee_id) FROM hr.em
ployees WHERE departme
nt_id = :dept_id

前述の出力は、データベースが追加の子カーソル(CHILD#が1)を作成したことを示しています。カーソル0は共有不可とマークされています。カーソル1は、カーソル0よりバッファ取得の数が少ないことを示し、バインド依存とバインド対応の両方としてマークされています。バインド対応カーソルは、バインド変数を含む述語の選択性に応じて、異なるバインド値に異なる計画を使用することがあります。

例15-15 バインド対応カーソル: 最適な計画の選択

この例は、例15-14の例の続きです。次のコードでは、極端にカーディナリティが低い(1行のみ)、値が10の同じemployeesの問合せを実行します。

EXEC :dept_id := 10;
SELECT COUNT(*), MAX(employee_id) FROM hr.employees WHERE department_id = :dept_id;

COUNT(*) MAX(EMPLOYEE_ID)
---------- ----------------
1              200

次の出力では、オプティマイザは、現在のバインド値10に対する低いカーディナリティ予測に基づいて、最適な計画(索引スキャン)を選択したことを示しています。

SQL> SELECT * from TABLE(DBMS_XPLAN.DISPLAY_CURSOR);

PLAN_TABLE_OUTPUT
-------------------------------------
SQL_ID    a9upgaqqj7bn5, child number 2
-------------------------------------
select COUNT(*), MAX(employee_id) FROM hr.employees WHERE department_id = :dept_id

Plan hash value: 1642965905

-------------------------------------------------------------------------------------
| Id| Operation                           | Name       |Rows|Bytes|Cost (%CPU)|Time |
-------------------------------------------------------------------------------------
| 0| SELECT STATEMENT                     |                   |  |  |2(100)|        |
| 1|  SORT AGGREGATE                      |                   |1 |8 |      |        |
| 2|   TABLE ACCESS BY INDEX ROWID BATCHED| EMPLOYEES         |1 |8 |2  (0)|00:00:01|
|*3|    INDEX RANGE SCAN                  | EMP_DEPARTMENT_IX | 1|  |1  (0)|00:00:01|
-------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

3 - access("DEPARTMENT_ID"=:DEPT_ID)

V$SQLの出力は、3つの子カーソルが存在することを示しています。

SELECT SQL_TEXT, CHILD_NUMBER AS CHILD#, EXECUTIONS AS EXEC,
BUFFER_GETS AS BUFF_GETS, IS_BIND_SENSITIVE AS BIND_SENS,
IS_BIND_AWARE AS BIND_AWARE, IS_SHAREABLE AS SHAREABLE
FROM   V$SQL
WHERE  SQL_TEXT LIKE '%mployee%'
AND    SQL_TEXT NOT LIKE '%SQL_TEXT%';

SQL_TEXT               CHILD#  EXEC  BUFF_GETS BIND_SENS BIND_AWARE SHAREABLE
---------------------- ------ ----- ---------- --------- ---------- ---------
SELECT COUNT(*), MAX(e      0     2       1329         Y          N         N
mployee_id) FROM hr.em
ployees WHERE departme
nt_id = :dept_id

SELECT COUNT(*), MAX(e      1     1        800         Y          Y         Y
mployee_id) FROM hr.em
ployees WHERE departme
nt_id = :dept_id

SELECT COUNT(*), MAX(e      2     1          3         Y          Y         Y
mployee_id) FROM hr.em
ployees WHERE departme
nt_id = :dept_id

カーソルがバインド対応モードに切り替えられると、データベースは元のカーソル(CHILD#が0)を破棄しました。これは1回かぎりのオーバーヘッドです。データベースはカーソル0を共有不可とマークし(SHAREABLEがN)、これは、このカーソルは使用できず、カーソル・キャッシュから最初にエージ・アウトされることを意味します。

関連項目:

V$SQLの詳細は、『Oracle Databaseリファレンス』を参照してください

カーソルのマージ

オプティマイザがバインド対応カーソルの計画を作成し、この計画が既存のカーソルと同じである場合、オプティマイザはカーソルのマージを実行できます。

この場合、データベースはライブラリ・キャッシュの領域を節約するためにカーソルをマージします。データベースは、新しいバインド値の選択性を含めるために、カーソルの選択性の範囲を拡大します。

問合せが新しいバインド変数を使用すると、オプティマイザは、バインド値の選択性の類似に基づいて適合すると思われるカーソルを見つけようとします。データベースでこのようなカーソルが見つからない場合、新たに作成します。新しいカーソルの計画が既存のカーソルの計画と同じ場合、データベースはライブラリ・キャッシュの領域を節約するために2つのカーソルをマージします。マージによって、データベースは1つのカーソルを共有不可とマークします。ライブラリ・キャッシュが領域削減の必要に迫られている場合、データベースは共有不可のカーソルを最初にエージ・アウトします。

関連項目:

例 15-11

適応カーソル共有のビュー

適応カーソル共有では、V$ビューを使用して選択性の範囲、カーソル情報(カーソルがバインド対応かバインド依存かなど)および実行統計を表示できます。

- V$SQLは、カーソルがバインド依存とバインド対応のどちらであるかを示します。

- V$SQL_CS_HISTOGRAMは、3バケットの実行履歴ヒストグラムにより、実行カウントの配分を示します。

- V$SQL_CS_SELECTIVITYは、カーソル共有をチェックするために選択性が使用された場合に、バインド変数を含むすべての述語に格納されている選択性の範囲を示します。これには、述語のテキスト、および選択性の範囲の下限値と上限値が含まれています。

- V$SQL_CS_STATISTICSは、カーソルをバインド対応としてマークするかどうかを判断するためにオプティマイザが使用する情報を示します。実行のサンプルでは、データベースは、処理された行、取得するバッファ、およびCPU時間を追跡します。バインド・セットがカーソルの作成に使用された場合、PEEKED列はYESを示します。それ以外の場合、この値はNOです。

関連項目:

V$SQLおよび関連するビューの詳細は、『Oracle Databaseリファレンス』を参照してください。

カーソル共有のためのReal-World Performanceのガイドライン

この項の内容は次のとおりです。

- セキュリティおよびパフォーマンスのためのバインド変数を使用したアプリケーションの開発

- CURSOR_SHARING = FORCEを永続的な修正として使用しない

- カーソル再利用を増やすためのコーディング規則の確立

- オプティマイザ環境へのセッション・レベルの変更の最小化

セキュリティおよびパフォーマンスのためのバインド変数を使用したアプリケーションの開発

Real-World Performanceグループでは、すべてのエンタープライズ・アプリケーションでバインド変数を使用することを強くお薦めします。Oracle Databaseアプリケーションは、バインド変数を使用して記述されることを目的としていました。多数のユーザーが動的な非共有のSQL文を発行するようなアプリケーションを設計しないようにしてください。

Oracle Databaseがライブラリ・キャッシュ内の文の一致の検出に失敗するたびに、ハード解析を実行する必要があります。リテラルを使用してアプリケーションを開発すると危険性があるにもかかわらず、実在のアプリケーションのすべてにバインド変数が使用されているわけではありません。開発者は、リテラルを使用したプログラムを記述するほうが速くて簡単であることに気付く場合があります。しかし、開発時間を削減しても、開発後のパフォーマンスおよびセキュリティが向上するわけではありません。

ビデオ:

ハード解析によるパフォーマンスの問題を説明しているデモは、「RWP #3: 接続プールおよびハード解析」を参照してください

バインド変数を使用する主な利点は、次のとおりです。

- リソースの効率
すべての実行前にプログラムをコンパイルすると、リソースが効率的に使用されませんが、Oracle Databaseがハード解析を実行する際には、これは基本的に行われています。カーソルの作成、実行計画の生成および評価などを行うために、データベース・サーバーは、大量のCPUとメモリーを消費する必要があります。データベースでカーソルの共有を有効にすることによって、ソフト解析でのリソースの消費がはるかに少なくなります。アプリケーションでバインド変数ではなくリテラルを使用しているが、毎日少数の問合せしか実行されない場合、DBAでは、追加のオーバーヘッドがパフォーマンスの問題として認識されない場合があります。しかし、アプリケーションが1秒当たり何百または何千もの問合せを実行する場合、追加のリソース・オーバーヘッドにより、パフォーマンスが許容不可能なレベルにまで簡単に低下することがあります。バインド変数を使用すると、文が何回実行されても、データベースはハード解析を1回のみ実行できます。

- スケーラビリティ
データベースがハード解析を実行すると、共有プールおよびライブラリ・キャッシュでラッチの取得および保持に時間がかかります。ラッチは、低レベルのシリアライズ・デバイスです。データベースによる共有メモリー内の構造のラッチが長く頻繁になるほど、これらのラッチのキューも長くなります。複数の文が同じ実行計画を共有する場合、ラッチに対するリクエストおよびラッチの存続期間が停止します。この動作によってスケーラビリティが向上します。

- スループットおよびレスポンス時間
データベースがカーソルの再解析および作成を常に回避すると、ユーザー領域でより多くの時間が費やされます。Real-World Performanceグループでは、リテラルをバインドを使用するように変更すると、スループットおよびユーザーのレスポンス時間を桁違いに向上させることが多いことがわかりました。

ビデオ:

バインド変数のパフォーマンスの利点を示しているデモは、「RWP #4: バインド変数およびソフト解析」を参照してください

- セキュリティ
SQLインジェクション攻撃を防ぐ唯一の方法は、バインド変数を使用することです。悪意のあるユーザーが、アプリケーションにコードを挿入することによって文字列を連結するアプリケーションを利用する可能性があります。

関連項目:

リテラルによるセキュリティの脆弱性を修正するアプリケーションの例は、『Oracle Database PL/SQL言語リファレンス』を参照してください

CURSOR_SHARING = FORCEを永続的な修正として使用しない

ベスト・プラクティスは、共有可能なSQLを書き込み、CURSOR_SHARINGにデフォルトのEXACTを使用することです。ただし、多くの類似文のあるアプリケーションでは、CURSOR_SHARINGをFORCEに設定することでカーソル共有が大幅に改善されます。リテラルをシステム生成のバインド値で置き換えると、メモリー使用量が減少し、解析が高速になり、ラッチの競合が減少します。ただし、FORCEは、永続的な開発ソリューションとなることを意図しているわけではありません。

一般的なガイドラインとして、Real-World Performanceグループは、まれな状況の場合を除きCURSOR_SHARINGをFORCEに設定しないことをお薦めします。次のすべての条件を満たす場合のみ設定します。

- 共有プール内の文は、リテラルの値のみが異なります。

- 非常に多くのライブラリ・キャッシュ・ミスが発生するため、レスポンス時間が最適ではありません。

- 既存のコードには、セキュリティおよびスケーラビリティの深刻な不具合(バインド変数がない)があり、ソース・コードが修正されるまで、一時的な対策を講じる必要があります。

- この初期化パラメータは、インスタンス・レベルではなくセッション・レベルで設定します。

CURSOR_SHARINGをFORCEに設定する場合、次の短所があります。

- アプリケーションではユーザー定義のバインド変数が使用されません。これはSQLインジェクションに対してオープンになっていることを意味します。CURSOR_SHARINGをFORCEに設定しても、SQLインジェクション・バグが修正されたり、コードがよりセキュアにレンダリングされることはありません。悪意のあるSQLテキストがすでに挿入された後でのみ、データベースは値をバインドします。

ビデオ:

FORCEを使用するアプリケーションのReal-World PerformanceグループによるAWR分析については、「RWP #4: バインド変数およびソフト解析」を参照してください。

- データベースは、共有プール内で類似文を検索するために、ソフト解析の間に追加作業を実行する必要があります。

- データベースはすべてのリテラルを削除します。これは有効な情報も削除する可能性があることを意味します。たとえば、データベースがSUBSTR関数およびTO_DATE関数のリテラル値を削除するとします。リテラルのほうが最適な場合にシステム生成のバインド変数を使用すると、実行計画に悪影響を及ぼす可能性があります。

- SELECT文にリテラルを含む選択された式の最大長(DESCRIBEからの戻り値)が増加します。ただし、戻されたデータの実際の長さは変わりません。

- スター型変換はサポートされません。

関連項目:

- 「CURSOR_SHARINGおよびバインド変数置換」

- CURSOR_SHARING初期化パラメータの詳細は、『Oracle Databaseリファレンス』を参照してください。

カーソル再利用を増やすためのコーディング規則の確立

デフォルトでは、バインド変数の名前など、2つのSQL文のテキストの違いによって、カーソルの共有がデータベースで行われなくなります。また、バインド変数のサイズ変更によって、カーソルの不一致が発生する可能性があります。このため、アプリケーション・コードでバインド変数を使用しても、カーソル共有が十分に保証されるわけではありません。

Real-World Performanceグループでは、SQL文およびPL/SQLブロックの空白設定および大文字/小文字の区別の規則を標準化することをお薦めします。また、バインド変数の命名規則および定義を確立します。データベースが予想どおりにカーソルを共有しない場合、V$SQL_SHARED_CURSORを問い合せることによって診断を開始します。

例15-16 SQLテキストのバリエーション

この例では、バインド変数を使用するアプリケーションは、同じバインド変数値を使用する7つの文を実行しますが、文はテキスト的に同じではありません。

VARIABLE emp_id NUMBER
EXEC :emp_id := 101;

SELECT SUM(salary) FROM hr.employees WHERE employee_id < :emp_id;
SELECT SUM(salary) FROM hr.employees WHERE employee_id < :EMP_ID;
SELECT SUM(salary) FROM hr.employees WHERE employee_id < :Emp_Id;
SELECT SUM(salary)  FROM hr.employees WHERE employee_id < :emp_id;
select sum(salary) from hr.employees where employee_id < :emp_id;
Select sum(salary) From hr.employees Where employee_id < :emp_id;
Select sum(salary) From hr.employees Where employee_id< :emp_id;

問合せのV$SQLAREAは、カーソル共有が発生しなかったことを示しています。

COL SQL_TEXT FORMAT a35
SELECT SQL_TEXT, SQL_ID, VERSION_COUNT, HASH_VALUE
FROM   V$SQLAREA
WHERE  SQL_TEXT LIKE '%mployee%'
AND    SQL_TEXT NOT LIKE '%SQL_TEXT%';

SQL_TEXT                            SQL_ID        VERSION_COUNT HASH_VALUE
----------------------------------- ------------- ------------- ----------
SELECT SUM(salary) FROM hr.employee bkrfu3ggu5315             1 3751971877
s WHERE employee_id < :EMP_ID
SELECT SUM(salary) FROM hr.employee 70mdtwh7xj9gv             1  265856507
s WHERE employee_id < :Emp_Id
Select sum(salary) From hr.employee 18tt4ny9u5wkt             1 2476929625
s Where employee_id< :emp_id
SELECT SUM(salary)  FROM hr.employe b6b21tbyaf8aq             1 4238811478
es WHERE employee_id < :emp_id
SELECT SUM(salary) FROM hr.employee 4318cbskba8yh             1  615850960
s WHERE employee_id < :emp_id
select sum(salary) from hr.employee 633zpx3xm71kj             1 4214457937
s where employee_id < :emp_id
Select sum(salary) From hr.employee 1mqbbbnsrrw08             1  830205960
s Where employee_id < :emp_id

7 rows selected.

例15-17 バインド長の不一致

次のコードでは、異なる長さのバインド変数を定義し、同じバインド値を使用したテキスト的に同じ文を実行します。

VARIABLE lname VARCHAR2(20)
EXEC :lname := 'Taylor';
SELECT SUM(salary) FROM hr.employees WHERE last_name = :lname;
VARIABLE lname VARCHAR2(100)
EXEC :lname := 'Taylor';
SELECT SUM(salary) FROM hr.employees WHERE last_name = :lname;

次の問合せは、データベースはカーソルを共有しなかったことを示しています。

COL SQL_TEXT FORMAT a35
SELECT SQL_TEXT, SQL_ID, VERSION_COUNT, HASH_VALUE
FROM   V$SQLAREA
WHERE  SQL_TEXT LIKE '%mployee%'
AND    SQL_TEXT NOT LIKE '%SQL_TEXT%';

SQL_TEXT                            SQL_ID          VERSION_COUNT HASH_VALUE
----------------------------------- ------------- ------------- ----------
SELECT SUM(salary) FROM hr.employee buh8j4557r0h1             2 1249608193
s WHERE last_name = :lname

理由は、バインド長によるものです。

COL BIND_LENGTH_UPGRADEABLE FORMAT a15
SELECT s.SQL_TEXT, s.CHILD_NUMBER,
c.BIND_LENGTH_UPGRADEABLE
FROM   V$SQL s, V$SQL_SHARED_CURSOR c
WHERE  SQL_TEXT LIKE '%employee%'
AND    SQL_TEXT NOT LIKE '%SQL_TEXT%'
AND    s.CHILD_ADDRESS = c.CHILD_ADDRESS;

SQL_TEXT                            CHILD_NUMBER BIND_LENGTH_UPG
----------------------------------- ------------ ---------------
SELECT SUM(salary) FROM hr.employee            0 N
s WHERE last_name = :lname
SELECT SUM(salary) FROM hr.employee            1 Y
s WHERE last_name = :lname

オプティマイザ環境へのセッション・レベルの変更の最小化

ベスト・プラクティスは、アプリケーションのユーザーが最適化アプローチと目標を各セッションに対して変更しないようにすることです。オプティマイザ環境に変更を行うと、他の同一の文がカーソル共有されることを回避できます。

例15-18 環境の不一致

この例では、テキスト的に同じだがカーソルを共有していない2つの文を示しています。

VARIABLE emp_id NUMBER

EXEC :emp_id := 110;

ALTER SESSION SET OPTIMIZER_MODE = FIRST_ROWS;
SELECT salary FROM hr.employees WHERE employee_id < :emp_id;
ALTER SESSION SET OPTIMIZER_MODE = ALL_ROWS;
SELECT salary FROM hr.employees WHERE employee_id < :emp_id;

問合せのV$SQL_SHARED_CURSORは、オプティマイザ・モードでの不一致を示しています。

SELECT S.SQL_TEXT, S.CHILD_NUMBER, s.CHILD_ADDRESS,
C.OPTIMIZER_MODE_MISMATCH
FROM   V$SQL S, V$SQL_SHARED_CURSOR C
WHERE  SQL_TEXT LIKE '%employee%'
AND    SQL_TEXT NOT LIKE '%SQL_TEXT%'
AND S.CHILD_ADDRESS = C.CHILD_ADDRESS;

SQL_TEXT                            CHILD_NUMBER CHILD_ADDRESS    O
----------------------------------- ------------ ---------------- -
SELECT salary FROM hr.employees WHE            0 0000000080293040 N
RE employee_id < :emp_id
SELECT salary FROM hr.employees WHE            1 000000008644E888 Y
RE employee_id < :emp_id

第VII部 SQLの監視および追跡

DBMS_MONITORを使用したデータベース操作の追跡、SQLテスト・ケース・ビルダーを使用したパフォーマンスの問題に関連する情報のパッケージ化、SQLトレースを使用したSQL文の問題の診断データの生成を行います。

この部には次の章が含まれます:

- データベース操作の監視

- SQLテスト・ケース・ビルダーを使用した診断データの収集

- アプリケーション・トレースの実行

16 データベース操作の監視

データベース操作は、バッチ・ジョブまたはデータ抽出、変換およびロード(ETL)処理など、エンド・ユーザーまたはアプリケーション・コードで定義された一連のデータベース・タスクです。データベース操作の定義、監視およびレポート生成が可能です。

この章の内容は次のとおりです。

- データベース操作の監視について

- データベース操作監視の有効化および無効化

- データベース操作の作成

- Cloud Controlを使用したSQL実行の監視

データベース操作の監視について

データベース操作は単純または複合のいずれかです。

単純なデータベース操作は、単一SQL文またはPL/SQLのプロシージャまたはファンクションです。複合データベース操作は、各セクションが独自の開始点および終了点を定義する、データベース・セッションの2つの時点間でのアクティビティです。1つのセッションは、一度に1つの複合データベース操作にのみ関与できます。

Oracle Database 11gで導入されたリアルタイムSQL監視では、1つのSQL文またはPL/SQLプロシージャを監視できます。Oracle Database 12cから、リアルタイム・データベース操作で複合操作を自動的に監視できるようになりました。データベースは、パラレルな問合せ、DML文およびDDL文を、実行の開始と同時に自動的に監視します。デフォルトでは、リアルタイムSQL監視は、SQL文がパラレルに実行されるか、1回の実行で最小で5秒のCPU時間またはI/O時間が消費された場合に自動的に開始されます。

この項の内容は次のとおりです。

- データベース操作の監視の目的

- データベース操作監視の概念

- データベース操作監視のユーザー・インタフェース

- データベース操作監視の基本的なタスク

関連項目:

データベース操作の概要は、『Oracle Database概要』を参照してください

データベース操作の監視の目的

リアルタイムでのSQLの監視により、単一のSQL文またはPL/SQLプログラム・ユニットを監視できます。データベース操作では、名前が付けられて一意に識別される再実行可能な単位として一連の文またはプロシージャを処理可能にして、この機能を拡張します。

データベース操作の監視は通常、次のユーザーにとって役に立ちます。

- コストの高い(応答時間が短い)SQL文とPL/SQLファンクションの識別を行うDBA

- データ・ウェアハウスまたはOLTPシステムでバッチ・ジョブを管理するDBA

- Oracle Data Pump操作など、特定の操作に関連するアクティビティの監視が必要なアプリケーションまたはデータベースの開発者

データベース操作の監視は次のタスクの実行に役に立ちます。

- 追跡およびレポート作成
追跡にはまずDBMS_SQL_MONITOR、OCI、JDBC APIなどのデータベース操作の定義が必要です。現在使用しているセッションとは別のセッションから操作を定義できます。定義した操作のための追跡対象はデータベース・インフラストラクチャで決定されます。

操作のレポートを生成できます。たとえば、チューニング・タスクとして、バッチ・ジョブのかわりに実行するSQL文やその実行統計の以前の状態、その操作の実行中にデータベースで発生した事象などの特定が必要な場合もあります。

- 実行の進捗状況の監視
このタスクでは、現在実行中のデータベース操作の監視が行われます。この情報は、操作の完了に時間がかかる理由を調査している場合に特に役立ちます。

- リソース使用率の監視
SQLの実行により過剰なCPUが使用されたり、過剰なI/Oが発行されたりするタイミング、およびSQLの実行に時間がかかるタイミングを検出することが必要な場合があります。Oracle Database Resource Manager(Resource Manager)を使用して、コンシューマ・グループごとに、そのグループにおけるすべてのSQL実行の最大リソース使用率を指定するしきい値を構成できます。SQL操作が指定されたしきい値に達したとき、Resource Managerでは、その操作をより優先順位の低いコンシューマ・グループに切り替えたり、セッションまたはコールを終了したり、イベントのログを記録できます。これらのSQL操作を監視できます。

- レスポンス時間のチューニング
データベース操作をチューニングする際、通常はレスポンス時間の改善を念頭に置きます。多くの場合に、データベース操作のパフォーマンスの問題は主にSQLパフォーマンスの問題と言えます。

関連項目:

- 「Cloud Controlを使用したSQL実行の監視」

- Oracle Database管理者ガイド

単純なデータベース操作のユースケース

単純操作のリアルタイムSQL監視は、現在実行中のSQL文が実行計画のどの段階にあるのを特定したり、文がその時間をどこで消費しているのかを特定したりするのに役立ちます。また、完了したばかりの文の時間やリソース使用率の内訳を確認できます。このようにして、特定の操作でコストが高くなる理由をより適切に特定できます。

リアルタイムSQL監視の通常のユースケースには次が含まれます。

- 頻繁に実行されるSQL文の実行速度が通常より遅い場合。この問題の根本原因を特定する必要があります。

- データベース・セッションのパフォーマンスが低下する場合。

- パラレルSQL文に時間がかかる場合。サーバー・プロセスで作業がどのように分割されているのかを特定する必要があります。

複合データベース操作のユースケース

OLTPおよびデータ・ウェアハウス環境では、ジョブによって関連するSQL文が論理的にグループ化されることが多くあります。このジョブには複数のセッションを含むことができます。

データベース操作監視は、最適ではない状態で実行されているジョブを見つけ出して、リソースが消費されている場所を特定する場合に役に立ちます。このように、データベース操作では、関連情報を追跡してパフォーマンス・チューニング時間を改善できます。

複合操作を監視する通常のユースケースには次が含まれます。

- 多数のSQL文を含む定期的なバッチ・ジョブが一定数の時間内に完了する必要があるものの、予定の2倍の時間がかかった場合。

- データベースのアップグレード後に、重要なバッチ・ジョブの実行時間が2倍になった場合。この問題を解決するには、アップグレードの前後にバッチ・ジョブから十分な関連統計データを収集し、2つのデータ・セットを比較した上で、変更を特定する必要があります。

- SQLチューニング・セット(STS)のパックに予想よりはるかに長く時間がかかった場合。この問題を診断するには、時間の経過ごとに何が実行されていたのかを把握する必要があります。この問題は簡単に再現できないため、プロセスを実行中に監視する必要があります。

関連項目:

「SQLチューニング・セットについて」

データベース操作監視の概念

このトピックでは、データベース操作のアーキテクチャおよび属性の概要について説明します。

この項の内容は次のとおりです。

- データベース操作のアーキテクチャについて

- 複合データベース操作

- データベース操作の属性

データベース操作のアーキテクチャについて

CONTROL_MANAGEMENT_PACK_ACCESS初期化パラメータをDIAGNOSTIC+TUNING(デフォルト)に設定するとデータベース操作を監視できます。リアルタイムSQL監視は、Oracle Database Tuning Packの機能の1つです。

次の図には、データベース操作のアーキテクチャの概要が示されています。

図16-1 データベース操作のアーキテクチャ

図16-1に示すように、DBMS_SQL_MONITORパッケージを使用して、データベース操作を定義することができます。監視が初期化されると、データベース操作に関するメタデータがAWRに格納されます。データベースによる監視統計のリフレッシュは、監視対象の文の実行とほぼリアルタイムで実行されます(通常は1秒に一度)。データベースでは定期的にデータがディスクに保存されます。

V$SQL_MONITORビューには、監視対象のすべてのデータベース操作のエントリがあります。このエントリでは、実行のために収集される主要なパフォーマンス・メトリック(経過時間、CPU時間、読取り/書込み数、I/O待機時間、およびその他の様々な待機時間など)が追跡されます。V$SQL_PLAN_MONITORビューには、監視対象のSQL文の実行計画における各操作の監視統計が含まれています。DBMS_SQL_MONITOR.REPORT_SQL_MONITORを使用してレポートにアクセスできます。これには、Oracle Enterprise Manager Cloud Control(Cloud Control)インタフェースが含まれます。

関連項目:

- 「Cloud Controlを使用したSQL実行の監視」

- CONTROL_MANAGEMENT_PACK_ACCESS初期化パラメータの詳細は、Oracle Databaseリファレンスを参照してください。

- V$SQL_MONITORおよびV$SQL_PLAN_MONITORビューの詳細は、『Oracle Databaseリファレンス』を参照してください

- DBMS_SQLTUNEパッケージおよびDBMS_SQL_MONITORパッケージの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

複合データベース操作

複合データベース操作は、2つの時点間の1つのセッションのアクティビティから成ります。データベース操作間に厳密に1つのセッションが存在します。

このセッションで実行されるSQL文またはPL/SQLプロシージャは複合操作の一部です。複合データベース操作は、データベース・カーネルでも定義できます。通常の複合操作には、SQL*Plusスクリプト、バッチ・ジョブおよびETL処理が含まれます。

データベース操作の属性

データベース操作は、名前および実行IDによって一意に識別されます。

これらの属性は次のように定義されます。

- データベース操作名
これは、daily_sales_reportなど、ユーザーが作成する名前です。1つのジョブが異なるセッションや異なるデータベースで同時に実行される場合でも、この名前は同じです。データベース操作名は異なる名前空間には存在しません。

- データベース操作実行ID
複数の同じデータベース操作は、名前が同じでも実行IDが異なっていれば、同時に実行可能です。この数値IDによって同じデータベース操作の異なる実行が一意に識別されます。

データベース操作を開始すると、データベースでは実行IDが自動的に作成されます。また、ユーザーが作成した実行IDも指定できます。

データベースでは、V$SQL_MONITORビューで監視対象のSQL文およびPL/SQL文をそれぞれ識別するために次の3つの値が使用されます。文がデータベース操作に含まれているかどうかは関係ありません。

- SQL文を識別するためのSQL識別子(SQL_ID)

- 実行開始タイムスタンプ(SQL_EXEC_START)

- この主キーが一意であることを保証する内部生成識別子(SQL_EXEC_ID)

0(ゼロ)または複数の追加属性を使用することでデータベース操作の特性を説明および特定できます。各属性には名前と値があります。たとえば、操作daily_sales_reportの場合は、db_name属性を定義してそれにprod値を割り当てることができます。

関連項目:

- V$SQL_MONITORビューの詳細は、『Oracle Databaseリファレンス』を参照してください

- DBMS_SQL_MONITOR.BEGIN_OPERATIONファンクションの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

データベース操作監視のユーザー・インタフェース

この項の内容は次のとおりです。

- Cloud Controlの「監視されたSQL実行」ページ

- DBMS_SQL_MONITORパッケージ

- データベース操作監視のビュー

Cloud Controlの「監視されたSQL実行」ページ

Cloud Controlの「監視されたSQL実行」ページは、データベース操作に関するレポートを作成するために推奨されるインタフェースです。

「監視されたSQL実行」ページへのアクセス

「監視されたSQL実行」には、SQL ID、データベース時間、I/Oリクエストなどの情報が表示されます。

「監視されたSQL実行」ページにアクセスする手順は次のとおりです。

1. 適切な資格証明を使用してCloud Controlにログインします。

2. 「ターゲット」メニューの下で、「データベース」を選択します。

3. データベース・ターゲットのリストで、管理対象のOracle Databaseインスタンスのターゲットを選択します。

4. データベースの資格証明の入力を求められた場合は、実行するタスクに必要な最小限の資格証明を入力します。

5. 「パフォーマンス」メニューから、「SQL監視」を選択します。
「監視されたSQL実行」ページが表示されます。

図16-2 監視されたSQL実行

DBMS_SQL_MONITORパッケージ

DBMS_SQL_MONITORパッケージでは、データベース操作の開始と終了を定義し、データベース操作のレポートを生成します。

表16-1 DBMS_SQL_MONITOR

プログラム・ユニット

説明

REPORT_SQL_MONITOR

このファンクションは、実行、レポートの詳細レベルおよびレポート・タイプを指定するいくつかの入力パラメータを受け入れます。指定されたパラメータがない場合は、監視されていた最後の実行のテキスト・レポートがファンクションによって生成されます。

BEGIN_OPERATION

このファンクションでは、セッションがデータベース操作と関連付けられます。

END_OPERATION

このファンクションでは、指定されたデータベース操作の実行からセッションの関連をなくします。

関連項目:

DBMS_SQL_MONITORパッケージの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください

データベース操作監視のビュー

SQL文の実行の統計は、V$SQL_MONITOR、V$SQL_PLAN_MONITORおよびV$SQL_MONITOR_SESSTATの各ビューを使用して監視できます。

表16-2にはこれらのビューの概要が示されています。

表16-2 データベース操作監視のビュー

ビュー

説明

V$SQL_MONITOR

このビューには、データベース操作内の上位SQL文に関する、グローバルで高水準な情報が含まれています。

監視された各SQL文にはこのビューにあるエントリが含まれています。各行にはSQL文が含まれており、このSQL文の統計は、複数のセッションと操作内でのSQL文の実行のすべてから累積されたものです。主キーは、DBOP_NAME、DBOP_EXEC_IDおよびSQL_IDの各列を組み合せたものです。

V$SQL_MONITORビューには、V$SQLで使用される統計のサブセットが含まれます。ただし、V$SQLとは異なり、監視の統計は複数の実行処理にわたって累積されません。かわりに、V$SQL_MONITORの1つのエントリは、SQL文の1回の実行のみに対応します。同じSQL文の2つの実行を監視する場合、V$SQL_MONITORに各実行のエントリが個別に作成されます。

V$SQL_MONITORには、パラレル実行のコーディネータ・プロセスに対して1つのエントリと、パラレル実行のサーバー・プロセスごとに1つのエントリが割り当てられます。各エントリにはV$SQL_PLAN_MONITORの対応するエントリがあります。SQL文のパラレル実行に割り当てられた各プロセスは、同じ実行に対して連携動作するため、これらのエントリは同じ実行キー(コンポジットSQL_ID、SQL_EXEC_STARTおよびSQL_EXEC_ID)を共有します。実行キーを集計することで、パラレル実行の全体的な統計を確認できます。

V$SQL_MONITOR_SESSTAT

このビューには、データベース操作に関連するすべてのセッションの統計が含まれています。

統計のほとんどは累積されます。データベースでは、その統計がXML形式で格納され、各統計に各列が使用されることはありません。このビューは、主にレポートの生成を目的としています。ここでは、V$SQL_MONITOR_SESSTATではなくV$SESSTATを使用することをお薦めします。

V$SQL_PLAN_MONITOR

このビューには、監視対象のSQL文の実行計画における各ステップの監視統計が含まれています。

SQL文が実行されている間、データベースではV$SQL_PLAN_MONITOR内の統計が1秒ごとに更新されます。監視対象のすべてのSQL文のV$SQL_PLAN_MONITORに複数のエントリが存在します。各エントリは、文の実行計画のステップに対応しています。

前述のビューと次のビューを使用して、監視された実行に関する追加情報を取得できます。

- V$ACTIVE_SESSION_HISTORY

- V$SESSION

- V$SESSION_LONGOPS

- V$SQL

- V$SQL_PLAN

関連項目:

データベース操作監視のV$ビューの詳細は、Oracle Databaseリファレンスを参照してください

データベース操作監視の基本的なタスク

この項では、データベース操作監視の基本的なタスクを説明します。基本的なタスクには次があります。

- 「データベース操作監視の有効化および無効化」
このタスクでは、データベース操作の自動監視がシステム・レベルおよび文レベルでどのように有効化できるのかを説明します。

- 「データベース操作の作成」
この項では、PL/SQLを使用してデータベース操作の開始と終了をどのように定義できるのかが説明されています。

- 「SQLモニターを使用したデータベース操作のレポート作成」
この項では、データベース操作のレポートをどのように生成し解釈できるのかが説明されています。

データベース操作監視の有効化および無効化

初期化パラメータを使用して、監視を有効または無効にします。

この項の内容は次のとおりです。

- システム・レベルでのデータベース操作監視の有効化

- 文レベルでのデータベース操作監視の有効化および無効化

システム・レベルでのデータベース操作監視の有効化

SQL監視機能は、STATISTICS_LEVEL初期化パラメータがTYPICAL(デフォルト値)またはALLのいずれかに設定されている場合に、デフォルトで有効になります。SQL監視は、長時間実行されるすべての問合せに対して自動的に開始されます。

前提条件

SQL監視はOracle Database Tuning Packの機能であるため、CONTROL_MANAGEMENT_PACK_ACCESS初期化パラメータをDIAGNOSTIC+TUNING(デフォルト値)に設定する必要があります。

前提条件

このチュートリアルでは、次のことが前提となっています。

- STATISTICS_LEVEL初期化パラメータがBASICに設定されています。

- データベース操作の自動監視を有効にします。

データベース操作の監視を有効化する手順は次のとおりです。

1. 適切な権限でSQL*Plusをデータベースに接続し、現行のデータベース操作の設定を問い合せます。
たとえば、次のSQL*Plusコマンドを実行します。

SQL> SHOW PARAMETER statistics_level

NAME                                TYPE        VALUE
----------------------------------- ----------- -----
statistics_level                    string      BASIC

2. 統計レベルをTYPICALに設定します。
たとえば、次のSQL文を実行します。

SQL> ALTER SYSTEM SET STATISTICS_LEVEL='TYPICAL';

関連項目:

STATISTICS_LEVELおよびCONTROL_MANAGEMENT_PACK_ACCESS初期化パラメータの詳細は、『Oracle Databaseリファレンス』を参照してください

文レベルでのデータベース操作監視の有効化および無効化

CONTROL_MANAGEMENT_PACK_ACCESS初期化パラメータをDIAGNOSTIC+TUNINGに設定すると、ヒントを使用して特定のSQL文の監視を有効化または無効化できます。

MONITORヒントでは監視を有効化する一方で、NO_MONITORヒントでは監視を無効化します。

データベースによるSQL文の監視を強制または回避するには、2つの文レベルのヒントが使用できます。SQL監視を強制するには、次のようにMONITORヒントを使用します。

SELECT /*+ MONITOR */ SYSDATE FROM DUAL;

このヒントは、CONTROL_MANAGEMENT_PACK_ACCESSパラメータがDIAGNOSTIC+TUNINGに設定されている場合にのみ有効です。監視対象のヒント付きSQL文を監視から除外するには、NO_MONITOR逆ヒントを使用します。

前提条件

このチュートリアルでは、次のことが前提となっています。

- 現在、データベース監視がシステム・レベルで有効化されています。

- SELECT * FROM sales ORDER BY time_id文の自動監視を無効にします。

SQL文のデータベース操作の監視を無効化する手順は次のとおりです。

1. NO_MONITORヒントを使用して問合せを実行します。
たとえば、次の文を実行します。

SQL> SELECT * /*+NO_MONITOR*/ FROM sales ORDER BY time_id;

関連項目:

MONITORおよびNO_MONITORヒントの使用方法の詳細は、『Oracle Database SQL言語リファレンス』を参照してください

データベース操作の作成

データベース操作の作成では、その開始ポイントと終了ポイントを明示的に定義します。

DBMS_SQL_MONITOR.BEGIN_OPERATIONファンクションを使用してデータベース操作を開始し、DBMS_SQL_MONITOR.END_OPERATIONプロシージャを使用してデータベース操作を終了できます。

前提条件

このチュートリアルでは、次のことが前提となっています。

- 管理者として、sh.sales表の項目数とsh.customers表の顧客数を問い合せます。

- これら2つの問合せをsh_countという名前のデータベース操作として監視します。

データベース操作を作成する手順は次のとおりです。

1. SQL*Plusを起動し、適切な権限を持つユーザーとして接続します。

2. 実行IDを保持する変数を定義します。
たとえば、次のSQL*Plusコマンドを実行します。

VAR eid NUMBER

3. データベース操作を開始します。
たとえば、BEGIN_OPERATIONファンクションを次のように実行します。

EXEC :eid := DBMS_SQL_MONITOR.BEGIN_OPERATION('sh_count');

4. 操作内で問合せを実行します。
たとえば、次の文を実行します。

SQL> SELECT count(*) FROM sh.sales;

COUNT(*)
----------
918843

SQL> SELECT COUNT(*) FROM sh.customers;

COUNT(*)
----------
55500

5. データベース操作を終了します。
たとえば、END_OPERATIONプロシージャを次のように実行します。

EXEC DBMS_SQL_MONITOR.END_OPERATION('sh_count', :eid);

6. データベース操作が完了したことを確認します。
たとえば、次の問合せを実行します(出力例も示します)。

SELECT SUBSTR(DBOP_NAME, 1, 10), DBOP_EXEC_ID,
SUBSTR(STATUS, 1, 10)
FROM  V$SQL_MONITOR
WHERE DBOP_NAME IS NOT NULL
ORDER BY EXEC_ID;

DBOP_NAME     EXEC_ID STATUS
---------- ---------- ----------
sh_count            1 DONE

関連項目:

DBMS_SQL_MONITORパッケージの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください

Cloud Controlを使用したSQL実行の監視

デフォルトでは、AWRによってSQLの監視レポートがXML形式で自動的に取得されます。

このレポートでは、実行されていないかキューに入っておらず、最終の取得サイクル以降に実行が完了しているSQL文のみが取得されます。AWRでは、経過した実行時間に基づいて最もコストの高い文に対してのみレポートを取得します。

Enterprise Manager Cloud Control(Cloud Control)の「監視されたSQL実行」ページには、監視対象の文のアクティビティが概要が示されます。このページを使用して、特定の文に関する追加の詳細をドリルダウンして取得することができます。「監視されたSQL実行の詳細」ページでは、次のような様々なビューのデータが使用されます。

- GV$SQL_MONITOR

- GV$SQL_PLAN_MONITOR

- GV$SQL_MONITOR_SESSTAT

- GV$SQL

- GV$SQL_PLAN

- GV$ACTIVE_SESSION_HISTORY

- GV$SESSION_LONGOPS

- DBA_HIST_REPORTS

- DBA_HIST_REPORTS_DETAILS

前提条件

このチュートリアルでは、次のことが前提となっています。

- ユーザーshは、長時間実行される次のパラレル問合せ(各顧客の売上の問合せ)を実行します。

SELECT c.cust_id, c.cust_last_name, c.cust_first_name,
s.prod_id, p.prod_name, s.time_id
FROM   sales s, customers c, products p
WHERE  s.cust_id = c.cust_id
AND    s.prod_id = p.prod_id
ORDER BY c.cust_id, s.time_id;

- この問合せで過剰なリソースが消費されないようにします。文が実行されている間に、並列性のレベル、合計データベース時間、I/Oリクエスト数など、データベース操作に関する基本的な統計を判別します。

- Cloud Controlを使用して文の実行を監視します。

注意:

コマンドラインでSQL監視レポートを生成するには、次のサンプルSQL*Plusスクリプトのように、DBMS_SQLTUNEパッケージのREPORT_SQL_MONITORファンクションを実行します。

VARIABLE my_rept CLOB
BEGIN
:my_rept :=DBMS_SQLTUNE.REPORT_SQL_MONITOR();
END;
/
PRINT :my_rept

SQLの実行を監視する手順は次のとおりです。

1. 「Cloud Controlの「監視されたSQL実行」ページ」の説明に従って、「監視されたSQL実行」ページにアクセスします。
次の図では、一番上の行にパラレル問合せが表示されています。

この例では、問合せが1.4分間実行されています。

2. SQL ID列内の値をクリックして文の詳細を確認します。
監視されたSQLの詳細ページが表示されます。

前述のレポートには、文の実行に関する実行計画と統計が示されています。たとえば、「時系列」列には、実行計画の各ステップがアクティブであった時間が示されます。時間は、文の実行の開始と終了との相対で表示されます。「実行」列には、操作が実行された回数が示されます。

3. 「概要」セクションで、SQLテキストの横のリンクをクリックします。
メッセージでSQL文のすべてのテキストが示されます。

4. 「データベース時間」の隣にある「時間と待機の統計」セクションで、棒グラフの最も大きな部分にカーソルを移動します。
データベース時間の半分以上がユーザーI/Oで消費されていることがメッセージに示されます。

データベース時間では、データベースがこのSQL文で動作するために消費した時間量が測定されます。この値には、I/O時間など、CPU時間と待機時間が含まれます。棒グラフは、CPUリソース、ユーザーI/Oリソースおよびその他のリソースをハイライト表示するために色分けされた複数の部分に分割されています。任意の部分にカーソルを移動すると、合計に対するそのパーセント値が表示されます。

5. 「詳細」セクションの「IOリクエスト」列で、I/Oリクエスト・バーの部分にカーソルを移動して、合計に対するパーセント値を表示します。
メッセージが表示されます。

前の図では、「IOリクエスト」メッセージに監視対象のSQLによって発行された読取りリクエストの合計数が示されています。このメッセージには、読取りリクエストが合計I/Oリクエストの80%を占めることが示されています。

関連項目:

- 「監視されたSQL実行の詳細」ページの要素の説明およびレポート内のすべての統計の詳細は、Cloud Controlオンライン・ヘルプを参照してください。

- データベース操作監視のV$SQL_MONITORおよび関連するビューの詳細は、Oracle Databaseリファレンスを参照してください

17 SQLテスト・ケース・ビルダーを使用した診断データの収集

SQLテスト・ケースは、パフォーマンスの問題が発生した特定のSQL文の実行計画を開発者が再現できるようにするための一連の情報です。SQLテスト・ケース・ビルダーは、異なるデータベース・インスタンス内の問題の再現に必要な情報を自動的に収集するツールです。

この章の内容は次のとおりです。

- SQLテスト・ケース・ビルダーの目的

- SQLテスト・ケース・ビルダーの概念

- SQLテスト・ケース・ビルダーのユーザー・インタフェース

- SQLテスト・ケース・ビルダーの実行

SQLテスト・ケース・ビルダーの目的

SQLテスト・ケース・ビルダーでは、問題とそれが発生した環境に関する情報を収集および再現する、時に困難で時間がかかるプロセスを自動化します。

SQLテスト・ケース・ビルダーの出力は、事前に定義されたディレクトリに集められたスクリプトです。これらのスクリプトには、必要なすべてのオブジェクトと環境の再作成に必要なコマンドが含まれています。テスト・ケースの準備が整ったら、そのディレクトリのZIPファイルを作成して別のデータベースに移動するか、またはそのファイルをOracleサポートにアップロードできます。

SQLテスト・ケース・ビルダーの概念

この項の内容は次のとおりです。

- SQLインシデント

- SQLテスト・ケース・ビルダーで取得される情報

- SQLテスト・ケース・ビルダーの出力

SQLインシデント

Oracle Databaseの障害診断インフラストラクチャでは、インシデントは1つの問題の1回の発生を表します。SQLインシデントはSQL関連の問題です。問題(クリティカル・エラー)が複数回発生したとき、それぞれの発生に対してインシデントが作成されます。インシデントには日時が記録され、自動診断リポジトリ(ADR)で追跡されます。各インシデントは、ADR内で一意の数値であるインシデントIDによって識別されます。

SQLテスト・ケース・ビルダーには、コマンドラインで常時アクセスできます。Oracle Enterprise Manager Cloud Control(Cloud Control)では、SQLテスト・ケース・ページは、SQLインシデントが見つかった場合にのみ利用できます。

関連項目:

- ADRの概要は、『Oracle Database概要』を参照してください。

- 問題の調査方法、レポート作成方法および解決方法の詳細は、『Oracle Database管理者ガイド』を参照してください。

SQLテスト・ケース・ビルダーで取得される情報

SQLテスト・ケース・ビルダーで取得される永続的な情報には、実行済の問合せ、表および索引の定義(実際のデータは対象外)、PL/SQLパッケージおよびプログラム・ユニット、オプティマイザの統計、SQL計画ベースライン、初期化パラメータの設定などがあります。Oracle Database 12cから、文の実行の一部としてのみ使用できる情報など、一時情報の取得や再現もSQLテスト・ケース・ビルダーで行われるようになりました。

SQLテスト・ケース・ビルダーでは、次のものがサポートされています。

- 適応計画
SQLテスト・ケース・ビルダーでは、適応計画に関して行われた決定への入力が取得され、各決定の時点でそれらを再現します(「適応計画」を参照)。適応計画の場合、最終プランの決定には、各バッファ統計コレクタの最終統計値で十分です。

- 自動メモリー管理
データベースは、各SQL操作で要求されたメモリーを自動的に処理します。ソートなどのアクションは、パフォーマンスに重大な影響を及ぼす可能性があります。SQLテスト・ケース・ビルダーでは、データベースで割り当てられたメモリーの場所とその割当て量などのメモリー・アクティビティが記録されています。

- 動的統計
異なるデータベース上の動的統計の再収集では、データの消失時間など、常に同じ結果が生成されるわけではありません(「動的統計」を参照)。問題を再現するには、SQLテスト・ケース・ビルダーでソース・データベースから動的統計の結果をエクスポートします。テスト・データベースでは、SQLテスト・ケース・ビルダーによって、動的統計を再収集するのではなくソース・データベースから取得した同じ値を再利用します。

- 複数の実行のサポート
SQLテスト・ケース・ビルダーでは、問合せの複数の実行の間に累積された動的情報を取得できます。この機能は、自動再最適化の際に重要です(「自動再最適化」を参照)。

- コンパイル環境およびバインド値の再現
コンパイル環境設定は、問合せ最適化コンテキストの重要な一部です。ソース・データベースで問題の問合せが実行された際には、ユーザーが変更したデフォルトではない設定がSQLテスト・ケース・ビルダーで取得されます。デフォルトではないパラメータ値が使用されている場合、SQLテスト・ケース・ビルダーは、問合せを実行する前に、その同じ値を再構築します。

- オブジェクトの統計履歴
オブジェクトの統計履歴は、統計値の変更によって計画に変更が生じたかどうかを確認する場合に役に立ちます。DBMS_STATSは、履歴をデータ・ディクショナリ内に格納します。SQLテスト・ケース・ビルダーは、エクスポートの間にこの統計データをステージング表に格納します。インポートの間には、SQLテスト・ケース・ビルダーによって、統計履歴のデータがステージング表からターゲット・データベースに自動的にリロードされます。

- 文の履歴
文の履歴は、適応カーソル共有、静的フィードバックおよびカーソル共有の不具合に関する問題の診断の際に重要です。この履歴には、実行計画とコンパイル統計および実行統計が含まれます。

関連項目:

- SQL計画ベースラインの管理

- DBMS_STATSパッケージの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

SQLテスト・ケース・ビルダーの出力

SQLテスト・ケース・ビルダーの出力には、必要なすべてのオブジェクトおよび環境の再作成に必要なコマンドを含むファイルがまとめられています。デフォルトでは、SQLテスト・ケース・ビルダーで次の場所にファイルを格納します。ここでのincnumはインシデント番号を指し、runnumは実行番号を指します。

$ADR_HOME/incident/incdir_incnum/SQLTCB_runnum

たとえば、有効な出力ファイル名は次のようになります。

$ORACLE_HOME/log/diag/rdbms/dbsa/dbsa/incident/incdir_2657/SQLTCB_1

デフォルトではない場所を指定するには、次の例のように、Oracleディレクトリを作成してDBMS_SQLDIAG.EXPORT_SQL_TESTCASEを呼び出します。

CREATE OR REPLACE DIRECTORY my_tcb_dir_exp '/tmp';

BEGIN
DBMS_SQLDIAG.EXPORT_SQL_TESTCASE (
directory => 'my_tcb_dir_exp'
,   sql_text  => 'SELECT COUNT(*) FROM sales'
,   testcase  => tco
);
END;

関連項目:

ADRリポジトリの構造の詳細は、『Oracle Database管理者ガイド』を参照してください。

SQLテスト・ケース・ビルダーのユーザー・インタフェース

SQLテスト・ケース・ビルダーにアクセスするには、Cloud Controlを使用するか、コマンドラインでPL/SQLを使用します。

SQLテスト・ケース・ビルダーのグラフィカル・インタフェース

Cloud Control内では、インシデント・マネージャ・ページまたはサポート・ワークベンチ・ページからSQLテスト・ケース・ビルダーにアクセスできます。

インシデント・マネージャへのアクセス

このタスクでは、データベース・ホーム・ページのインシデントと問題セクションからインシデント・マネージャに移動する方法を説明します。

インシデント・マネージャにアクセスする手順は次のとおりです。

1. 適切な資格証明を使用してCloud Controlにログインします。

2. 「ターゲット」メニューの下で、「データベース」を選択します。

3. データベース・ターゲットのリストで、管理対象のOracle Databaseインスタンスのターゲットを選択します。

4. データベースの資格証明の入力を求められた場合は、実行するタスクに必要な最小限の資格証明を入力します。

5. インシデントと問題セクションで、調査するSQLインシデントを特定します。
次の例のように、ORA 600エラーはSQLインシデントです。

6. インシデントの概要をクリックします。
「インシデント・マネージャ」の「問題の詳細」ページが表示されます。

表にリストされたインシデントを含む「サポート・ワークベンチ」ページが表示されます。

関連項目:

- Cloud Controlのサポート・ワークベンチを使用して問題を表示する方法の詳細は、『Oracle Database管理者ガイド』を参照してください。

- Cloud Controlのオンライン・ヘルプを参照してください。

サポート・ワークベンチへのアクセス

このタスクでは、Oracle Databaseメニューからインシデント・マネージャに移動する方法を説明します。

サポート・ワークベンチにアクセスする手順は次のとおりです。

1. 適切な資格証明を使用してCloud Controlにログインします。

2. 「ターゲット」メニューの下で、「データベース」を選択します。

3. データベース・ターゲットのリストで、管理対象のOracle Databaseインスタンスのターゲットを選択します。

4. データベースの資格証明の入力を求められた場合は、実行するタスクに必要な最小限の資格証明を入力します。

5. 「Oracle Database」メニューから、「診断」→「サポート・ワークベンチ」を選択します。
表にリストされたインシデントを含む「サポート・ワークベンチ」ページが表示されます。

関連項目:

Cloud Controlのオンライン・ヘルプを参照してください。

SQLテスト・ケース・ビルダーのコマンドライン・インタフェース

DBMS_SQLDIAGパッケージは、SQLテスト・ケース・ビルダーに関連するタスクを実行します。

このパッケージは、SQLテスト・ケース・ビルダー用の様々なサブプログラムで構成されます。表17-1に、そのサブプログラムの一部を示します。

表17-1 DBMS_SQLDIAGのSQLテスト・ケース・ファンクション

プロシージャ

説明

EXPORT_SQL_TESTCASE

SQLテスト・ケースをユーザー指定のディレクトリにエクスポートします。

EXPORT_SQL_TESTCASE_DIR_BY_INC

引数として渡されたインシデントIDに対応するSQLテスト・ケースをエクスポートします。

EXPORT_SQL_TESTCASE_DIR_BY_TXT

引数として渡されたSQLテキストに対応するSQLテスト・ケースをエクスポートします。

IMPORT_SQL_TESTCASE

SQLテスト・ケースをスキーマにインポートします。

関連項目:

DBMS_SQLDIAGパッケージの詳細は、Oracle Database PL/SQLパッケージおよびタイプ・リファレンスを参照してください

SQLテスト・ケース・ビルダーの実行

このチュートリアルでは、Cloud Controlを使用したSQLテスト・ケース・ビルダーの実行方法について説明します。

前提条件

このチュートリアルでは、次のことが前提となっています。

- 内部エラーが発生する次のEXPLAIN PLAN文をユーザーshとして実行します。

EXPLAIN PLAN FOR
SELECT unit_cost, sold
FROM   costs c,
( SELECT /*+ merge */ p.prod_id, SUM(quantity_sold) AS sold
FROM   products p, sales s
WHERE  p.prod_id = s.prod_id
GROUP BY p.prod_id ) v
WHERE  c.prod_id = v.prod_id;

- データベース・ホーム・ページのインシデントと問題セクションに、内部エラーによって生成されるSQLインシデントが表示されます。

- 「インシデント・マネージャへのアクセス」の説明に従って、「インシデントの詳細」ページにアクセスします。

SQLテスト・ケース・ビルダーを実行する手順は次のとおりです。

1. 「インシデント」タブをクリックします。
問題の詳細ページが表示されます。

2. インシデントの概要をクリックします。
インシデントの詳細ページが表示されます。

3. 「ガイドされた解決」で、「診断データの表示」をクリックします。
「インシデントの詳細: incident_number」ページが表示されます。

4. 「アプリケーション情報」セクションで、「追加の診断」をクリックします。
「追加の診断」サブページが表示されます。

5. 「SQLテスト・ケース・ビルダー」を選択して、「実行」をクリックします。
「ユーザー処理を実行」ページが表示されます。

6. サンプリング割合を選択し(オプション)、「送信」をクリックします。
処理が完了すると、「確認」ページが表示されます。

7. 「SQLテスト・ケース・ビルダーの出力」に説明されている場所にあるSQLテスト・ケース・ファイルにアクセスします。

関連項目:

Cloud Controlのオンライン・ヘルプを参照してください。

18 アプリケーション・トレースの実行

この章では、エンドツーエンド・アプリケーションのトレース、およびトレース・ファイルを生成および読み取る方法について説明します。

- エンドツーエンド・アプリケーションのトレースの概要

- エンドツーエンド・トレースにおける統計収集の有効化

- エンドツーエンド・アプリケーションのトレースの有効化

- SQLトレースおよびTKPROFを使用した出力ファイルの生成

- TKPROF出力の解釈のガイドライン

- アプリケーション・トレース・ユーティリティ

- アプリケーションのトレースのビュー

関連項目:

自動トレースを使用したSQL*Plus文のトレースおよびチューニングの詳細は、SQL*Plusユーザーズ・ガイドおよびリファレンスを参照してください

エンドツーエンド・アプリケーションのトレースの概要

エンドツーエンド・アプリケーションのトレースでは、高負荷のSQL文などの過剰なデータベース・ワークロードのソースを、クライアント識別子、サービス、モジュール、アクション、セッション、インスタンスまたはデータベース全体によって識別できます。

複数層環境では、エンド・クライアントからの要求は中間層で別のデータベース・セッションにルーティングされるため、異なるデータベース・セッションを越えてクライアントを追跡することは困難になります。エンドツーエンド・アプリケーションのトレースは、クライアントIDを使用して、データベースへのすべての層を通じて特定のエンドクライアントを一意にトレースするインフラストラクチャで、エンド・クライアントがデータベースで実行している操作の情報を提供します。

エンドツーエンド・アプリケーションのトレースの目的

エンドツーエンド・アプリケーションのトレースは、複数層環境のパフォーマンス上の問題の診断を単純化します。

たとえば、高負荷のSQL文などの過剰なワークロードのソースを識別でき、担当するユーザーに連絡をとることができます。また、問題が発生しているユーザーから連絡を受けることもできます。これにより、データベース・レベルで、ユーザーのセッションが何を実行しているかを識別できます。

さらに、エンドツーエンド・アプリケーションのトレースでは、あるサービスの特定のモジュールおよびアクションを追跡することで、アプリケーション・ワークロードの管理が簡素化されます。モジュール名およびアクション名は、アプリケーション開発者が設定します。たとえば、PL/SQLプログラムでこれらの値を設定するには、DBMS_APPLICATION_INFOパッケージのSET_MODULEおよびSET_ACTIONプロシージャを使用します。

エンドツーエンド・アプリケーションのトレースでは、ワークロードの問題を次のように識別できます。

- クライアント識別子: HR.HRなどのログオンIDに基づいてエンド・ユーザーを指定します。

- サービス: 共通の属性、サービス・レベルのしきい値および優先順位を使用してアプリケーション・グループを指定するか、または会計アプリケーションの場合はACCTGなどのように単一アプリケーションを指定します。

- モジュール: 売掛勘定または総勘定元帳など、アプリケーションの機能ブロックを指定します。

- Action: モジュールのINSERT操作やUPDATE操作などのアクションを指定します。

- セッション: 任意のデータベース・セッション識別子(SID)に基づいて、ローカル・インスタンスのセッションを指定します。

- インスタンス: インスタンス名に基づいて任意のインスタンスを指定します。

エンドツーエンド・アプリケーションのトレースのツール

SQLトレース機能およびTKPROFは、パフォーマンスを診断する2つの基本ツールで、これを使用すると、アプリケーションが実行するSQL文の効率を正確に評価できます。

最善の結果を得るには、EXPLAIN PLANを単体ではなくこれらのツールとともに使用してください。トレース情報がファイルに書き込まれた後、このデータをTRCSESSユーティリティで統合し、TKPROFやSQLトレースで診断できます。

エンドツーエンド・アプリケーションのトレースのためのインタフェースとして推奨されるのは、Oracle Enterprise Manager Cloud Control(Cloud Control)です。Cloud Controlを使用する場合、各コンシューマ・タイプの上位コンシューマを表示して、特定のコンシューマの統計収集およびSQLトレースを使用可能または使用禁止にできます。Cloud Controlが使用可能でない場合は、DBMS_MONITOR APIを使用してこの機能を管理できます。

関連項目:

DBMS_MONITOR、DBMS_SESSION、DBMS_SERVICEおよびDBMS_APPLICATION_INFOの各パッケージの詳細は、Oracle Database PL/SQLパッケージおよびタイプ・リファレンスを参照してください

SQLトレース機能の概要

SQLトレース機能は、個々のSQL文に関するパフォーマンス情報を提供します。

SQLトレースは、文単位に次の統計を生成します。

- 解析、実行、フェッチのカウント

- CPU時間および経過時間

- 物理読取りおよび論理読取り

- 処理された行数

- ライブラリ・キャッシュでのミス

- それぞれの解析が行われるユーザー名

- 各コミットおよびロールバック

- 各SQL文の待機イベント・データおよび各トレース・ファイルの要約

また、SQL文のカーソルがクローズされている場合は、SQLトレースにより次の内容を含む行ソース情報が提供されます。

- 各SQL文の実際の実行計画を示す行操作

- 行数、一貫性のある読取りの数、物理読取り数、物理書込み数および行の各操作の経過時間

1つのセッションまたはインスタンスに対してSQLトレース機能を使用可能にできますが、かわりにDBMS_SESSIONまたはDBMS_MONITORパッケージを使用することをお薦めします。セッションまたはインスタンスに対してSQLトレース機能を使用可能にすると、ユーザー・セッションまたはインスタンスで実行されるすべてのSQL文のパフォーマンス統計がトレース・ファイルに格納されます。SQLトレース機能を使用するとパフォーマンスに影響を与えることがあり、システム・オーバーヘッドの増加、過剰なCPU使用率およびディスク領域の不足をもたらす場合があります。

TRCSESSコマンドライン・ユーティリティは、セッションまたはクライアント識別子などの特定の基準に基づいて、複数のトレース・ファイルからトレース情報を統合します。

関連項目:

- TRCSESS

- DBMS_SESSIONまたはDBMS_MONITORパッケージを使用してセッションまたはインスタンスに対するSQLトレースを使用可能にする方法の詳細は、「エンドツーエンド・アプリケーションのトレースの有効化」を参照してください

TKPROFの概要

トレース・ファイルの内容をフォーマットし、判読可能なファイルとして出力するには、TKPROFプログラムを実行します。

TKPROFでは次のこともできます。

- 統計をデータベースに格納するSQLスクリプトを作成します。

- SQL文の実行計画を判断します。

TKPROFは、実行した各文を、消費したリソースおよびコールした回数、処理した行数とともにレポートします。この情報を使用すると、リソースを最も多く使用している文を検出できます。参考にできる基準をもとに、使用されたリソースが実行された作業に対して妥当であるかどうかを評価できます。

エンドツーエンド・トレースにおける統計収集の有効化

PL/SQLを使用して適切な統計を収集するには、DBMS_MONITORのプロシージャを使用して、クライアント識別子、サービス、モジュールまたはアクションに対する統計収集を使用可能にする必要があります。デフォルト・レベルは、セッション・レベルの統計収集です。統計収集はデータベース全体を対象にしており、データベース・インスタンスの再起動後も引き続き行われます。

統計は次の基準でも収集できます。

- クライアント識別子に対する統計収集の有効化

- Service_ Module_およびアクションに対する統計収集の有効化

クライアント識別子に対する統計収集の有効化

プロシージャCLIENT_ID_STAT_ENABLEでは、特定のクライアント識別子に対する統計収集が使用可能になり、プロシージャCLIENT_ID_STAT_DISABLEでは、それが使用禁止になります。V$SESSIONのCLIENT_IDENTIFIER列でクライアント識別子を表示できます。

前提条件

このチュートリアルでは、識別子がoe.oeのクライアントに対する統計収集を使用可能にし、その後使用禁止にするものとします。

クライアント識別子に対する統計収集の有効化および無効化

1. SQL*Plusを起動し、適切な権限でデータベースに接続します。

2. oe.oeに対する統計収集を使用可能にします。
たとえば、次のようなコマンドを実行します。

EXECUTE DBMS_MONITOR.CLIENT_ID_STAT_ENABLE(client_id => 'OE.OE');

3. oe.oeに対する統計収集を使用禁止にします。
たとえば、次のようなコマンドを実行します。

EXECUTE DBMS_MONITOR.CLIENT_ID_STAT_DISABLE(client_id => 'OE.OE');

サービス、モジュールおよびアクションに対する統計収集の有効化

プロシージャSERV_MOD_ACT_STAT_ENABLEでは、サービス、モジュールおよびアクションの組合せに対する統計収集が使用可能になります。一方、プロシージャSERV_MOD_ACT_STAT_DISABLEでは、サービス、モジュールおよびアクションの組合せに対する統計収集が使用禁止になります。

前述のDBMS_MONITORプロシージャでモジュールまたはアクションを変更する場合、その変更は次のユーザー・コールがセッションで実行されると有効になります。たとえば、モジュールがセッションでmodule1に設定され、そのモジュールがセッションのユーザー・コールでmodule2にリセットされた場合、このユーザー・コールでは、モジュールはmodule1のままです。モジュールは、セッションの次のユーザー・コールでmodule2に変更されます。

前提条件

このチュートリアルでは、統計を次のように収集するものとします。

- ACCTGサービスに関する統計

- PAYROLLモジュール内のすべてのアクションに関する統計

- GLEDGERモジュール内のINSERT ITEMアクションに関する統計

サービス、モジュールおよびアクションに対する統計収集を使用可能および使用禁止にする手順は次のとおりです。

1. SQL*Plusを起動し、適切な権限でデータベースに接続します。

2. 目的のサービス、モジュールおよびアクションに対する統計収集を使用可能にします。
たとえば、次のコマンドを実行します。

BEGIN
DBMS_MONITOR.SERV_MOD_ACT_STAT_ENABLE(
service_name => 'ACCTG'
,   module_name  => 'PAYROLL' );
END;

BEGIN
DBMS_MONITOR.SERV_MOD_ACT_STAT_ENABLE(
service_name => 'ACCTG'
,   module_name  => 'GLEDGER'
,   action_name  => 'INSERT ITEM' );
END;

3. 以前に指定したサービス、モジュールおよびアクションの組合せに対する統計収集を使用禁止にします。
たとえば、次のようなコマンドを実行します。

BEGIN
DBMS_MONITOR.SERV_MOD_ACT_STAT_DISABLE(
service_name => 'ACCTG'
,   module_name  => 'GLEDGER'
,   action_name  => 'INSERT ITEM' );
END;

エンドツーエンド・アプリケーションのトレースの有効化

クライアント識別子、サービス、モジュール、アクション、セッション、インスタンスまたはデータベースのトレースを使用可能にするには、DBMS_MONITORパッケージの適切なプロシージャを実行します。次の基準により、特定の診断およびワークロード管理のトレースを使用可能にできます。

- クライアント識別子に対するトレースの有効化

- Service_ Module_およびアクションに対するトレースの有効化

- セッションに対するトレースの有効化

- インスタンスまたはデータベースに対するトレースの有効化

指定した基準により、特定のトレース情報がトレース・ファイルのセットに収集され、1つの出力トレース・ファイルに結合されます。

クライアント識別子に対するトレースの有効化

指定されたクライアント識別子に対するトレースをデータベース全体で使用可能にするには、CLIENT_ID_TRACE_ENABLEプロシージャを使用します。CLIENT_ID_TRACE_DISABLEプロシージャでは、データベースにおける特定のクライアント識別子のトレースが全体的に使用禁止になります。

前提条件

このチュートリアルでは、次のことが前提となっています。

- OE.OEは、SQLトレースを使用可能にするクライアント識別子です。

- 待機情報をトレースに含めます。

- バインド情報をトレースから除外します。

クライアント識別子に対するトレースを使用可能および使用禁止にする手順は次のとおりです。

1. SQL*Plusを起動し、適切な権限でデータベースに接続します。

2. クライアントに対するトレースを使用可能にします。
たとえば、次のプログラムを実行します。

BEGIN
DBMS_MONITOR.CLIENT_ID_TRACE_ENABLE(
client_id => 'OE.OE' ,
waits     => true    ,
binds     => false   );
END;

3. クライアントに対するトレースを使用禁止にします。
たとえば、次のコマンドを実行します。

EXECUTE DBMS_MONITOR.CLIENT_ID_TRACE_DISABLE(client_id => 'OE.OE');

サービス、モジュールおよびアクションに対するトレースの有効化

SERV_MOD_ACT_TRACE_ENABLEプロシージャでは、データベースにおける、サービス名、モジュールおよびアクションの指定の組合せに対するSQLトレースが全体的に使用可能になります。ただし、このプロシージャでデータベース・インスタンス名が指定されている場合を除きます。SERV_MOD_ACT_TRACE_DISABLEプロシージャでは、サービス名、モジュールおよびアクション名の指定の組合せについて、使用可能なすべてのインスタンスにおけるトレースが全体的に使用禁止になります。

前提条件

このチュートリアルでは、次のことが前提となっています。

- サービスACCTGに対するトレースを使用可能にします。

- ACCTGサービスおよびPAYROLLモジュールの組合せに対するトレースをすべてのアクションで使用可能にします。

- 待機情報をトレースに含めます。

- バインド情報をトレースから除外します。

- inst1インスタンスに対するトレースのみを使用可能にします。

サービス、モジュールおよびアクションに対するトレースを使用可能および使用禁止にする手順は次のとおりです。

1. SQL*Plusを起動し、適切な権限でデータベースに接続します。

2. サービス、モジュールおよびアクションに対するトレースを使用可能にします。
たとえば、次のコマンドを実行します。

BEGIN
DBMS_MONITOR.SERV_MOD_ACT_TRACE_ENABLE(
service_name  => 'ACCTG'   ,
module_name   => 'PAYROLL' ,
waits         =>  true     ,
binds         =>  false    ,
instance_name => 'inst1'   );
END;

3. サービス、モジュールおよびアクションに対するトレースを使用禁止にします。
たとえば、次のコマンドを実行します。

BEGIN
DBMS_MONITOR.SERV_MOD_ACT_TRACE_DISABLE(
service_name  => 'ACCTG'   ,
module_name   => 'PAYROLL' ,
instance_name => 'inst1'   );
END;

セッションに対するトレースの有効化

SESSION_TRACE_ENABLEプロシージャでは、ローカル・インスタンスにおける、特定のデータベース・セッション識別子(SID)のトレースが使用可能になります。

DBMS_MONITORパッケージはDBAロールが付与されているユーザーのみが起動できる一方、ユーザーは、次の例のようにDBMS_SESSION.SESSION_TRACE_ENABLEプロシージャを起動して、所有するセッションのSQLトレースを使用可能にできます。

BEGIN
DBMS_SESSION.SESSION_TRACE_ENABLE(
waits => true
, binds => false);
END;

前提条件

このチュートリアルでは、次のことが前提となっています。

- データベースに管理者権限でログインする。

- ユーザーOEにアクティブなセッションが1つある。

- OEセッションに対するトレースを一時的に有効化する。

- 待機情報をトレースに含めます。

- バインド情報をトレースから除外します。

セッションでトレースを使用可能および使用禁止にする手順は次のとおりです。

1. SQL*Plusを起動し、管理者権限でデータベースにログインします。

2. トレースするセッションの値に対するセッションIDおよびシリアル番号を調べます。
たとえば、次のようにV$SESSIONを問い合せます。

SELECT SID, SERIAL#, USERNAME
FROM   V$SESSION
WHERE  USERNAME = 'OE';

SID    SERIAL# USERNAME
---------- ---------- ------------------------------
27         60 OE

3. 特定のセッションのトレースを使用可能にするには、前述の手順の値を使用します。
たとえば、次のプログラムを実行して、OEセッションに対するトレースを有効化します。この場合、true引数では待機情報がトレースに含まれ、false引数ではバインド情報がトレースに含められません。

BEGIN
DBMS_MONITOR.SESSION_TRACE_ENABLE(
session_id => 27
, serial_num => 60
, waits      => true
, binds      => false);
END;

4. セッションに対するトレースを使用禁止にします。
SESSION_TRACE_DISABLEプロシージャでは、特定のデータベース・セッション識別子(SID)およびシリアル番号のトレースが使用禁止になります。次に例を示します。

BEGIN
DBMS_MONITOR.SESSION_TRACE_DISABLE(
session_id => 27
, serial_num => 60);
END;

インスタンスまたはデータベースに対するトレースの有効化

DBMS_MONITOR.DATABASE_TRACE_ENABLEプロシージャは、他のすべてのセッション・レベルのトレースより優先されますが、クライアント識別子、サービス、モジュールおよびアクションのトレースを補完します。トレースは現在および将来のセッションのすべてに対して使用可能になります。

すべての新規セッションは、DATABASE_TRACE_DISABLEプロシージャがコールされるまで、このプロシージャで指定された待機およびバインド情報を継承します。instance_nameパラメータを指定してこのプロシージャを起動すると、指定されたインスタンスのセッション・レベルのSQLトレースがリセットされます。instance_nameパラメータを指定せずにこのプロシージャを起動すると、データベース全体のセッション・レベルのSQLトレースがリセットされます。

前提条件

DATABASE_TRACE_ENABLEプロシージャを実行するには、管理者権限が必要です。

前提条件

このチュートリアルでは、次のことが前提となっています。

- inst1インスタンスのすべてのSQLに対するトレースを使用可能にします。

- 待機情報をトレースに含めます。

- バインド情報をトレースから除外します。

セッションでトレースを使用可能および使用禁止にする手順は次のとおりです。

1. SQL*Plusを起動し、必要な権限でデータベースにログインします。

2. DATABASE_TRACE_ENABLEプロシージャをコールして、任意のインスタンスまたはデータベース全体のSQLトレースを使用可能にします。
たとえば、次のプログラムを実行します。この場合、true引数は、待機情報がトレースに含められることを指定し、false引数は、バインド情報がトレースに含められないことを指定します。

BEGIN
DBMS_MONITOR.DATABASE_TRACE_ENABLE(
waits         => true
, binds         => false
, instance_name => 'inst1' );
END;

3. セッションに対するトレースを使用禁止にします。
SESSION_TRACE_DISABLEプロシージャは、起動セッションのトレースを使用禁止にします。たとえば、次のプログラムでは、inst1のトレースが使用禁止になります。

EXECUTE DBMS_MONITOR.DATABASE_TRACE_DISABLE(instance_name => 'inst1');

データベース全体に対してセッション・レベルのSQLトレースを使用禁止にするには、instance_nameパラメータを指定せずにDATABASE_TRACE_DISABLEプロシージャを起動します。

EXECUTE DBMS_MONITOR.DATABASE_TRACE_DISABLE();

SQLトレースおよびTKPROFを使用した出力ファイルの生成

この項では、SQLトレースとTKPROFの基本的な使用手順について説明します。

SQLトレース機能とTKPROFを使用する手順は次のとおりです。

1. トレース・ファイル管理用の初期化パラメータを設定します。
「手順1: トレース・ファイル管理用の初期化パラメータの設定」を参照してください。

2. 対象とするセッションに対してSQLトレース機能を使用可能にして、アプリケーションを実行します。手順2では、アプリケーションによって発行されたSQL文に関する統計を含むトレース・ファイルが作成されます。
「手順2: SQLトレース機能を使用可能にする方法」を参照してください。

3. 手順2で作成されるトレース・ファイルを判読可能な出力ファイルに変換するために、TKPROFを実行します。手順3ではオプションとして、データベースへの統計の格納に使用できるSQLスクリプトを作成できます。
「手順3: TKPROFでの出力ファイルの生成」を参照してください。

4. 任意で、手順3で作成したSQLスクリプトを実行してデータベースに統計を格納します。
「手順4: SQLトレース機能統計の格納」を参照してください。

手順1: トレース・ファイル管理用の初期化パラメータの設定

セッションに対してSQLトレース機能が使用可能になると、Oracle Databaseはトレース・ファイルを生成します。このファイルには、そのセッションでトレースされたSQL文に関する統計が記録されています。インスタンスに対してSQLトレース機能が使用可能になると、Oracle Databaseはプロセスごとに個別のトレース・ファイルを作成します。

トレース・ファイル管理用の初期化パラメータを設定する手順は次のとおりです。

1. 表18-1に従って、TIMED_STATISTICS、MAX_DUMP_FILE_SIZEおよびDIAGNOSTIC_DEST初期化パラメータの設定をチェックします。

表18-1 SQLトレース機能を使用可能にする前にチェックする初期化パラメータ

パラメータ

説明

DIAGNOSTIC_DEST

自動診断リポジトリ(ADR)ホームの場所を指定します。各データベース・インスタンスの診断ファイルは、この専用ディレクトリ内にあります。DIAGNOSTIC_DEST初期化パラメータの詳細は、『Oracle Databaseリファレンス』を参照してください。

MAX_DUMP_FILE_SIZE

SQLトレース機能がデータベース・インスタンス・レベルで使用可能になっている場合、データベースをコールするたびに、オペレーティング・システムのファイル形式を持つファイルにテキスト行が書き込まれます。これらのファイルの最大サイズ(オペレーティング・システム・ブロック単位)は、初期化パラメータによって制限されます。デフォルト値はUNLIMITEDです。トレース・ファイルのサイズを制御する方法については、『Oracle Database管理者ガイド』を参照してください。

TIMED_STATISTICS

SQLトレース機能によるCPU時間や経過時間などの時間統計の収集、およびV$ビューの中の様々な統計の収集を使用可能または使用禁止にできます。

STATISTICS_LEVELをTYPICALまたはALLに設定した場合、TIMED_STATISTICSのデフォルト値はtrueになります。STATISTICS_LEVELをBASICに設定した場合、TIMED_STATISTICSのデフォルト値はfalseになります。STATISTICS_LEVEL初期化パラメータについては、『Oracle Databaseリファレンス』を参照してください。

時間計測を使用可能にすると、下位レベル操作に対する時間計測呼出しが余分に発生します。これは動的パラメータです。セッション・パラメータでもあります。TIMED_STATISTICS初期化パラメータについては、『Oracle Databaseリファレンス』を参照してください。

2. 結果のトレース・ファイルを認識する方法を考えます。
トレース・ファイルを名前で区別できるようにしてください。SELECT 'program_name' FROM DUALのような文をプログラムに組み込むことによって、トレース・ファイルにタグを付けることができます。これにより、各ファイルの生成元のプロセスを追跡できます。

TRACEFILE_IDENTIFIER初期化パラメータを設定し、トレース・ファイル名の一部となるカスタム識別子も指定できます(TRACEFILE_IDENTIFIER初期化パラメータについては、『Oracle Databaseリファレンス』を参照してください)。たとえば、次の文によって、後続のトレース・ファイル名にmy_trace_idを追加し、識別しやすくできます。

ALTER SESSION SET TRACEFILE_IDENTIFIER = 'my_trace_id';

3. オペレーティング・システムがファイルの複数のバージョンを保持している場合、SQLトレース機能が生成するトレース・ファイルの数に対して、バージョンの上限が十分に高い値に設定されていることを確認してください。

4. 生成されたトレース・ファイルを自分以外のオペレーティング・システム・ユーザーが所有できる場合、TKPROFを使用してそれらをフォーマットするために必要な権限があることを確認します。

手順2: SQLトレース機能を使用可能にする方法

次のいずれかのレベルでSQLトレース機能を使用可能にします。

- データベース・インスタンス
DBMS_MONITOR.DATABASE_TRACE_ENABLEプロシージャを使用してトレースを使用可能にし、DBMS_MONITOR.DATABASE_TRACE_DISABLEプロシージャを使用してトレースを使用禁止にします。

- データベース・セッション
DBMS_SESSION.SET_SQL_TRACEプロシージャを使用して、トレースを使用可能(true)または使用禁止(false)にします。

注意:

SQLトレース機能を実行するとシステムのオーバーヘッドが増加するため、この機能はSQL文をチューニングするときにのみ使用可能にし、チューニングが終了してから使用禁止にしてください。

データベース・インスタンス・レベルでトレースを使用可能および使用禁止にする手順は次のとおりです。

1. SQL*Plusを起動し、管理者権限でデータベースに接続します。

2. データベース・インスタンス・レベルでトレースを使用可能にします。
次の例では、orclインスタンスに対するトレースを使用可能にします。

EXEC DBMS_MONITOR.DATABASE_TRACE_ENABLE(INSTANCE_NAME => 'orcl');

3. トレースする文を実行します。

4. データベース・インスタンスに対するトレースを使用禁止にします。
次の例では、orclインスタンスに対するトレースを使用禁止にします。

EXEC DBMS_MONITOR.DATABASE_TRACE_DISABLE(INSTANCE_NAME => 'orcl');

セッション・レベルでトレースを使用可能および使用禁止にする手順は次のとおりです。

1. SQL*Plusを起動し、必要な資格証明を使用してデータベースに接続します。

2. 現行のセッションに対するトレースを使用可能にします。
次の例では、現行のセッションに対するトレースを使用可能にします。

EXEC DBMS_SESSION.SET_SQL_TRACE(sql_trace => true);

3. トレースする文を実行します。

4. 現行のセッションに対するトレースを使用禁止にします。
次の例では、現行のセッションに対するトレースを使用禁止にします。

EXEC DBMS_SESSION.SET_SQL_TRACE(sql_trace => false);

関連項目:

DBMS_MONITOR.DATABASE_TRACE_ENABLEの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

手順3: TKPROFでの出力ファイルの生成

TKPROFは、SQLトレース機能によって生成されたトレース・ファイルを入力として受け入れ、フォーマットされた出力ファイルを生成します。TKPROFは、実行計画も生成します。

SQLトレース機能によってトレース・ファイルが生成されると、次を実行できるようになります。

- トレース・ファイルごとにTKPROFを実行して、フォーマットされた出力ファイルを各セッションに1つずつ作成できます。

- トレース・ファイルを連結し、その結果のファイルに対してTKPROFを実行して、インスタンス全体のフォーマットされた出力ファイルを生成できます。

- TRCSESSコマンドライン・ユーティリティを実行して複数のトレース・ファイルからトレース情報を統合し、結果に対してTKPROFを実行します。

TKPROFは、トレース・ファイルに記録されているCOMMIT文およびROLLBACK文をレポートしません。

注意:

次のSQL文は、SQLトレース・ファイルで25文字に切り捨てられます。

SET ROLE
GRANT
ALTER USER
ALTER ROLE
CREATE USER
CREATE ROLE

Example 18-1 TKPROF出力

SELECT * FROM emp, dept
WHERE emp.deptno = dept.deptno;

call   count      cpu    elapsed     disk    query current    rows
---- -------  -------  --------- -------- -------- -------  ------
Parse      1     0.16      0.29         3       13       0       0
Execute    1     0.00      0.00         0        0       0       0
Fetch      1     0.03      0.26         2        2       4      14

Misses in library cache during parse: 1
Parsing user id: (8) SCOTT

Rows     Execution Plan
-------  ---------------------------------------------------

14  MERGE JOIN
4   SORT JOIN
4     TABLE ACCESS (FULL) OF 'DEPT'
14    SORT JOIN
14      TABLE ACCESS (FULL) OF 'EMP'

この文では、TKPROF出力に次の情報が含まれています。

- SQL文のテキスト

- 表形式で示されたSQLトレース統計

- 文の解析と実行におけるライブラリ・キャッシュ・ミスの回数。

- 文を最初に解析したユーザー。

- EXPLAIN PLANによって生成された実行計画

TKPROFは、トレース・ファイルのユーザー・レベル文と再帰的SQLコールの要約も提供します。

手順4: SQLトレース機能統計の格納

SQLトレース機能によって生成されたアプリケーションに関する統計の履歴を保持し、別の時点でこれらの統計を比較することがあります。TKPROFは、表を作成して、統計の行をその表に挿入するSQLスクリプトを生成します。このスクリプトには、次の内容が記述されています。

- TKPROF_TABLEという出力表を作成するCREATE TABLE文

- トレースしたSQL文ごとに統計行を1行ずつTKPROF_TABLEに追加するINSERT文

TKPROFの実行後にこのスクリプトを実行すると、統計がデータベースに格納されます。

TKPROFによる出力SQLスクリプトの生成

TKPROFを実行する場合は、INSERTパラメータを使用して、生成されるSQLスクリプトの名前を指定します。このパラメータを指定しないと、TKPROFはスクリプトを生成しません。

TKPROFによる出力SQLスクリプトの編集

TKPROFによってSQLスクリプトが作成された後、SQLスクリプトを実行する前にスクリプトを編集できます。以前に収集した統計の出力表が作成され、新しい統計をこの表に追加する場合は、スクリプトからCREATE TABLE文を削除します。これにより、スクリプトが新しい行を既存の表に挿入します。

異なるデータベースの統計を別々の表に格納するためなど、複数の出力表を作成している場合は、CREATE TABLE文とINSERT文を編集して、出力表の名前を変更してください。

出力表の問合せ

次のCREATE TABLE文はTKPROF_TABLEを作成します。

CREATE TABLE TKPROF_TABLE (

DATE_OF_INSERT    DATE,
CURSOR_NUM        NUMBER,
DEPTH             NUMBER,
USER_ID           NUMBER,
PARSE_CNT         NUMBER,
PARSE_CPU         NUMBER,
PARSE_ELAP        NUMBER,
PARSE_DISK        NUMBER,
PARSE_QUERY       NUMBER,
PARSE_CURRENT     NUMBER,
PARSE_MISS        NUMBER,
EXE_COUNT         NUMBER,
EXE_CPU           NUMBER,
EXE_ELAP          NUMBER,
EXE_DISK          NUMBER,
EXE_QUERY         NUMBER,
EXE_CURRENT       NUMBER,
EXE_MISS          NUMBER,
EXE_ROWS          NUMBER,
FETCH_COUNT       NUMBER,
FETCH_CPU         NUMBER,
FETCH_ELAP        NUMBER,
FETCH_DISK        NUMBER,
FETCH_QUERY       NUMBER,
FETCH_CURRENT     NUMBER,
FETCH_ROWS        NUMBER,
CLOCK_TICKS       NUMBER,
SQL_STATEMENT     LONG);

出力表のほとんどの列は、フォーマットされた出力ファイルに記録されている統計と直接対応しています。たとえば、PARSE_CNT列の値は出力ファイルの解析ステップに関するカウント統計に対応しています。

表18-2の列は、統計が入っている行を識別する際に役立ちます。

表18-2 統計の行を識別するTKPROF_TABLE列

列

説明

SQL_STATEMENT

SQLトレース機能が収集した統計行の対象となるSQL文です。この列にはLONGデータ型があるため、式またはWHERE句の条件では使用できません。

DATE_OF_INSERT

行が表に挿入された日時です。この値は、SQLトレース機能が統計を収集した時間とは異なります。

DEPTH

SQL文が発行された再帰レベルを示します。たとえば、値0はユーザーがその文を発行したことを示します。値1は、Oracle Databaseが値0の文(ユーザー発行の文)を処理するために再帰的コールとしてその文を生成したことを示します。値nは、Oracle Databaseが値n-1の文を処理する再帰的コールとしてその文を生成したことを示します。

USER_ID

この文を発行するユーザーを識別します。この値はフォーマットした出力ファイルにも出力されます。

CURSOR_NUM

Oracle Databaseでは、この列の値を使用して、各SQL文が割り当てられたカーソルの追跡を行います。

文の実行計画は出力表に格納されません。次の問合せは、出力表からの統計を返します。これらの統計は、例18-7で示したフォーマットされた出力に対応します。

SELECT * FROM TKPROF_TABLE;

出力例は次のように表示されます。

DATE_OF_INSERT CURSOR_NUM DEPTH USER_ID PARSE_CNT PARSE_CPU PARSE_ELAP
-------------- ---------- ----- ------- --------- --------- ----------
21-DEC-2012          1      0     8         1        16         22

PARSE_DISK PARSE_QUERY PARSE_CURRENT PARSE_MISS EXE_COUNT EXE_CPU
---------- ----------- ------------- ---------- --------- -------
3          11           0            1           1         0

EXE_ELAP EXE_DISK EXE_QUERY EXE_CURRENT EXE_MISS EXE_ROWS FETCH_COUNT
-------- -------- --------- ----------- -------- -------- -----------
0        0        0          0          0        0         1

FETCH_CPU FETCH_ELAP FETCH_DISK FETCH_QUERY FETCH_CURRENT FETCH_ROWS
--------- ---------- ---------- ----------- ------------- ----------
2        20          2          2            4           10

SQL_STATEMENT
---------------------------------------------------------------------
SELECT * FROM EMP, DEPT WHERE EMP.DEPTNO = DEPT.DEPTNO

TKPROF出力の解釈のガイドライン

この項では、TKPROF出力を解釈するためのガイドラインを示します。

- 統計の精度を解釈するためのガイドライン

- 再帰的SQL文に関するガイドライン

- チューニングする文の決定に関するガイドライン

- TKPROFの解釈におけるトラップを回避するためのガイドライン

TKPROFは有用な分析を提供しますが、効率の最も正確なメジャーは、アプリケーションのパフォーマンスです。TKPROF出力の最後の部分は、トレース実行期間中にプロセスが実行した作業のサマリーです。

統計の精度を解釈するためのガイドライン

時間統計の精度は、100分の1秒です。このため、100分の1秒以下で終了するカーソル操作の時間は正しく計測されない場合があります。統計を解読するときには、この制限を覚えておいてください。非常に高速に実行する単純な問合せの結果を解読するときには特に注意してください。

再帰的SQL文に関するガイドライン

ユーザーが発行したSQL文を実行するために、Oracle Databaseは内部的に追加のSQL文を発行する必要があります。そのような文は、再帰的コールまたは再帰的SQLと呼ばれます。たとえば、セッションで十分な領域のない表に行を挿入しようとすると、データベースは再帰的コールを実行して動的に領域を割り当てます。データベースでは、データ・ディクショナリの情報がメモリーにないため、ディスクから取り出す必要がある場合にも、再帰的コールが生成されます。

SQLトレース機能が使用可能になっているときに、再帰的コールが発生すると、TKPROFは再帰的SQL文の統計を生成し、出力ファイルで再帰的SQL文を明確に示します。SYSコマンドライン・パラメータをNOに設定して、出力ファイルへのOracle Database内部再帰的コール(たとえば、領域管理)のリスト表示を抑止できます。再帰的SQL文の統計は、再帰的コールを発生させたSQL文のリストでなく、再帰的SQL文のリストに表示されます。したがって、SQL文の処理に必要なリソースの合計を計算するときは、その文自体の統計と、その文によって生じる再帰的コールの統計を考慮する必要があります。

注意:

再帰的SQL統計は、SQLレベルの操作には組み込まれません。

チューニングする文の決定に関するガイドライン

どのSQL文によって大部分のCPUまたはディスク・リソースが使用されるかを確認する必要があります。TIMED_STATISTICSパラメータが使用可能になっている場合は、CPUの高いアクティビティをCPU列で見つけられます。TIMED_STATISTICSが使用可能になっていない場合は、QUERYおよびCURRENT列をチェックしてください。

ロックの問題と効率の悪いPL/SQLループを除いて、問題の文を発見するためにはCPU時間と経過時間のどちらも必要ありません。重要なのは、問合せモード(すなわち、読取り一貫性の対象)と現行モード(読取り一貫性の非対象)の両方でアクセスするブロックの数です。セグメント・ヘッダーと更新されるブロックは現行モードで獲得されますが、すべての問合せ処理と副問合せ処理は問合せモードでデータを要求します。これらのメジャーは、インスタンス統計CONSISTENT GETSおよびDB BLOCK GETSとまったく同じです。高ディスク・アクティビティはディスク列で見つけられます。

次のリストには、あるSQL文のTKPROF出力が出力ファイルに表示されるときと同じ状態で示されています。:

SELECT *
FROM emp, dept
WHERE emp.deptno = dept.deptno;

call   count      cpu    elapsed     disk    query current    rows
---- -------  -------  --------- -------- -------- -------  ------
Parse     11     0.08      0.18        0       0       0         0
Execute   11     0.23      0.66        0       3       6         0
Fetch     35     6.70      6.83      100   12326       2       824
------------------------------------------------------------------
total     57     7.01      7.67      100   12329       8       826

Misses in library cache during parse: 0

7.01 CPU秒で、824行を取り出せる場合は、これ以上このトレース出力を検索する必要はありません。事実上、チューニング作業でのTKPROFレポートの主な用途は、詳細なチューニング段階のプロセスを排除することです。

この出力では、1つの文に対して11の解析コールが存在していたため、10の不要な解析コールが作成され、その配列フェッチ操作が実行されたことを確認できます。フェッチで取り出された行よりも多くの行がフェッチされました。CPU時間と経過時間の大きなギャップは、物理I/Oの存在を示します。

関連項目:

例18-4

TKPROFの解釈におけるトラップを回避するためのガイドライン

この項では、TKPROFの解釈における細かなポイントをいくつか説明します。

- 引数トラップを回避するためのガイドライン

- 読取り一貫性トラップを回避するためのガイドライン

- スキーマ・トラップを回避するためのガイドライン

- タイム・トラップを回避するためのガイドライン

引数トラップを回避するためのガイドライン

実行時にバインドされる値を認識していない場合は、引数トラップに陥る可能性があります。EXPLAIN PLANは、SQL文のテキストからバインド変数の型を判断できないので、型は常にVARCHARであると想定されます。バインド変数が実際には番号または日付である場合、TKPROFが暗黙的データ変換を行い、その結果、効率の悪い計画が実行される可能性があります。この状況を回避するには、異なるデータ型を使用して問合せを試み、独自に変換を実行します。

読取り一貫性トラップを回避するためのガイドライン

次の例は、読取り一貫性トラップを示しています。コミットされていないトランザクションがNAME列に一連の更新を行ったことを知らないと、多くのブロックがアクセスされる理由を判断することは非常に困難です。

通常、このようなケースは再現可能ではありません。そのプロセスが再度実行された場合に、別のトランザクションが同じようにそのプロセスに影響を及ぼすことはあまりありません。

SELECT name_id
FROM cq_names
WHERE name = 'FLOOR';

call     count     cpu     elapsed     disk     query current     rows
----     -----     ---     -------     ----     ----- -------     ----
Parse        1    0.10        0.18        0         0       0        0
Execute      1    0.00        0.00        0         0       0        0
Fetch        1    0.11        0.21        2       101       0        1

Misses in library cache during parse: 1
Parsing user id: 01 (USER1)

Rows     Execution Plan
e----     --------- ----
0     SELECT STATEMENT
1       TABLE ACCESS (BY ROWID) OF 'CQ_NAMES'
2         INDEX (RANGE SCAN) OF 'CQ_NAMES_NAME' (NON_UNIQUE)

スキーマ・トラップを回避するためのガイドライン

この例は極端な場合を示しているので、スキーマ・トラップは容易に検出できます。最初は、明らかに単純に索引付けされた問合せが多くのデータベース・ブロックを検索する必要がある理由、または現行モードでブロックにアクセスすることが必要な理由を理解することは困難です。

SELECT name_id
FROM cq_names
WHERE name = 'FLOOR';

call        count        cpu      elapsed     disk  query current rows
--------  -------   --------    ---------  ------- ------ ------- ----
Parse           1       0.06         0.10        0      0       0    0
Execute         1       0.02         0.02        0      0       0    0
Fetch           1       0.23         0.30       31     31       3    1

Misses in library cache during parse: 0
Parsing user id: 02  (USER2)

Rows     Execution Plan
-------  ---------------------------------------------------
0  SELECT STATEMENT
2340    TABLE ACCESS (BY ROWID) OF 'CQ_NAMES'
0      INDEX (RANGE SCAN) OF 'CQ_NAMES_NAME' (NON-UNIQUE)

2つの統計は、問合せが全表スキャンを使用して実行された可能性があることを示しています。これらの統計は、現行モードでのブロック・アクセスと、実行計画のTable Access行ソースに由来する行数です。これは、トレース・ファイルが生成された後、TKPROFが実行される前に、必要な索引が構築されたことを示しています。

新規トレース・ファイルを生成すると次のデータが与えられます。

SELECT name_id
FROM cq_names
WHERE name = 'FLOOR';

call    count    cpu   elapsed  disk  query current     rows
-----  ------ ------  -------- ----- ------ -------    -----
Parse       1   0.01      0.02     0      0       0        0
Execute     1   0.00      0.00     0      0       0        0
Fetch       1   0.00      0.00     0      2       0        1

Misses in library cache during parse: 0
Parsing user id: 02  (USER2)

Rows     Execution Plan
-------  ---------------------------------------------------
0  SELECT STATEMENT
1    TABLE ACCESS (BY ROWID) OF 'CQ_NAMES'
2      INDEX (RANGE SCAN) OF 'CQ_NAMES_NAME' (NON-UNIQUE)

この正しいバージョンで注目する機能の1つは、解析コールには10ミリ秒のCPU時間と20ミリ秒の経過時間を要する一方で、問合せとフェッチの実行にはまったく時間がかかっていないことです。これらの例外的事態が発生するのは、10ミリ秒というクロック刻みがデータの実行およびフェッチに要する時間と比べて非常に長いためです。このような場合、文を多く実行して統計的に有効な数値を得ることが重要になります。

タイム・トラップを回避するためのガイドライン

次の例で示すように、特定の問合せに長時間かかる理由がわからないことがあります。

UPDATE cq_names SET ATTRIBUTES = lower(ATTRIBUTES)
WHERE ATTRIBUTES = :att

call       count       cpu    elapsed     disk    query current        rows
-------- -------  --------  --------- -------- -------- -------  ----------
Parse          1      0.06       0.24        0        0       0           0
Execute        1      0.62      19.62       22      526      12           7
Fetch          0      0.00       0.00        0        0       0           0

Misses in library cache during parse: 1
Parsing user id: 02  (USER2)

Rows     Execution Plan
-------  ---------------------------------------------------
0  UPDATE STATEMENT
2519  TABLE ACCESS (FULL) OF 'CQ_NAMES'

ここでも、別のトランザクションによる妨害というのが答えです。この場合は、別のトランザクションが更新を発行する前後の数秒間、表cq_namesで共有ロックが保持されています。妨害の影響が発生していることを診断できるようになるにはかなりの経験が必要です。一方で、妨害によって発生する遅延が短時間である(または前の例のようにブロック・アクセスにおける増加がわずかである)場合は、比較用のデータが必要です。ただし、妨害によるオーバーヘッドが少なく、本質的に文が効率的である場合は、統計を分析する必要はありません。

アプリケーション・トレース・ユーティリティ

この項では、次のユーティリティの構文およびセマンティクスについて説明します。

- TRCSESS

- TKPROF

TRCSESS

TRCSESSユーティリティでは、次の複数の基準に基づいて、選択されたトレース・ファイルからのトレース出力が統合されます。TRCSESSによりトレース情報が1つの出力ファイルにマージされると、TKPROFは出力ファイルを処理できます。

説明

TRCSESSは、パフォーマンスまたはデバッグを向上させるため、特定のセッションのトレースを統合する際に便利です。

特定のセッションのトレースは、専用サーバー・モデルでは、1つのプロセスが存続期間中ずっと1つのセッションに対応するため、通常は問題になりません。このセッションのトレース情報は、このセッションに対応するサーバー処理に属するトレース・ファイルで参照できます。ただし、共有サーバー構成では、時間の経過とともにユーザー・セッションが様々なプロセスで対応されます。ユーザー・セッションのトレースは、様々なプロセスに属する各種トレース・ファイル間で分散されるため、1つのセッションのライフサイクル全体を把握することが困難です。

ガイドライン

session、clientid、service、actionまたはmoduleオプションのいずれかを指定する必要があります。複数のオプションを指定する場合、TRCSESSにより、指定した基準に基づいてすべてのトレース・ファイルが出力ファイルに統合されます。

構文

trcsess  [output=output_file_name]
[session=session_id]
[clientid=client_id]
[service=service_name]
[action=action_name]
[module=module_name]
[trace_files]

オプション

引数

説明

output

出力の生成場所となるファイルを指定します。このオプションを指定しない場合、標準出力に書き込まれます。

session

指定されたセッションのトレース情報を統合します。セッション識別子は、セッション索引とセッション・シリアル番号の組合せ(21.2371など)です。これらの値はV$SESSIONビューで見つけることができます。

clientid

指定されたクライアント識別子のトレース情報を統合します。

service

指定されたサービス名のトレース情報を統合します。

action

指定されたアクション名のトレース情報を統合します。

module

指定されたモジュール名のトレース情報を統合します。

trace_files

TRCSESSでトレース情報を検索するトレース・ファイル名(スペースで区切る)を表示します。トレース・ファイル名の指定にワイルドカード文字(*)を使用できます。トレース・ファイルを指定しない場合、TRCSESSは、現在のディレクトリ内のすべてのファイルを入力として受け取ります。

例

例18-2 単一のセッションに対するトレース

このTRCSESSの出力例は、特定のセッションにおけるトレースのコンテナを示しています。この例では、セッション索引およびシリアル番号は21.2371となります。現在のディレクトリのすべてのファイルが入力データとみなされます。

trcsess session=21.2371

例18-3 複数のトレース・ファイルの指定

次の例では、トレース・ファイルを2つ指定します。

trcsess session=21.2371 main_12359.trc main_12995.trc

出力例は次のようになります。

[PROCESS ID = 12359]
*** 2014-04-02 09:48:28.376
PARSING IN CURSOR #1 len=17 dep=0 uid=27 oct=3 lid=27 tim=868373970961 hv=887450622 ad='22683fb4'
select * from cat
END OF STMT
PARSE #1:c=0,e=339,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=4,tim=868373970944
EXEC #1:c=0,e=221,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=4,tim=868373971411
FETCH #1:c=0,e=791,p=0,cr=7,cu=0,mis=0,r=1,dep=0,og=4,tim=868373972435
FETCH #1:c=0,e=1486,p=0,cr=20,cu=0,mis=0,r=6,dep=0,og=4,tim=868373986238
*** 2014-04-02 10:03:58.058
XCTEND rlbk=0, rd_only=1
STAT #1 id=1 cnt=7 pid=0 pos=1 obj=0 op='FILTER  '
STAT #1 id=2 cnt=7 pid=1 pos=1 obj=18 op='TABLE ACCESS BY INDEX ROWID OBJ$ '
STAT #1 id=3 cnt=7 pid=2 pos=1 obj=37 op='INDEX RANGE SCAN I_OBJ2 '
STAT #1 id=4 cnt=0 pid=1 pos=2 obj=4 op='TABLE ACCESS CLUSTER TAB$J2 '
STAT #1 id=5 cnt=6 pid=4 pos=1 obj=3 op='INDEX UNIQUE SCAN I_OBJ# '
[PROCESS ID=12995]
*** 2014-04-02 10:04:32.738
Archiving is disabled

TKPROF

TKPROFプログラムは、トレース・ファイルの内容をフォーマットし、判読可能なファイルとして出力します。

TKPROFは次のことも実行します。

- 統計をデータベースに格納するSQLスクリプトを作成します。

- SQL文の実行計画を判断します。

注意:

SQL文のカーソルがクローズされていない場合、SQL文の実際の実行計画がTKPROF出力に自動的に含まれることはありません。この場合は、TKPROFでEXPLAINオプションを使用して、実行計画を生成します。

TKPROFは、実行した各文を、消費したリソースおよびコールした回数、処理した行数とともにレポートします。

説明

TKPROFは、リソースを最も多く使用している文を検出できます。参考にできる基準をもとに、使用されたリソースが実行された作業に対して妥当であるかどうかを評価できます。

ガイドライン

必要な引数は、入力ファイルと出力ファイルのみです。引数を指定せずにTKPROFを起動すると、オンライン・ヘルプが表示されます。

構文

tkprof input_file output_file
[ waits=yes|no ]
[ sort=option ]
[ print=n ]
[ aggregate=yes|no ]
[ insert=filename3 ]
[ sys=yes|no ]
[ table=schema.table ]
[ explain=user/password ]
[ record=filename4 ]
[ width=n ]

オプション

TKPROFは多くのコマンドライン・オプションをサポートします。

表18-3 TKPROFの引数

引数

説明

input_file

入力ファイル、つまりSQLトレース機能によって生成された統計を収録しているトレース・ファイルを指定します。このファイルは、単一のセッションに対して生成されたトレース・ファイル、または複数のセッションの個々のトレース・ファイルを結合して生成したファイルのどちらでもかまいません。

output_file

TKPROFが、フォーマット済の出力を書き出すファイルを指定します。

WAITS

トレース・ファイル内の待機イベントのサマリーを記録するかどうかを指定します。有効な値はYES(デフォルト)およびNOです。

SORT

トレースしたSQL文のリストを出力ファイルに作成する前に、指定したソート・オプションに基づいて降順にソートします。複数のオプションが指定されている場合、出力はソート・オプションに指定されている値の合計によって降順にソートされます。このパラメータを指定しないと、TKPROFはそれぞれの文のリストを使用順に出力ファイルに作成します。ソート・オプションは次のとおりです。

- PRSCNT - 解析回数

- PRSCPU - 解析に費やされたCPU時間

- PRSELA - 解析に費やされた経過時間

- PRSDSK - 解析中のディスクに対する物理読取りの回数

- PRSQRY - 解析中の一貫モード・ブロック読取りの回数

- PRSCU - 解析中の現行モード・ブロック読取りの回数

- PRSMIS - 解析中のライブラリ・キャッシュ・ミスの回数

- EXECNT - 実行数

- EXECPU - 実行に費やされたCPU時間

- EXEELA - 実行に費やされた経過時間

- EXEDSK - 実行中のディスクに対する物理読取りの回数

- EXEQRY - 実行中の一貫モード・ブロック読取りの回数

- EXECU - 実行中の現行モード・ブロック読取りの回数

- EXEROW - 実行中に処理された行数

- EXEMIS - 実行中のライブラリ・キャッシュ・ミスの回数

- FCHCNT - フェッチ数

- FCHCPU - フェッチに費やされたCPU時間

- FCHELA - フェッチに費やされた経過時間

- FCHDSK - フェッチ中のディスクに対する物理読取りの回数

- FCHQRY - フェッチ中の一貫モード・ブロック読取りの回数

- FCHCU - フェッチ中の現行モード・ブロック読取りの回数

- FCHROW - フェッチされた行数

- USERID - カーソルを解析するユーザーのユーザーID

PRINT

出力ファイルから最初に整数でソートされたSQL文のみのリストを作成します。このパラメータを指定しないと、TKPROFはトレースしたSQL文すべてのリストを作成します。このパラメータは、オプションのSQLスクリプトには影響しません。SQLスクリプトは、常に、トレースされたすべてのSQL文に対する挿入データを生成します。

AGGREGATE

AGGREGATE = NOを指定すると、TKPROFは同じSQLテキストに対する複数のユーザーのデータを集計しません。

INSERT

トレース・ファイルの統計をデータベースに格納するSQLスクリプトを作成します。TKPROFは、名前filename3を使用してこのスクリプトを作成します。このスクリプトは表を作成し、トレースされた各SQL文の統計が入っている行をこの表に挿入します。

SYS

ユーザーSYSが発行したSQL文、つまり再帰的SQL文の出力ファイルへのリストを使用可能または使用禁止にします。デフォルト値はYESで、TKPROFはこれらの文のリストを作成します。NOの値が指定されると、TKPROFはそれらのリストを作成しません。このパラメータは、オプションのSQLスクリプトには影響しません。SQLスクリプトは、常にトレースされたすべてのSQL文(再帰的SQL文を含む)に関する統計を挿入します。

TABLE

実行計画が出力ファイルに書き込まれる前に、TKPROFが一時的にこれらの実行計画を格納しておく表のスキーマと名前を指定します。指定された表が存在する場合、TKPROFはその表の行をすべて削除し、EXPLAIN PLAN文(より多くの行を表に書き込む)でその表を使用してからその表の行をすべて削除します。指定した表が存在しない場合、TKPROFはこの表を作成して使用し、使用後にこの表を削除します。

指定されたユーザーは、表に対してINSERT、SELECTおよびDELETE文を発行できる必要があります。表が存在しない場合は、CREATE TABLEおよびDROP TABLE文も発行できる必要があります。

このオプションを指定すると、EXPLAINの値に指定されている同一のユーザーについて複数のユーザーが同時にTKPROFを実行できます。これらの複数のユーザーが個別に、TABLEに異なる値を指定しておくことで、一時的なPLAN TABLEの処理時に互いのデータを破壊するような状況が発生することを防ぐことができます。

TKPROFでは、次の組合せがサポートされます。

- EXPLAINパラメータを指定し、TABLEパラメータを指定しない
TKPROFでは、EXPLAINパラメータによって指定されたユーザーのスキーマに含まれる表PROF$PLAN_TABLEが使用されます。

- TABLEパラメータを指定し、EXPLAINパラメータを指定しない
TKPROFではTABLEパラメータが無視されます。

PLAN TABLEが存在しない場合、TKPROFでは表PROF$PLAN_TABLEが作成され、最後に削除されます。

EXPLAIN

トレース・ファイルの各SQL文の実行計画を判断して、これらの実行計画を出力ファイルに書き込みます。TKPROFは実行計画の各ステップによって処理された行数も表示します。

TKPROFは、このパラメータに指定されたユーザーとパスワードを使用してOracle Databaseに接続した後、EXPLAIN PLAN文を発行して実行計画を判断します。指定されたユーザーは、CREATE SESSIONシステム権限を持っている必要があります。EXPLAINオプションが使用されている場合は、TKPROFが大きなトレース・ファイルを処理するのに要する時間が長くなります。

注意: インスタンスの始動直後に生成されたトレース・ファイルは、スタートアップ・プロセスのアクティビティを反映するデータを含みます。特に、これらは、システム・グローバル領域(SGA)のキャッシュがいっぱいになったときの不均衡な量のI/Oアクティビティを反映します。チューニングを行うときには、このようなトレース・ファイルは無視してください。

RECORD

トレース・ファイル内の非再帰的SQL文をすべて収録したSQLスクリプトを、指定したfilenameで作成します。このスクリプトを使用して、トレース・ファイルからユーザー・イベントを再実行できます。

WIDTH

EXPLAIN PLANなど、一部のTKPROF出力の出力行幅を制御する整数です。このパラメータは、TKPROF出力の後処理に役立ちます。

出力

この項では、TKPROFの出力について説明します。

TKPROFでのSQL文を発行するユーザーの識別

TKPROFは、各SQL文を発行したユーザーのユーザーIDを出力します。SQLトレース入力ファイルに複数のユーザーからの統計が含まれ、文が複数のユーザーによって発行された場合、TKPROFは、文を解析した最後のユーザーのIDを出力します。すべてのデータベース・ユーザーのユーザーIDは、列ALL_USERS.USER_IDのデータ・ディクショナリに表示されます。

TKPROFの表形式の統計

TKPROFは、SQLトレース機能によって戻されるSQL文の統計のリストを行と列に作成します。各行は、SQL文を処理する3つのステップの1つに対応します。統計は、次に示すCALL列の値によって識別されます。表18-4を参照してください。

表18-4 CALL列の値

CALLの値

意味

PARSE

適切なセキュリティ認可のチェック、および表、列、その他の参照オブジェクトの存在のチェックを行ってSQL文を実行計画に変換します。

EXECUTE

Oracle Databaseによる実際の文の実行です。INSERT文、UPDATE文およびDELETE文では、データの変更が行われます。SELECT文では、選択された行が識別されます。

FETCH

問合せを満たす行を取得します。フェッチは、SELECT文についてのみ実行されます。

SQLトレース機能の出力におけるその他の列は、すべての文の解析、実行、フェッチについての統計です。queryとcurrentの合計が、アクセスされたバッファの総数となります。これは論理I/O(LIO)とも呼ばれます。表18-5を参照してください。

表18-5 解析、実行およびフェッチのSQLトレース統計

SQLトレース統計

意味

COUNT

文が解析、実行またはフェッチされた回数です。

CPU

文に対するすべての解析コール、実行コールまたはフェッチ・コールにかかったCPU時間の合計(単位は秒)です。この値は、TIMED_STATISTICSが使用可能になっていない場合、ゼロ(0)になります。

ELAPSED

文に対するすべての解析コール、実行コールまたはフェッチ・コールにかかった経過時間の合計(単位は秒)です。この値は、TIMED_STATISTICSが使用可能になっていない場合、ゼロ(0)になります。

DISK

すべての解析コール、実行コールまたはフェッチ・コールに対して、ディスク上のデータファイルから物理的に読み取ったデータ・ブロックの総数です。

QUERY

すべての解析コール、実行コールまたはフェッチ・コールに対して、一貫モードで取り出されたバッファの総数です。通常バッファは 問合せに対して一貫モードで取り出されます。

CURRENT

現行モードで取り出されたバッファの総数です。INSERT、UPDATEおよびDELETEなどの文の場合、バッファはカレント・モードで取得される。

処理された行に関する統計は、ROWS列に表示されます。この列は、SQL文によって処理される行数を示します。この値には、SQL文の副問合せによって処理された行は含まれません。SELECT文の場合、戻された行数はフェッチ・ステップに表示されます。UPDATE文、DELETE文およびINSERT文の場合、処理された行数は実行ステップに表示されます。

注意:

行ソースの件数は、カーソルがクローズされたときに表示されます。SQL*Plusでは、ユーザー・カーソルは1つしかないため、文が実行されるたびに直前のカーソルがクローズされます。これにより、行ソースの件数が表示されます。PL/SQLには、独自のカーソル処理方法があり、親カーソルがクローズされても子カーソルはクローズされません。終了(または再接続)によって、件数が表示されます。

TKPROFのライブラリ・キャッシュ・ミス

TKPROFは、各SQL文の解析ステップと実行ステップの結果として生じるライブラリ・キャッシュ・ミス回数のリストも作成します。これらの統計は、表形式の統計に続く別の行に表示されます。文でライブラリ・キャッシュ・ミスが発生しなかった場合、TKPROFはその統計のリストを作成しません。「例」における解析ステップでは、ライブラリ・キャッシュ・ミスが1回発生し、実行ステップではライブラリ・キャッシュ・ミスは発生しませんでした。

TKPROFの行ソースの操作

TKPROF出力の行ソースの操作では、行に対して実行される各操作で処理される行数と、物理読取りおよび書込みなど、行ソースの追加情報が提供されます。

表18-6 行ソースの操作

行ソースの操作

意味

cr

行ソースにより実行される一貫性のある読取り。

r

行ソースにより実行される物理読取り。

w

行ソースにより実行される物理書込み。

time

時間(マイクロ秒)。

次のサンプルのTKPROF出力で、行ソース操作列内のcr、r、wおよびtimeの値をメモしておきます。

Rows     Row Source Operation
-------  ---------------------------------------------------
0  DELETE  (cr=43141 r=266947 w=25854 time=60235565 us)
28144   HASH JOIN ANTI (cr=43057 r=262332 w=25854 time=48830056 us)
51427    TABLE ACCESS FULL STATS$SQLTEXT (cr=3465 r=3463 w=0 time=865083 us)
647529    INDEX FAST FULL SCAN STATS$SQL_SUMMARY_PK
(cr=39592 r=39325 w=0 time=10522877 us) (object id 7409)

TKPROF内の待機イベント情報

待機イベント情報が存在する場合、TKPROF出力には次のようなセクションが含まれます。

Elapsed times include waiting on following events:
Event waited on                             Times   Max. Wait  Total Waited
----------------------------------------   Waited  ----------  ------------
db file sequential read                      8084        0.12          5.34
direct path write                             834        0.00          0.00
direct path write temp                        834        0.00          0.05
db file parallel read                           8        1.53          5.51
db file scattered read                       4180        0.07          1.45
direct path read                             7082        0.00          0.05
direct path read temp                        7082        0.00          0.44
rdbms ipc reply                                20        0.00          0.01
SQL*Net message to client                       1        0.00          0.00
SQL*Net message from client                     1        0.00          0.00

さらに、ファイルの最後でトレース・ファイル全体について待機イベントが要約されます。

待機イベント情報がそのセッションのトレース・ファイルに確実に書き込まれるようにするには、次のSQL文を実行します。

ALTER SESSION SET EVENTS '10046 trace name context forever, level 8';

例

例18-4 最もリソース集中型の文の印刷

SORTパラメータとPRINTパラメータの組合せを使用して大規模なトレース・ファイルを処理する場合は、リソースを最も多く使用する文のみを含むTKPROF出力ファイルを生成できます。次の文は、トレース・ファイルに格納されている、ほとんどの物理I/Oを生成した10個の文を印刷します。

TKPROF ora53269.trc ora53269.prf SORT = (PRSDSK, EXEDSK, FCHDSK) PRINT = 10

例18-5 SQLスクリプトの生成

この例では、TKPROFを実行して、examp12_jane_fg_sqlplus_007.trcという名前のトレース・ファイルを取り込み、outputa.prfという名前のフォーマット済の出力ファイルに書き込みます。

TKPROF examp12_jane_fg_sqlplus_007.trc OUTPUTA.PRF EXPLAIN=hr TABLE=hr.temp_plan_table_a INSERT=STOREA.SQL SYS=NO
SORT=(EXECPU,FCHCPU)

この例は、スクリーン上で複数行にわたって表示される可能性があるので、使用しているオペレーティング・システムによっては継続文字を使用する必要があります。

この例で使用されている他のパラメータに注意してください。

- EXPLAINの値によって、TKPROFがユーザーhrとして接続され、トレースされた各SQL文の実行計画を生成するためにEXPLAIN PLAN文が使用されます。これを使用してアクセス・パスおよび行ソース行数を取得できます。

注意:

SQL文のカーソルがクローズされていない場合、SQL文の実際の実行計画がTKPROF出力に自動的に含まれることはありません。この場合は、TKPROFでEXPLAINオプションを使用して、実行計画を生成できます。

- TABLEの値によって、TKPROFがスキーマscottの表temp_plan_table_aを一時的なPLAN TABLEとして使用します。

- INSERTの値によって、TKPROFがトレースされたすべてのSQL文に関する統計をデータベース内に格納するSQLスクリプト、STOREA.SQLを生成します。

- SYSパラメータに値NOが指定されていることにより、TKPROFは出力ファイルに再帰的SQL文のリストを作成しません。このため、一時表操作などのOracle Databaseの内部の文は無視できます。

- SORTの値によって、TKPROFはSQL文を出力ファイルに書き込む前に、SQL文の実行にかかったCPU時間と行のフェッチにかかったCPU時間の合計値の順にSQL文をソートします。効率を最大にするためには、SORTパラメータを常に使用してください。

例18-6 TKPROFヘッダー

この例では、TKPROFレポートに対するサンプル・ヘッダーを示します。

TKPROF: Release 12.1.0.0.2

Copyright (c) 1982, 2012, Oracle and/or its affiliates.  All rights reserved.

Trace file: /disk1/oracle/log/diag/rdbms/orcla/orcla/trace/orcla_ora_917.trc
Sort options: default

********************************************************************************
count    = number of times OCI procedure was executed
cpu      = cpu time in seconds executing
elapsed  = elapsed time in seconds executing
disk     = number of physical reads of buffers from disk
query    = number of buffers gotten for consistent read
current  = number of buffers gotten in current mode (usually for update)
rows     = number of rows processed by the fetch or execute call
********************************************************************************

例18-7 TKPROF本体

この例では、TKPROFレポートに対するサンプル・ボディを示します。

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.01       0.00          0          0          0           0
Execute      1      0.00       0.00          0          0          0           0
Fetch        0      0.00       0.00          0          0          0           0
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total        2      0.01       0.00          0          0          0           0

Misses in library cache during parse: 1
Optimizer mode: FIRST_ROWS
Parsing user id: 44

Elapsed times include waiting on following events:
Event waited on                             Times   Max. Wait  Total Waited
----------------------------------------   Waited  ----------  ------------
SQL*Net message to client                       1        0.00          0.00
SQL*Net message from client                     1       28.59         28.59
********************************************************************************

select condition
from
cdef$ where rowid=:1

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.00       0.00          0          0          0           0
Execute      1      0.00       0.00          0          0          0           0
Fetch        1      0.00       0.00          0          2          0           1
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total        3      0.00       0.00          0          2          0           1

Misses in library cache during parse: 1
Optimizer mode: CHOOSE
Parsing user id: SYS   (recursive depth: 1)

Rows     Row Source Operation
-------  ---------------------------------------------------
1  TABLE ACCESS BY USER ROWID OBJ#(31) (cr=1 r=0 w=0 time=151 us)

********************************************************************************

SELECT last_name, job_id, salary
FROM employees
WHERE salary =
(SELECT max(salary) FROM employees)

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.02       0.01          0          0          0           0
Execute      1      0.00       0.00          0          0          0           0
Fetch        2      0.00       0.00          0         15          0           1
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total        4      0.02       0.01          0         15          0           1

Misses in library cache during parse: 1
Optimizer mode: FIRST_ROWS
Parsing user id: 44

Rows     Row Source Operation
-------  ---------------------------------------------------
1  TABLE ACCESS FULL EMPLOYEES (cr=15 r=0 w=0 time=1743 us)
1   SORT AGGREGATE (cr=7 r=0 w=0 time=777 us)
107    TABLE ACCESS FULL EMPLOYEES (cr=7 r=0 w=0 time=655 us)

Elapsed times include waiting on following events:
Event waited on                             Times   Max. Wait  Total Waited
----------------------------------------   Waited  ----------  ------------
SQL*Net message to client                       2        0.00          0.00
SQL*Net message from client                     2        9.62          9.62
********************************************************************************

********************************************************************************
delete
from stats$sqltext st
where (hash_value, text_subset) not in
(select --+ hash_aj
hash_value, text_subset
from stats$sql_summary ss
where (   (   snap_id     < :lo_snap
or snap_id     > :hi_snap
)
and dbid            = :dbid
and instance_number = :inst_num
)
or (   dbid            != :dbid
or instance_number != :inst_num)
)

call     count       cpu    elapsed       disk      query    current rows
------- ------  -------- ---------- ---------- ---------- ---------- ----------
Parse        1      0.00       0.00          0          0          0          0
Execute      1     29.60      60.68     266984      43776     131172      28144
Fetch        0      0.00       0.00          0          0          0          0
------- ------  -------- ---------- ---------- ---------- ---------- ----------
total        2     29.60      60.68     266984      43776     131172      28144

Misses in library cache during parse: 1
Misses in library cache during execute: 1
Optimizer mode: CHOOSE
Parsing user id: 22

Rows     Row Source Operation
-------  ---------------------------------------------------
0  DELETE  (cr=43141 r=266947 w=25854 time=60235565 us)
28144   HASH JOIN ANTI (cr=43057 r=262332 w=25854 time=48830056 us)
51427    TABLE ACCESS FULL STATS$SQLTEXT (cr=3465 r=3463 w=0 time=865083 us)
647529    INDEX FAST FULL SCAN STATS$SQL_SUMMARY_PK
(cr=39592 r=39325 w=0 time=10522877 us) (object id 7409)

Elapsed times include waiting on following events:
Event waited on                             Times   Max. Wait  Total Waited
----------------------------------------   Waited  ----------  ------------
db file sequential read                      8084        0.12          5.34
direct path write                             834        0.00          0.00
direct path write temp                        834        0.00          0.05
db file parallel read                           8        1.53          5.51
db file scattered read                       4180        0.07          1.45
direct path read                             7082        0.00          0.05
direct path read temp                        7082        0.00          0.44
rdbms ipc reply                                20        0.00          0.01
SQL*Net message to client                       1        0.00          0.00
SQL*Net message from client                     1        0.00          0.00
********************************************************************************

例18-8 TKPROFのサマリー

この例では、TKPROFレポートに対するサマリーを示します。

OVERALL TOTALS FOR ALL NON-RECURSIVE STATEMENTS

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        4      0.04       0.01          0          0          0           0
Execute      5      0.00       0.04          0          0          0           0
Fetch        2      0.00       0.00          0         15          0           1
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total       11      0.04       0.06          0         15          0           1

Misses in library cache during parse: 4
Misses in library cache during execute: 1
Elapsed times include waiting on following events:
Event waited on                             Times   Max. Wait  Total Waited
----------------------------------------   Waited  ----------  ------------
SQL*Net message to client                       6        0.00          0.00
SQL*Net message from client                     5       77.77        128.88

OVERALL TOTALS FOR ALL RECURSIVE STATEMENTS

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.00       0.00          0          0          0           0
Execute      1      0.00       0.00          0          0          0           0
Fetch        1      0.00       0.00          0          2          0           1
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total        3      0.00       0.00          0          2          0           1

Misses in library cache during parse: 1
5  user  SQL statements in session.
1  internal SQL statements in session.
6  SQL statements in session.
********************************************************************************
Trace file: main_ora_27621.trc
Trace file compatibility: 9.00.01
Sort options: default
1  session in tracefile.
5  user  SQL statements in trace file.
1  internal SQL statements in trace file.
6  SQL statements in trace file.
6  unique SQL statements in trace file.
76  lines in trace file.
128  elapsed seconds in trace file.

アプリケーションのトレースのビュー

このセクションでは、次のトピックについて説明します。

- トレース統計の公開に関連するビュー

- トレースの有効化に関連するビュー

トレース統計の公開に関連するビュー

収集した統計情報は、次のV$ビューおよびデータ・ディクショナリ・ビューで表示できます。

収集した統計情報は、次のV$ビューで表示できます。

- DBA_ENABLED_AGGREGATIONSビューは、現在使用可能になっている統計に対して収集されたグローバルな統計を表示します。

- V$CLIENT_STATSビューは、特定のクライアント識別子に対して収集された統計を表示します。

- V$SERVICE_STATSビューは、特定のサービスに対して収集された統計を表示します。

- V$SERV_MOD_ACT_STATSビューは、指定されたサービス、モジュールおよびアクションの組合せに対して収集された統計を表示します。

- V$SERVICEMETRICビューは、データベース・コールの経過時間とCPUの使用に対して収集された統計を表示します。

関連項目:

V$ビューおよびデータ・ディクショナリ・ビューの詳細は、『Oracle Databaseリファレンス』を参照してください。

トレースの有効化に関連するビュー

Cloud ControlのレポートまたはDBA_ENABLED_TRACESビューに、未処理のトレースを表示できます。

DBA_ENABLED_TRACESビューでは、トレース・タイプを含め、トレースを使用可能にした方法に関する詳細を判断できます。トレース・タイプは、クライアント識別子、セッション、サービス、データベース、またはサービス、モジュールおよびアクションの組合せについてトレースが使用可能かどうかを指定します。

第VIII部 自動SQLチューニング

SQLチューニング・アドバイザおよびSQLアクセス・アドバイザは、SQLチューニングの推奨事項を提供する組込みツールです。

この部には次の章が含まれます:

- SQLチューニング・セットの管理

- SQLチューニング・アドバイザを使用したSQLの分析

- SQLアクセス・アドバイザを使用したアクセス・パスの最適化

19 SQLチューニング・セットの管理

この章の内容は次のとおりです。

- SQLチューニング・セットについて

- SQLチューニング・セットの作成

- SQLチューニング・セットのロード

- SQLチューニング・セットの内容の表示

- SQLチューニング・セットの変更

- SQLチューニング・セットの転送

- SQLチューニング・セットの削除

SQLチューニング・セットについて

SQLチューニング・セット(STS)は、チューニング・ツールへの入力として使用できるデータベース・オブジェクトです。

STSに含まれるのは、次のとおりです。

- SQL文のセット

- 関連する実行コンテキスト(ユーザー・スキーマ、アプリケーション・モジュール名およびアクション、バインド値のリストおよびカーソルのSQLのコンパイルの環境など)

- 関連する基本実行統計(経過時間、CPUタイム、バッファ読取り、ディスク読取り、処理された行数、カーソル・フェッチ、実行数、実行完了数、オプティマイザ・コストおよびコマンドのタイプなど)

- 各SQL文に関連する実行計画および行ソースの統計(オプション)

このデータベースは、SQLチューニング・セットをデータベース提供のスキーマに格納します。

この項の内容は次のとおりです。

- SQLチューニング・セットの目的

- SQLチューニング・セットの概念

- SQLチューニング・セットのユーザー・インタフェース

- SQLチューニング・セットの基本タスク

注意:

STSをプラガブル・データベースとともに使用すると、データの可視性と権限の要件が一致しない場合があります。コンテナ・データベース(CDB)内での管理機能の動作をまとめた表が記載されている『Oracle Database管理者ガイド』を参照してください。

SQLチューニング・セットの目的

STSを使用すると、SQL文と関連するメタデータを単一のデータベース・オブジェクトにグループ化し、そのオブジェクトを使用してチューニングに関する目標を達成できます。具体的には、SQLチューニング・セットによって次の目標が達成されます。

- パフォーマンス・チューニング・アドバイザへの入力の提供
STSは、SQLチューニング・アドバイザ、SQLアクセス・アドバイザ、SQLパフォーマンス・アナライザなど、複数のデータベース・アドバイザの入力として使用できます。

- データベース間でのSQLの転送
SQLチューニングセットを別のデータベースにエクスポートすることで、SQLワークロードをデータベース間で転送してリモート・パフォーマンス診断およびチューニングを実行できます。本番データベースにパフォーマンスが最適でないSQL文がある場合、開発者が直接本番システム上で調査およびチューニングを実行することは望ましくありません。DBAにより、開発者が安全に分析およびチューニングできるテスト用データベースに、問題のあるSQL文を転送できます。

SQLチューニング・セットの概念

STSを作成するには、SQL文をソースからSTSにロードする必要があります。

図19-1のように、使用可能なソースには、自動ワークロード・リポジトリ(AWR)、共有SQL領域、ユーザーによって提供されたカスタマイズ済のSQL、トレース・ファイル、他のSTSなどがあります。

図19-1 SQLチューニング・セット

SQLチューニング・セットでは、次の操作を実行できます。

- アプリケーション・モジュール名とアクション、または任意の実行統計を使用して、SQL文をフィルタできます。

- SQL文を実行統計の任意の組合せに基づいてランク付けできます。

- アドバイザの入力として使用したり、それを異なるデータベースに転送したりできます。

関連項目:

AWRの詳細は、『Oracle Databaseパフォーマンス・チューニング・ガイド』を参照してください

SQLチューニング・セットのユーザー・インタフェース

Oracle Enterprise Manager Cloud Control (Cloud Control)またはPL/SQLパッケージを使用すると、SQLチューニング・セットを管理できます。Cloud Controlをお薦めします。

Cloud Controlでの「SQLチューニング・セット」ページへのアクセス

Cloud ControlのSQLチューニング・セット・ページは、SQLチューニング・セットに関係する多くの操作を実行できる開始ページです。

SQLチューニング・セット・ページにアクセスする手順は次のとおりです。

1. 「Cloud Controlのデータベース・ホーム・ページへのアクセス」の説明に従って、「データベース・ホーム」ページにアクセスします。

2. 「パフォーマンス」メニューから「SQL」を選択し、さらに「SQLチューニング・セット」を選択します。
SQLチューニング・セット・ページは、図19-2のように表示されます。

図19-2 SQLチューニング・セット

関連項目:

Oracle Database 2日でパフォーマンス・チューニング・ガイド

SQLチューニング・セットへのコマンドライン・インタフェース

コマンドラインでは、DBMS_SQLTUNEパッケージを使用してSQLチューニング・セットを管理できます。所有するSQLチューニング・セットを管理するためのADMINISTER SQL TUNING SETシステム権限が必要です。または、任意のSQLチューニング・セットを管理するためのADMINISTER ANY SQL TUNING SETシステム権限が必要です。

関連項目:

DBMS_SQLTUNEの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

SQLチューニング・セットの基本タスク

DBMS_SQLTUNEは、SQLチューニング・セットの作成、使用および削除に必要なプロシージャを提供します。

次の図は、基本ワークフローを示しています。

図19-3 SQLチューニング・セットAPI

通常、STS操作を実行する順序は次のとおりです。

1. 新規STSを作成します。
このタスクについては、「SQLチューニング・セットの作成」を参照してください。

2. そのSTSをSQL文および関連するメタデータとともにロードします。
このタスクについては、「SQLチューニング・セットのロード」を参照してください。

3. オプションで、STSの内容を表示します。
このタスクについては、「SQLチューニング・セットの内容の表示」を参照してください。

4. オプションで、STSの内容を更新または削除します。
このタスクについては、「SQLチューニング・セットの変更」を参照してください。

5. 入力にSTSを使用してチューニング・タスクを作成します。

6. オプションで、他のデータベースにSTSを転送します。
このタスクについては、「SQLチューニング・セットの転送」を参照してください。

7. 完了時にSTSを削除します。
このタスクについては、「SQLチューニング・セットの削除」を参照してください。

SQLチューニング・セットの作成

データベース内に空のSTSを作成するには、DBMS_SQLTUNE.CREATE_SQLSETプロシージャを実行します。プロシージャのかわりにファンクションを使用すると、データベースによってSTSの名前が生成されます。

次の表では、一部のプロシージャ・パラメータを説明します。

表19-1 DBMS_SQLTUNE.CREATE_SQLSETパラメータ

パラメータ

説明

sqlset_name

STSの名前

description

STSに関するオプションの説明

前提条件

このチュートリアルでは、SQLT_WKLD_STSという名前のSTSを作成するものとします。

STSを作成する手順は次のとおりです。

1. 適切な権限でデータベースにSQL*Plusを接続し、DBMS_SQLTUNE.CREATE_SQLSETプロシージャを実行します。
たとえば、次のPL/SQLプログラムを実行します。

BEGIN
DBMS_SQLTUNE.CREATE_SQLSET (
sqlset_name  => 'SQLT_WKLD_STS'
,   description  => 'STS to store SQL from the private SQL area'
);
END;

2. オプションで、STSが作成されたことを確認します。
次の例では、現行のユーザーによって所有されているすべてのSQLチューニング・セットのステータスを問い合せます。

COLUMN NAME FORMAT a20
COLUMN COUNT FORMAT 99999
COLUMN DESCRIPTION FORMAT a30

SELECT NAME, STATEMENT_COUNT AS "SQLCNT", DESCRIPTION
FROM   USER_SQLSET;

出力例は次のように表示されます。

NAME                 SQLCNT DESCRIPTION
-------------------- ------ ------------------------------
SQLT_WKLD_STS             2 SQL Cache

関連項目:

詳細な参照情報については、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

SQLチューニング・セットのロード

STSをSQL文とともにロードするには、DBMS_SQLTUNE.LOAD_SQLSETプロシージャを実行します。STSにデータを移入するための標準ソースは、AWR、他のSTSまたは共有SQL領域です。ワークロード・リポジトリおよびSQLチューニング・セットのどちらの場合も、事前定義済のテーブル・ファンクションにより、新しいSTSに移入する列をソースから選択できます。

表19-2に、プロシージャの一部のDBMS_SQLTUNE.LOAD_SQLSETパラメータの説明を示します。完全なリファレンス情報については、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

表19-2 DBMS_SQLTUNE.LOAD_SQLSETのパラメータ

パラメータ

説明

populate_cursor

STSの入力に使用するカーソル参照を指定します。

load_option

STSへの文のロード方法を指定します。指定可能な値は、INSERT (デフォルト)、UPDATEおよびMERGEです。

DBMS_SQLTUNE.SELECT_CURSOR_CACHEファンクションは、指定されたフィルタに従って、SQL文を共有SQL領域から収集します。このファンクションは、各データ・ソースで検出されるSQL IDまたはPLAN_HASH_VALUEの組合せごとに1つのSQLSET_ROWを戻します。

CAPTURE_CURSOR_CACHE_SQLSETファンクションを使用すると、特定の間隔で共有SQL領域を繰り返しポーリングできます。このファンクションは、SELECT_CURSOR_CACHEおよびLOAD_SQLSETプロシージャを繰り返しコールする場合よりも効率的です。また、高負荷SQL文のワークロードのみを取得するAWR、またはデータ・ソースに1回のみアクセスするLOAD_SQLSETプロシージャとは対照的に、ワークロード全体を効果的に取得します。

前提条件

このチュートリアルの前提条件は、次のとおりです。

- SELECT_CURSOR_CACHEファンクションで提供されるフィルタは、現行のユーザーが実行するSQL文の一部として評価されます。したがって、それらのフィルタは、ユーザーのセキュリティ権限で実行され、ユーザーがアクセスできるすべての構成メンバーおよび副問合せを含んでいますが、それ以外のものは含んでいません。

- 現行のユーザーは、共有SQL領域のビューに対する権限を持っている必要があります。

前提条件

このチュートリアルでは、SQLT_WKLD_STSという名前のSQLチューニング・セットに共有SQL領域の文をロードするものとします。

STSをロードする手順は次のとおりです。

1. 適切な権限を持つユーザーとして、SQL*Plusをデータベースに接続します。

2. DBMS_SQLTUNE.LOAD_SQLSETプロシージャを実行します。
たとえば、次のPL/SQLプログラムを実行すると、shスキーマに属するすべてのカーソル・キャッシュ文をSQLチューニング・セットに移入できます。

DECLARE
c_sqlarea_cursor DBMS_SQLTUNE.SQLSET_CURSOR;
BEGIN
OPEN c_sqlarea_cursor FOR
SELECT VALUE(p)
FROM   TABLE(
DBMS_SQLTUNE.SELECT_CURSOR_CACHE(
' module = ''SQLT_WKLD'' AND parsing_schema_name = ''SH'' ')
) p;
-- load the tuning set
DBMS_SQLTUNE.LOAD_SQLSET (
sqlset_name     => 'SQLT_WKLD_STS'
,   populate_cursor =>  c_sqlarea_cursor
);
END;
/

SQLチューニング・セットの内容の表示

STSを作成し、データを移入したら、DBMS_SQLTUNE.SELECT_SQLSETファンクションを実行して、STSの内容を(オプションでフィルタ条件を使用して)読み取ります。

PL/SQL パイプライン・テーブル・ファンクションを使用するSELECT_SQLSETの出力を選択し、行のコレクションを入力として受け入れます。SELECT文のFROMリストで表演算子のオペランドとしてテーブル・ファンクションを起動します。

表19-3に、SELECT_SQLSETファンクションの一部のパラメータの説明を示します。完全なリファレンス情報については、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

表19-3 DBMS_SQLTUNE.SELECT_SQLSETのパラメータ

パラメータ

説明

basic_filter

SQLSET_ROWの属性に対して定義されたSTSからSQLをフィルタするためのSQL述語。

object_filter

共有SQL領域から選択されたSQLのオブジェクト・リストに含まれるオブジェクトを指定します。

表19-4に、SQLSET_ROWオブジェクトの一部の属性の説明を示します。これらの属性は、TABLE(DBMS_SQLTUNE.SELECT_SQLSET())を問い合せたときに列として表示されます。

表19-4 SQLSET_ROWの属性

パラメータ

説明

parsing_schema_name

SQLの解析が行われるスキーマ

elapsed_time

このSQL文で経過した秒数の合計

buffer_gets

このSQL文のバッファ取得回数(データベースがブロックにアクセスした回数)の合計

前提条件

このチュートリアルでは、SQLT_WKLD_STSという名前のSTSの内容を表示するものとします。

STSの内容を表示する手順は次のとおりです。

1. 適切な権限でデータベースにSQL*Plusを接続し、TABLEファンクションを使用してSTSの内容を問い合せます。
たとえば、次の問合せを実行します。

COLUMN SQL_TEXT FORMAT a30
COLUMN SCH FORMAT a3
COLUMN ELAPSED FORMAT 999999999

SELECT SQL_ID, PARSING_SCHEMA_NAME AS "SCH", SQL_TEXT,
ELAPSED_TIME AS "ELAPSED", BUFFER_GETS
FROM   TABLE( DBMS_SQLTUNE.SELECT_SQLSET( 'SQLT_WKLD_STS' ) );

出力例は次のように表示されます。

SQL_ID        SCH SQL_TEXT                          ELAPSED BUFFER_GETS
------------- --- ------------------------------ ---------- -----------
79f8shn041a1f SH  select * from sales where quan    8373148       24016
tity_sold < 5 union select * f
rom sales where quantity_sold
> 500

2cqsw036j5u7r SH  select promo_name, count(*) c     3557373         309
from promotions p, sales s whe
re s.promo_id = p.promo_id and
p.promo_category = 'internet'
group by p.promo_name order b
y c desc

fudq5z56g642p SH  select sum(quantity_sold) from    4787891       12118
sales s, products p where s.p
rod_id = p.prod_id and s.amoun
t_sold > 20000 and p.prod_name
= 'Linen Big Shirt'

bzmnj0nbvmz8t SH  select * from sales where amou     442355       15281
nt_sold = 4

2. オプションで、ユーザー固有の条件に基づいて結果をフィルタします。
次の例では、バッファ取得に対するディスク読取りの比率が50%以上の文を表示します。

COLUMN SQL_TEXT FORMAT a30
COLUMN SCH FORMAT a3
COLUMN BUF_GETS FORMAT 99999999
COLUMN DISK_READS FORMAT 99999999
COLUMN %_DISK FORMAT 9999.99
SELECT sql_id, parsing_schema_name as "SCH", sql_text,
buffer_gets as "B_GETS",
disk_reads, ROUND(disk_reads/buffer_gets*100,2) "%_DISK"
FROM TABLE( DBMS_SQLTUNE.SELECT_SQLSET(
'SQLT_WKLD_STS',
'(disk_reads/buffer_gets) >= 0.50' ) );

出力例は次のように表示されます。

SQL_ID        SCH SQL_TEXT                       B_GETS DISK_READS %_DISK
------------- --- ------------------------------ ------ ---------- -------
79f8shn041a1f SH  select * from sales where quan  24016      17287  71.98
tity_sold < 5 union select * f
rom sales where quantity_sold
> 500

fudq5z56g642p SH  select sum(quantity_sold) from  12118       6355  52.44
sales s, products p where s.p
rod_id = p.prod_id and s.amoun
t_sold > 20000 and p.prod_name
= 'Linen Big Shirt'

SQLチューニング・セットの変更

SQL文をSTSから削除するには、DBMS_SQLTUNE.DELETE_SQLSETプロシージャを使用します。

UPDATE_SQLSETプロシージャを使用すると、STS名およびSQL IDで識別される既存のSTS内のSQL文の属性(PRIORITYまたはOTHERなど)を更新できます。

前提条件

このチュートリアルでは、SQLT_WKLD_STSを次のように変更するものとします。

- フェッチ回数が100を超えるすべてのSQL文を削除します。

- IDがfudq5z56g642pのSQL文の優先順位を1に変更します。優先順位は、SQLチューニング・アドバイザを実行するときのランク付け基準として使用できます。

STSの内容を変更する手順は次のとおりです。

1. 適切な権限でデータベースにSQL*Plusを接続し、オプションでTABLEファンクションを使用してSTSの内容を問い合せます。
たとえば、次の問合せを実行します。

SELECT SQL_ID, ELAPSED_TIME, FETCHES, EXECUTIONS
FROM   TABLE(DBMS_SQLTUNE.SELECT_SQLSET('SQLT_WKLD_STS'));

出力例は次のように表示されます。

SQL_ID        ELAPSED_TIME    FETCHES EXECUTIONS
------------- ------------ ---------- ----------
2cqsw036j5u7r      3407459          2          1
79f8shn041a1f      9453965      61258          1
bzmnj0nbvmz8t       401869          1          1
fudq5z56g642p      5300264          1          1

2. ユーザー固有の条件に基づいてSQL文を削除します。
SQLSET_ROWの属性に対して定義されたSTSからSQLをフィルタするには、basic_filter述語を使用します。次の例では、フェッチ回数が100を超えるSTS内の文をすべて削除します。

BEGIN
DBMS_SQLTUNE.DELETE_SQLSET (
sqlset_name  => 'SQLT_WKLD_STS'
,     basic_filter => 'fetches > 100'
);
END;
/

3. SQL文の属性値を設定します。
次の例では、文2cqsw036j5u7rの優先順位を1に設定します。

BEGIN
DBMS_SQLTUNE.UPDATE_SQLSET (
sqlset_name     => 'SQLT_WKLD_STS'
,     sql_id          => '2cqsw036j5u7r'
,     attribute_name  => 'PRIORITY'
,     attribute_value =>  1
);
END;
/

4. オプションで、STSを問い合せて、目的の変更が加えられたことを確認します。
たとえば、次の問合せを実行します。

SELECT SQL_ID, ELAPSED_TIME, FETCHES, EXECUTIONS, PRIORITY
FROM   TABLE(DBMS_SQLTUNE.SELECT_SQLSET('SQLT_WKLD_STS'));

出力例は次のように表示されます。

SQL_ID        ELAPSED_TIME    FETCHES EXECUTIONS   PRIORITY
------------- ------------ ---------- ---------- ----------
2cqsw036j5u7r      3407459          2          1          1
bzmnj0nbvmz8t       401869          1          1
fudq5z56g642p      5300264          1          1

関連項目:

詳細は、『Oracle Database PL/SQLパッケージ・プロシージャおよびタイプ・リファレンス』を参照してください

SQLチューニング・セットの転送

Oracle Database 10gリリース2 (10.2)以降で作成された任意のデータベースにSTSを転送できます。これは、SQLパフォーマンス・アナライザを使用してテスト用データベースで回帰をチューニングする場合に役立ちます。

SQLチューニング・セットの転送について

データベース間のSQLチューニング・セットの転送は、SQLチューニング・セットとステージング表間でコピーして、他のツールを使用してステージング表を宛先データベースに移行することを意味します。最も一般的なツールは、Oracle Data Pumpまたはデータベース・リンクです。

SQLチューニング・セットを転送するための基本手順

SQLチューニング・セットを転送するには、STSをエクスポートし、ダンプ・ファイルを転送した後、ダンプ・ファイルをインポートする必要があります。

次の図は、Oracle Data Pumpとftpを使用したプロセスを示しています。

図19-4 SQLチューニング・セットの転送

図19-4に示すとおり、次のような手順があります。

1. 本番データベースで、DBMS_SQLTUNE.PACK_STGTAB_SQLSETを使用してSTSをステージング表にパックします。

2. Oracle Data Pumpを使用して、STSをステージング表から.dmpファイルにエクスポートします。

3. ftpなどの転送ツールを使用して本番ホストからテスト・ホストに.dmpファイルを転送します。

4. テスト・データベースで、Oracle Data Pumpを使用して、STSを.dmpファイルからステージング表にインポートします。

5. DBMS_SQLTUNE.UNPACK_STGTAB_SQLSETを使用して、STSをステージング表からアンパックします。

CON_DBID値が異なる場合のSQLチューニング・セットを転送するための基本手順

STSを転送するとき、ソース・データベースと宛先データベースのcon_dbidが異なる場合に、STS内の各SQL文のcon_dbidを再マップする必要があります。

con_dbid値が異なるのは、次の状況です。

- 単一インスタンスのデータベースであり、そのインスタンスが再起動されている

- Oracle RACデータベースに様々なインスタンスがある

- PDBが異なっている

- 非CDBとCDBが存在する

再マップする基本手順は次のとおりです。

1. DBMS_SQLTUNE.PACK_STGTAB_SQLSETを使用してSTSをステージング表にパックします。

2. DBMS_SQLTUNE.REMAP_STGTAB_SQLSETを使用して、ステージング表内の各con_dbidを再マップします。

3. STSをエクスポートします。

4. 転送先のCDBでSTSをアンパックします。

例19-1 非CDBからCDBにSTSを転送する場合のCON_DBIDの再マップ

この例では、STS_for_transportという名前のSTSを非CDBからCDBに転送します。ソース非CDB上で、DBMS_SQLTUNE.PACK_STGTAB_SQLSETプロシージャを使用して、すでにSTSをソース・ステージング表src_stg_tblにパックしています。転送先のCDBのコンテナIDは、12345です。

転送元の非CDBで、次のコマンドを実行します。

VARIABLE con_dbid_src NUMBER;

EXEC SELECT UNIQUE con_dbid INTO :con_dbid_src FROM src_stg_tbl;

BEGIN
DBMS_SQLTUNE.REMAP_STGTAB_SQLSET (
staging_table_name   => 'src_stg_tbl'
,   staging_schema_owner => 'dba1'
,   old_sqlset_name      => 'STS_for_transport'
,   old_con_dbid         => :con_dbid_src
,   new_con_dbid         => 12345);
END;

ステージング表のコンテンツをエクスポートして、引き続き通常の転送手順の使用できます。

関連項目:

REMAP_STGTAB_SQLSETの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください

DBMS_SQLTUNEを使用したSQLチューニング・セットの転送

SQLチューニング・セットを転送するには、DBMS_SQLTUNEパッケージの3つのサブプログラムを使用します。

次の表に、SQLチューニング・セットの転送に関連するDBMS_SQLTUNEプロシージャの説明を示します。

表19-5 SQLチューニング・セットを転送するためのDBMS_SQLTUNEプロシージャ

プロシージャ

説明

CREATE_STGTAB_SQLSET

エクスポートされたSQLチューニング・セットを保持するステージング表を作成します。

PACK_STGTAB_SQLSET

ステージング表にSQLチューニング・セットを移入します。

UNPACK_STGTAB_SQLSET

SQLチューニング・セットをステージング表からデータベースにコピーします。

前提条件

このチュートリアルでは、次のことが前提となっています。

- 現在のリリースで作成した本番データベースに、低下したSQLを含むSTSが存在する場合。

- Oracle Database 11gリリース2 (11.2)で作成したリモートのテスト用データベースでSQLパフォーマンス・アナライザの試行を実行する場合。

- STSを本番データベースからテスト用データベースにコピーして、SQLパフォーマンス・アナライザの試行で回帰をチューニングする場合。

- Oracle Database Pumpを使用して、データベース・ホスト間でSQLチューニング・セットを転送する場合。

STSを転送する手順は次のとおりです。

1. 管理者権限で、SQL*Plusを本番データベースに接続します。

2. CREATE_STGTAB_SQLSETプロシージャを使用して、エクスポートされたSQLチューニング・セットを保持するステージング表を作成します。
次の例では、dba1にmy_11g_staging_tableを作成し、ステージング表の形式を11.2に指定します。

BEGIN
DBMS_SQLTUNE.CREATE_STGTAB_SQLSET (
table_name  => 'my_10g_staging_table'
,   schema_name => 'dba1'
,   db_version  => DBMS_SQLTUNE.STS_STGTAB_11_2_VERSION
);
END;
/

3. PACK_STGTAB_SQLSETプロシージャを使用して、ステージング表にSQLチューニング・セットを移入します。
次の例では、dba1.my_11g_staging_tableに、hrが所有するSTS my_stsを移入します。

BEGIN
DBMS_SQLTUNE.PACK_STGTAB_SQLSET (
sqlset_name         => 'sqlt_wkld_sts'
,   sqlset_owner        => 'sh'
,   staging_table_name  => 'my_11g_staging_table'
,   staging_schema_owner => 'dba1'
,   db_version          => DBMS_SQLTUNE.STS_STGTAB_11_2_VERSION
);
END;
/

4. 必要に応じて、「CON_DBID値が異なる場合のSQLチューニング・セットを転送するための基本手順」の説明に従って、STS内の文のコンテナIDの値を再マップします。

5. Oracle Data Pumpを使用して、ステージング表のコンテンツをエクスポートします。
たとえば、オペレーティング・システム・プロンプトでexpdpコマンドを実行します。

expdp dba1 DIRECTORY=dpump_dir1 DUMPFILE=sts.dmp TABLES=my_11g_staging_table

6. dumpファイルをテスト・データベースのホストに転送します。

7. 管理者としてテスト・ホストにログインし、Oracle Data Pumpを使用してステージング表の内容をインポートします。
たとえば、オペレーティング・システム・プロンプトでimpdpコマンドを実行します。

impdp dba1 DIRECTORY=dpump_dir1 DUMPFILE=sts.dmp TABLES=my_11g_staging_table

8. テスト・データベースで、UNPACK_STGTAB_SQLSETプロシージャを使用してステージング表からデータベースにSQLチューニング・セットをコピーします。
次の例は、SQLチューニング・セットをアンパックする方法を示しています。

BEGIN
DBMS_SQLTUNE.UNPACK_STGTAB_SQLSET (
sqlset_name        => '%'
,   replace            => true
,   staging_table_name => 'my_11g_staging_table');
END;
/

関連項目:

DBMS_SQLTUNE.UNPACK_STGTAB_SQLSETの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください

SQLチューニング・セットの削除

データベースからSTSを削除するには、DBMS_SQLTUNE.DROP_SQLSETプロシージャを実行します。

前提条件

削除するSTSがチューニング・タスクによって現在使用されていないことを確認します。既存のチューニング・タスクがこのSTSを使用している場合は、STSを削除する前に、そのタスクを削除します。削除しないと、データベースからORA-13757エラーが発行されます。

前提条件

このチュートリアルでは、SQLT_WKLD_STSという名前のSTSを削除するものとします。

STSを削除する手順は次のとおりです。

1. SQL*Plusを起動し、適切な権限でデータベースにログインします。

2. DBMS_SQLTUNE.DROP_SQLSETプロシージャを実行します。
たとえば、次のPL/SQLプログラムを実行します。

BEGIN
DBMS_SQLTUNE.DROP_SQLSET( sqlset_name => 'SQLT_WKLD_STS' );
END;
/

3. オプションで、STSが削除されたことを確認します。
次の例では、現行のユーザーによって所有されているSQLT_WKLD_STSという名前のSQLチューニング・セットの数をカウントします(出力例も示します)。

SELECT COUNT(*)
FROM   USER_SQLSET
WHERE  NAME = 'SQLT_WKLD_STS';

COUNT(*)
----------
0

関連項目:

DBMS_SQLTUNEのSTSプロシージャの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

20 SQLチューニング・アドバイザを使用したSQLの分析

この章では、SQLチューニング・アドバイザの概要およびタスクについて説明します。

この章の内容は次のとおりです。

- SQLチューニング・アドバイザについて

- 自動SQLチューニング・タスクの管理

- オンデマンドでのSQLチューニング・アドバイザの実行

SQLチューニング・アドバイザについて

SQLチューニング・アドバイザは、Oracle Database Tuning Packに含まれるSQL診断ソフトウェアです。アドバイザの入力として1つ以上のSQL文を発行し、文のチューニング方法に関するアドバイスや推奨事項、および理論的根拠や予測されるメリットを受け取ることができます。

この項の内容は次のとおりです。

- SQLチューニング・アドバイザの目的

- SQLチューニング・アドバイザのアーキテクチャ

- 自動チューニング・オプティマイザの分析

SQLチューニング・アドバイザの目的

SQLチューニング・アドバイザは、パフォーマンスが最適でないSQL文に関する問題を解決するためのメカニズムです。

SQLチューニング・アドバイザを使用すると、高負荷SQL文のパフォーマンスを向上するための推奨事項を取得し、最適な計画を実行することによってパフォーマンスの低下を防ぐことができます。

次のようなチューニングの推奨事項があります。

- オブジェクト統計の収集

- 索引の作成

- SQL文のリライト

- SQLプロファイルの作成

- SQL計画ベースラインの作成

SQLチューニング・アドバイザによって生成される推奨事項は、次に示す特定の目標の達成に役立ちます。

- 手間のかかる手動チューニングを回避します。
高付加SQL文の識別とチューニングは、専門家にとっても困難な作業です。SQLチューニング・アドバイザは、オプティマイザを使用して自動的にSQLをチューニングします。

- 自動的に推奨事項を生成し、SQLプロファイルを実装します。
夜間のメンテナンス・ウィンドウで実行されるように、自動SQLチューニング・タスクを構成できます。このように起動すると、アドバイザは自動的に推奨事項を生成し、SQLプロファイルを実装できます。

- データベースによって生成された統計を分析して最適な計画を作成します。
データベースには、それ自体の操作に関する大量の統計が含まれます。SQLチューニング・アドバイザは、内部情報の詳細なマイニングと分析を実行して、実行計画を最適化できます。

- 開発者がSQLを本番システムではなくテスト・システム上でチューニングできるようにします。
本番データベースにパフォーマンスが最適でないSQL文がある場合、開発者が直接本番システム上で調査およびチューニングを実行することは望ましくありません。DBAにより、開発者が安全に分析およびチューニングできるテスト用データベースに、問題のあるSQL文を転送できます。

複数の文をチューニングする場合、SQLチューニング・アドバイザは文間の相互依存を認識しません。SQLチューニング・アドバイザを多数の文に対して実行すると、チューニングに関する推奨事項を取得できます。

注意:

SQLチューニング・アドバイザをプラガブル・データベースとともに使用すると、データの可視性と権限の要件一致しない場合があります。アドバイザは、現在のプラガブル・データベース(PDB)およびこの問合せが実行されている別のPDBで、問合せを調整できます。PDB管理者が1つのPDBしかチューニングできないのに対して、この方法では、コンテナ・データベース(CDB)管理者が、同じ問合せを多数のPDBで同時に調整できます。

関連項目:

- SQL計画の管理の詳細は、「SQL計画ベースラインの管理」を参照してください

- CDB内での管理機能の動作をまとめた表が記載されている『Oracle Database管理者ガイド』を参照してください

SQLチューニング・アドバイザのアーキテクチャ

自動チューニング・オプティマイザは、SQLチューニング・アドバイザによって中心的に使用されるツールです。アドバイザは、複数のソースから入力としてSQL文を受け入れ、オプティマイザを使用してこれらの文を分析して推奨できます。

ハード解析のたびに自動チューニング・オプティマイザを起動すると、時間とリソースが大幅に消費されます。チューニング・モードの対象となるのは、データベースのパフォーマンスに大きく影響を与える複雑な高負荷SQL文です。

SQLチューニング・アドバイザなどの管理性アドバイザは、アドバイザ・フレームワークと呼ばれる共通インフラストラクチャを使用します。このフレームワークは、タスク・オブジェクトを格納するための共通スキーマおよびインタフェースを提供します。アドバイザ・スキーマは、アドバイザからデータを格納する一連の表です。SQLチューニング・アドバイザは、チューニング入力を受け取り、アドバイザ・フレームワークによってアドバイザ・スキーマに書き込みます。SQLチューニング・アドバイザは、レポートの作成時にアドバイザ・スキーマからデータを読み取ります。

次の図は、SQLチューニング・アドバイザの基本的なアーキテクチャを示しています。

図20-1 SQLチューニング・アドバイザのアーキテクチャ

関連項目:

SQLの解析

自動およびオンデマンドSQLチューニング

DBMS_AUTO_SQLTUNEを使用して自動的に実行するか、DBMS_SQLTUNEを使用してオンデマンドで実行するために、SQLチューニング・アドバイザを構成します。

起動方法が次のように異なります。

- 自動
システムの夜間のメンテナンス・ウィンドウで実行されるように、SQLチューニング・アドバイザを構成できます。AUTOTASKによって実行される場合、自動SQLチューニング・アドバイザとして知られるこのアドバイザは、自動SQLチューニングを実行します。

- オンデマンド
オンデマンドSQLチューニングでは、手動でSQLチューニング・アドバイザを起動し、SQLのパフォーマンスに関する問題を検出し、その後それらの問題を診断して解決します。オンデマンドでSQLをチューニングする場合、インタフェースとしてOracle Enterprise Manager Cloud Control (Cloud Control)を使用することをお薦めしますが、DBMS_SQLTUNE PL/SQLパッケージも使用できます。

SQLチューニング・アドバイザは、自動チューニング・オプティマイザを使用して自身の分析を実行します。オプティマイザはユーザーではなくSQLを分析するため、この最適化は自動的に行われます。自動チューニング・オプティマイザを自動SQLチューニングと混同しないようにしてください。このドキュメントで言及しているのは、自動SQLチューニング・タスクによって実行される作業のみです。

関連項目:

- 「オンデマンドでのSQLチューニング・アドバイザの実行」

- "自動SQLチューニング・タスクの管理"

- DBMS_SQLTUNEの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

SQLチューニング・アドバイザへの入力

SQLチューニング・アドバイザの入力は、ADDM、AWR、共有SQL領域およびSQLチューニング・セットを含む複数のソースから取り込むことができます。

SQLチューニング・アドバイザは、次のような入力ソースを使用します。

- 自動データベース診断モニター(ADDM)
SQLチューニング・アドバイザの主な入力ソースは、ADDM(アダムと読みます)です。デフォルトで、ADDMが1時間に1回事前に実行されます。高負荷のSQL文を含むパフォーマンスの問題を識別するため、ADDMにより、過去1時間に自動ワークロード・リポジトリ(AWR)により収集された主要統計が分析されます。高負荷のSQL文が識別されると、そのSQLに対してSQLチューニング・アドバイザを実行するようにADDMにより推奨されます。

- AWR
AWRは、CPU使用率や待機時間など、関連統計でランク付けされた高負荷のSQL文を含むシステム・アクティビティについて、通常のスナップショットを作成します。

AWRを参照して負荷の高いSQL文を手動で識別できます。これらの文に対してSQLチューニング・アドバイザを実行できますが、この操作は自動SQLチューニングの一環としてOracle Databaseによって自動的に実行されます。デフォルトで、AWRには過去8日間のデータが保持されます。この方法を使用してAWRの保存期間内に実行された負荷の高いSQLを見つけてチューニングできます。

- 共有SQL領域
共有SQL領域を使用して、AWRにまだ取得されていない最近のSQL文をチューニングします。共有SQL領域とAWRは、現在の時刻からAWRの許容保存期間(デフォルトは8日以上)までの高負荷のSQL文を識別してチューニングする機能を提供します。

- SQLチューニング・セット
SQLチューニング・セット(STS)は、SQL文とその実行コンテキストを格納するデータベース・オブジェクトです。STSには、パフォーマンスを個別に測定することや、パフォーマンスが予測より低下しているSQL文を識別することを目的として、まだデプロイされていないSQL文を含めることができます。SQL文のセットを入力として使用する場合、最初にSTSを作成し、使用する必要があります。

関連項目:

- 「SQLチューニング・セットについて」を参照してください

- ADDMの詳細は、『Oracle Databaseパフォーマンス・チューニング・ガイド』を参照してください

- AWRの詳細は、『Oracle Databaseパフォーマンス・チューニング・ガイド』を参照してください

- 共有SQL領域の詳細は、『Oracle Database概要』を参照してください

SQLチューニング・アドバイザの出力

SQL文を分析した後、SQLチューニング・アドバイザは推奨事項を公開します。

具体的には、SQLチューニング・アドバイザは、次のタイプの出力を生成します。

- 実行計画の最適化に関するアドバイス

- 提案した最適化の理論的根拠

- 推定パフォーマンス向上率

- アドバイスを実装するためのSQL文

各推奨事項の向上率は、次の式を使用して計算されます。

abnf% = (time_old - time_new)/(time_old)

たとえば、チューニング前の実行時間が100秒であり、推奨事項を実装した後の新しい実行時間が推定で33秒になるものとします。このパフォーマンス向上率の計算式は、次のようになります。

67% = (100 - 33)/(100)

SQL文を最適化するには、推奨事項を受け入れるかどうかを選択します。自動SQLチューニング・アドバイザは、ユーザーの操作を必要とせずに、SQLプロファイルの推奨事項を実装して文をチューニングするように構成できます。オンデマンドで起動された場合、SQLチューニング・アドバイザはユーザーがSQLプロファイルを実装することを推奨できますが、それを自動的に実装できません。

自動チューニング・オプティマイザの分析

チューニング・モードでは、オプティマイザがオプションを考慮し、統計を収集するための時間がより長く与えられます。

たとえば、自動チューニング・オプティマイザは動的統計と文の部分的な実行を使用できます。次の図は、自動チューニング・オプティマイザの様々なタイプの分析を示しています。

図20-2 自動チューニング・オプティマイザ

この項の内容は次のとおりです。

- 統計分析

- SQLプロファイリング

- アクセス・パス分析

- SQL構造分析

- 代替計画分析

関連項目:

問合せオプティマイザの概念

統計分析

オプティマイザは、実行計画を生成する際にオブジェクトの統計に依存します。このような統計が失効しているか存在しない場合、最適でない計画がオプティマイザから生成される可能性があります。自動チューニング・オプティマイザは、存在しない統計または失効している統計があるかどうか、各問合せオブジェクトをチェックし、必要に応じて新しい統計の収集を推奨します。

次の図は、統計分析のプロセスを示しています。

図20-3 自動チューニング・オプティマイザによる統計分析

SQLプロファイリング

SQLプロファイリングは、自動チューニング・オプティマイザが自身の見積りを検証することです。

実行履歴を確認し、SQLをテストすることによって、オプティマイザは自身が実行計画を生成するための最も正確な情報を保持しているかどうかを確認できます。SQLプロファイリングは、SQLチューニング・アドバイザから推奨事項を生成し、それらを実装する手順に関連していますが、その手順とは異なります。

次の図は、SQLチューニング・アドバイザがSQLプロファイルを推奨し、それを自動的に実装する様子を示しています。プロファイルの作成後、オプティマイザはそのプロファイルを、実行計画を生成する際の追加入力として使用できます。

図20-4 SQLプロファイル

関連項目:

「SQLプロファイルについて」

SQLプロファイリングの動作

データベースでは、一部のDML文とDDL文をプロファイルできます。

具体的には、SQLチューニング・アドバイザは、次のタイプの文をプロファイルできます。

- DML文(SELECT、INSERTとSELECT句、UPDATE、DELETEおよびMERGEの更新または挿入操作)

- CREATE TABLE文(AS SELECT句の場合のみ)

分析を実行した後、SQLチューニング・アドバイザは、SQLプロファイルの実装を推奨するか、その実装を推奨しません。

次の図は、SQLプロファイリングのプロセスを示しています。

図20-5 SQLプロファイリング

SQLプロファイリング中、オプティマイザは文のコスト、選択性およびカーディナリティを検証します。オプティマイザは、次のいずれかの方法を使用します。

- データのサンプルを取得し、適切な述語をサンプルに適用します。
オプティマイザは、新しい見積りを通常の見積りと比較し、その違いが大きい場合は修正ファクタを適用します。

- SQL文の一部を実行します。
述語によって効率的なアクセス・パスが提供される場合、この方法はサンプルを取得する方法よりも効率的です。

オプティマイザは、過去の文の実行履歴を使用して、正しい設定を特定します。たとえば、通常SQL文が部分的にのみ実行されることが履歴からわかった場合、オプティマイザはALL_ROWS最適化ではなくFIRST_ROWSを使用します。

関連項目:

オプティマイザの目標の選択

SQLプロファイルの実装

統計分析またはSQLプロファイリング中にオプティマイザから補足情報が生成された場合、オプティマイザはSQLプロファイルの実装を推奨します。

図20-6に示すとおり、次のオプションが可能です。

- SQLチューニング・アドバイザをオンデマンドで実行する場合、ユーザーはSQLプロファイルを実装するかどうかを選択する必要があります。

- SQLプロファイルを自動的に実装するように自動SQLチューニング・タスクを構成した場合、アドバイザの動作は、ACCEPT_SQL_PROFILEチューニング・タスク・パラメータの設定によって異なります(「コマンドラインを使用した自動SQLチューニング・タスクの構成」を参照)。

- trueに設定した場合、アドバイザはSQLプロファイルを自動的に実装します。

- falseに設定した場合、ユーザーの操作が必要になります。

- AUTO (デフォルト)に設定した場合、この設定は、1つ以上のSQL文がSQLプロファイルとともに存在する場合はtrue、この条件が満たされない場合はfalseになります。

注意:

自動SQLチューニング・タスクは、自動的にSQL計画ベースラインを作成したり、それらに計画を追加したりできません(「計画の展開」を参照)。

図20-6 SQLプロファイルの実装

自動SQLチューニングの実行中または実行後の任意のタイミングで、レポートを表示できます。このレポートには、分析されたSQL文、生成された推奨事項、および自動的に実装されたSQLプロファイルの詳細が含まれます。

関連項目:

「SQLプロファイルについて」

アクセス・パス分析

アクセス・パスは、データベースによってデータが取り出される手段です。

たとえば、索引を利用した問合せと全表スキャンを利用した問合せでは、使用されるアクセス・パスが異なります。索引を使用すると全表スキャンを回避できるため、場合によってはSQL文のパフォーマンスを大幅に改善できます。次の図は、アクセス・パス分析を示しています。

図20-7 アクセス・パス分析

自動チューニング・オプティマイザは、新しい索引によって問合せのパフォーマンスが向上するかどうかを調べ、次のいずれかを推奨します。

- 索引の作成
索引の推奨事項は、SQLチューニング・アドバイザによって処理されるSQL文に固有の推奨事項です。新しい索引によって、単一のSQL文に関連するパフォーマンスの問題が簡単に解決される場合があります。

- SQLアクセス・アドバイザの実行
自動チューニング・オプティマイザでは、索引に関する推奨事項がSQL全体のワークロードにどのように影響するかは分析されないため、典型的なSQLワークロードを持つSQL文に対してSQLアクセス・アドバイザを実行することも推奨されます。SQLアクセス・アドバイザは、索引作成がSQL全体のワークロードに与える影響を調べてから、推奨事項を作成します。

SQL構造分析

構造分析中、自動チューニング・オプティマイザは、パフォーマンスの低下につながる可能性がある構文、意味または設計上の問題の識別を試みます。この目的は、記述が適切でないSQL文を識別し、それらの再構成方法に関するアドバイスを提供することです。

次の図は、構造分析を示しています。

図20-8 構造分析

構文の一部のバリエーションは、パフォーマンスが低下する原因となります。構造分析において、自動チューニング・オプティマイザは一連のルールに対して文を評価し、効率的でないコーディング手法を識別した後、可能な場合は代替文を推奨します。

図20-8に示すとおり、自動チューニング・オプティマイザは、次のカテゴリの構造的な問題を識別します。

- SQLコンストラクタの使用方法が効率的でない
パフォーマンスが低い文では、NOT EXISTSではなくNOT IN、またはUNION ALLではなくUNIONが使用されている場合があります。UNION演算子は、UNION ALL演算子とは対照的に、結果セットに重複行が含まれないように特別なソートを使用します。2つの問合せから重複行が戻されないことがわかっている場合は、UNION ALLを使用します。

- データ型が一致しない
索引付けされた列と、比較する値のデータ型が一致しない場合、暗黙的なデータ型の変換が発生するため、データベースは索引を使用しません。また、データベースはデータ型の変換に追加のリソースを消費する必要があり、データ値が正しく変換されないため、一部のSQL文が失敗することがあります。よくある誤りとして、数値データが含まれているが算術演算に使用されない列(電話番号、クレジット・カード番号、小切手番号など)があります。カーディナリティが低い見積り、最適ではない計画、およびORA-01722エラーを回避するには、開発者は、バインド変数が数値型ではなくVARCHAR2型であることを確認する必要があります。

- 設計に誤りがある
設計の誤りの典型的な例は、結合条件の欠落です。問合せブロック内の表の数がnの場合、デカルト積を回避するためにn-1個の結合条件が存在する必要があります。

いずれの場合も、自動チューニング・オプティマイザは、文の再構成に関連する提案を行います。提案される代替文は、元の文と類似していますが同じではありません。たとえば、提案される文では、UNIONではなくUNION ALLが使用される場合があります。このとき、提案された事項が適切であるかどうかを判断します。

代替計画分析

SQLチューニング・アドバイザは、SQL文をチューニングする際に、リアルタイムおよび履歴パフォーマンス・データに文の代替実行計画があるかどうかを検索します。

最初の計画以外の計画が存在する場合、SQLチューニング・アドバイザは、代替計画が見つかったことを報告します。次の図は、SQLチューニング・アドバイザが2つの代替計画を見つけて、代替計画の検出を生成する様子を示しています。

図20-9 代替計画分析

SQLチューニング・アドバイザは、代替実行計画を検証し、再生可能でない計画がある場合は通知します。再生可能な代替計画が見つかった場合、SQL計画ベースラインを作成して、将来これらの計画を選択するようオプティマイザに指示できます。

例20-1 代替計画の検出

次の例に、SELECT文の代替計画の検出を示します。

2- Alternative Plan Finding
---------------------------
Some alternative execution plans for this statement were found by searching
the system's real-time and historical performance data.

The following table lists these plans ranked by their average elapsed time.
See section "ALTERNATIVE PLANS SECTION" for detailed information on each
plan.

id plan hash  last seen            elapsed (s)  origin          note
-- ---------- -------------------- ------------ --------------- ----------------
1 1378942017  2009-02-05/23:12:08        0.000 Cursor Cache    original plan
2 2842999589  2009-02-05/23:12:08        0.002 STS

Information
-----------
- The Original Plan appears to have the best performance, based on the
elapsed time per execution.  However, if you know that one alternative
plan is better than the Original Plan, you can create a SQL plan baseline
for it. This will instruct the Oracle optimizer to pick it over any other
choices in the future.
execute dbms_sqltune.create_sql_plan_baseline(task_name => 'TASK_XXXXX',
object_id => 2, task_owner => 'SYS', plan_hash => xxxxxxxx);

前述の例では、SQLチューニング・アドバイザにより、2つの計画が見つかりました(共有SQL領域とSQLチューニング・セットに各1個)。共有SQL領域の計画は、最初の計画と同じです。

SQLチューニング・アドバイザは、最初の計画の経過時間が代替計画よりも劣る場合のみ代替計画を推奨します。この場合、SQLチューニング・アドバイザは、パフォーマンスの最も優れている計画で、SQL計画ベースラインを作成するよう推奨します。例20-1では、代替計画よりも最初の計画の方がパフォーマンスが優れているため、SQLチューニング・アドバイザは代替計画の使用を推奨していません。

例20-2 代替計画セクション

この例では、SQLチューニング・アドバイザ出力の代替計画セクションに、最初の計画と代替計画が含まれ、それらのパフォーマンスが要約されています。最も重要な統計は、経過時間です。最初の計画では索引が使用されていますが、代替計画では全表スキャンが使用され、経過時間が.002秒だけ増加しています。

Plan 1
------

Plan Origin                 :Cursor Cache
Plan Hash Value             :1378942017
Executions                  :50
Elapsed Time                :0.000 sec
CPU Time                    :0.000 sec
Buffer Gets                 :0
Disk Reads                  :0
Disk Writes                 :0

Notes:
1. Statistics shown are averaged over multiple executions.
2. The plan matches the original plan.

--------------------------------------------
| Id  | Operation            | Name        |
--------------------------------------------
|   0 | SELECT STATEMENT     |             |
|   1 |  SORT AGGREGATE      |             |
|   2 |   MERGE JOIN         |             |
|   3 |    INDEX FULL SCAN   | TEST1_INDEX |
|   4 |    SORT JOIN         |             |
|   5 |     TABLE ACCESS FULL| TEST        |
--------------------------------------------

Plan 2
------

Plan Origin                 :STS
Plan Hash Value             :2842999589
Executions                  :10
Elapsed Time                :0.002 sec
CPU Time                    :0.002 sec
Buffer Gets                 :3
Disk Reads                  :0
Disk Writes                 :0

Notes:
1. Statistics shown are averaged over multiple executions.

-------------------------------------
| Id  | Operation           | Name  |
-------------------------------------
|   0 | SELECT STATEMENT    |       |
|   1 |  SORT AGGREGATE     |       |
|   2 |   HASH JOIN         |       |
|   3 |    TABLE ACCESS FULL| TEST  |
|   4 |    TABLE ACCESS FULL| TEST1 |
-------------------------------------

SQLチューニング・アドバイザの推奨にかかわらず、代替計画を適用するには、DBMS_SQLTUNE.CREATE_SQL_PLAN_BASELINEをコールします。このプロシージャを使用して、任意の既存の再生可能な計画でSQL計画ベースラインを作成できます。

関連項目:

「SQL計画ベースラインとSQLプロファイルの違い」

自動SQLチューニング・タスクの管理

SQLのパフォーマンスに関する問題をプロアクティブに識別することが目的である場合、SQLチューニング・アドバイザを自動タスクとして構成することが単純な解決策となります。このタスクは、AWRから選択された、チューニングの候補として条件を満たす高負荷SQL文を処理します。

この項では、自動SQLチューニング・タスクの管理方法について説明します。この項の内容は次のとおりです。

- 自動SQLチューニング・タスクについて

- 自動SQLチューニング・タスクの有効化と無効化

- 自動SQLチューニング・タスクの構成

- 自動SQLチューニング・レポートの表示

関連項目:

自動メンテナンス・タスクの詳細は、『Oracle Database管理者ガイド』を参照してください。

自動SQLチューニング・タスクについて

デフォルトでは、自動SQLチューニング・タスクは夜間のメンテナンス・ウィンドウで実行されます。

この項の内容は次のとおりです。

- 自動SQLチューニングの目的

- 自動SQLチューニングの概要

- SQLチューニング・アドバイザへのコマンドライン・ユーザー・インタフェース

- 自動SQLチューニングの基本タスク

関連項目:

マルチテナント環境のSQLチューニング・アドバイザの詳細は、『Oracle Database管理者ガイド』を参照してください。

自動SQLチューニングの目的

チューニングを手動で実行せずに、自動SQLチューニングを構成すると、コストが減少し、管理性が向上します

多くのDBAには、SQLチューニングに必要な集中分析を行う時間がありません。時間がある場合でも、SQLチューニングには手動の手順がいくつか含まれます。様々なSQL文が特定の日に高負荷になる場合があるため、DBAがかなりの時間を費やしてそれらを監視し、チューニングすることが必要になる可能性があります。

自動SQLチューニング・タスクでは、次のタイプのSQLは処理されません。

- 非定型SQL文または1週間以内に繰り返し実行されないSQL文

- パラレル問合せ

- SQLプロファイリング後の実行に時間がかかりすぎるため、SQLチューニング・アドバイザによるテスト実行が現実的ではない問合せ

- 再帰的SQL

SQLチューニング・アドバイザをオンデマンドで起動し、前述のタイプのSQL文をチューニングできます。

自動SQLチューニングの概要

Oracle Schedulerは、自動化メンテナンス・タスクのインフラストラクチャ(AutoTaskと呼ばれる)を使用して、タスクを自動的に実行するようにスケジュールします。

デフォルトでは、自動SQLチューニング・タスクは夜間のメンテナンス・ウィンドウで最大1時間実行されます。メンテナンス・ウィンドウの属性(開始時刻と終了時刻、頻度、曜日など)は、カスタマイズできます。

関連項目:

- Oracle Schedulerの詳細は、『Oracle Database管理者ガイド』を参照してください。

- DBMS_AUTO_TASK_ADMINの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

SQLチューニング・アドバイザへのコマンドライン・ユーザー・インタフェース

コマンドラインでは、PL/SQLパッケージを使用してSQLチューニング・タスクを実行できます。表20-1に、最も関連性の高いパッケージの説明を示します。

表20-1 SQLチューニング・アドバイザのパッケージ

パッケージ

説明

DBMS_AUTO_SQLTUNE

SQLチューニング・アドバイザの実行、SQLプロファイルの管理、SQLチューニング・セットの管理およびリアルタイムでのSQLのパフォーマンスの監視を行うことができます。このAPIを使用するには、ADVISOR権限が必要です。

DBMS_AUTO_TASK_ADMIN

AUTOTASKへのインタフェースが提供されます。このインタフェースを使用して、自動SQLチューニング・タスクを有効および無効にできます。

関連項目:

DBMS_SQLTUNEとDBMS_AUTO_TASK_ADMINの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

自動SQLチューニングの基本タスク

この項では、SQLチューニング・アドバイザを自動タスクとして実行する際の基本タスクについて説明します。

次の図は、基本ワークフローを示しています。

図20-10 自動SQLチューニングのAPI

図20-11に示した基本手順は、次のとおりです。

1. 自動SQLチューニング・タスクを有効にします。
「自動SQLチューニング・タスクの有効化と無効化」を参照してください。

2. オプションで、自動SQLチューニング・タスクを構成します。
「自動SQLチューニング・タスクの構成」を参照してください。

3. 自動SQLチューニング・タスクの結果を表示します。
「自動SQLチューニング・レポートの表示」を参照してください。

4. 自動SQLチューニング・タスクを無効にします。
「自動SQLチューニング・タスクの有効化と無効化」を参照してください。

自動SQLチューニング・タスクの有効化と無効化

この項では、Cloud Control (推奨)またはコマンドライン・インタフェースを使用して、自動SQLチューニング・タスクを有効および無効にする方法について説明します。

Cloud Controlを使用した自動SQLチューニング・タスクの有効化と無効化

Cloud Controlを使用して、自動SQLチューニング・タスクを含む、すべての自動メンテナンス・タスクを有効および無効にできます。

Cloud Controlを使用して自動SQLチューニング・タスクを有効および無効にする手順は次のとおりです。

1. 「Cloud Controlのデータベース・ホーム・ページへのアクセス」の説明に従って、「データベース・ホーム」ページにアクセスします。

2. 「管理」メニューから、「Oracle Scheduler」を選択し、「自動化メンテナンス・タスク」を選択します。
自動化メンテナンス・タスク・ページが表示されます。

このページには、事前定義されたタスクが表示されます。対応するリンクをクリックして各タスクにアクセスすると、そのタスクの詳細を確認できます。

3. 「自動SQLチューニング」をクリックします。
「自動SQLチューニング結果のサマリー」ページが表示されます。

タスク・ステータスセクションには、自動SQLチューニング・タスクが有効になっているか無効になっているかが表示されます。次の図では、タスクが無効になっています。

4. 自動SQLチューニングで、「構成」をクリックします。
「自動化メンテナンス・タスク構成」ページが表示されます。

デフォルトでは、自動SQLチューニングはMAINTENANCE_WINDOW_GROUPで事前定義されたすべてのメンテナンス・ウィンドウで実行されます。

5. 次の手順を実行します。

a. 自動SQLチューニングのタスク設定で、「有効」または「無効」を選択して自動タスクを有効または無効にします。

b. 週の特定の曜日に自動SQLチューニングを無効にするには、ウィンドウ名の横にある該当するチェック・ボックスを選択します。

c. ウィンドウの特性を変更するには、ウィンドウ・グループの編集をクリックします。

d. 「適用」をクリックします。

コマンドラインを使用した自動SQLチューニング・タスクの有効化と無効化

自動SQLチューニング・タスクを有効および無効にするためにCloud Controlを使用しない場合は、コマンドラインを使用する必要があります。

次の選択肢があります。

- DBMS_AUTO_TASK_ADMIN PL/SQLパッケージに含まれるENABLEまたはDISABLEプロシージャを実行します。
コマンドラインで使用する手法としては、このパッケージをお薦めします。ENABLEおよびDISABLEプロシージャのどちらに対しても、window_nameパラメータを使用して特定のメンテナンス・ウィンドウを指定できます。

- STATISTICS_LEVEL初期化パラメータをBASICに設定して、自動SQLチューニング・アドバイザを含むすべてのアドバイザと統計の収集を無効にします。
監視機能と多くの自動機能が無効になるため、STATISTICS_LEVELはBASICに設定しないことを強くお薦めします。

DBMS_AUTO_TASK_ADMINを使用して自動SQLチューニングを有効および無効にする手順は次のとおりです。

1. 管理者権限でデータベースにSQL*Plusを接続し、次のいずれかを実行します。

- 自動タスクを有効にするには、次のPL/SQLブロックを実行します。

BEGIN
DBMS_AUTO_TASK_ADMIN.ENABLE (
client_name => 'sql tuning advisor'
,   operation   => NULL
,   window_name => NULL
);
END;
/

- 自動タスクを無効にするには、次のPL/SQLブロックを実行します。

BEGIN
DBMS_AUTO_TASK_ADMIN.DISABLE (
client_name => 'sql tuning advisor'
,   operation   => NULL
,   window_name => NULL
);
END;
/

2. データ・ディクショナリを問い合せて、変更を確認します。
たとえば、次のようにDBA_AUTOTASK_CLIENTを問い合せます(出力例も示します)。

COL CLIENT_NAME FORMAT a20

SELECT CLIENT_NAME, STATUS
FROM   DBA_AUTOTASK_CLIENT
WHERE  CLIENT_NAME = 'sql tuning advisor';

CLIENT_NAME          STATUS
-------------------- --------
sql tuning advisor   ENABLED

すべてのアドバイザと統計の収集を無効にする手順は次のとおりです。

1. 管理者権限でデータベースにSQL*Plusを接続し、現在の統計レベルの設定を問い合せます。
次のSQL*Plusコマンドを実行すると、STATISTICS_LEVELがALLに設定されていることが示されます。

sys@PROD> SHOW PARAMETER statistics_level

NAME                                 TYPE        VALUE
------------------------------------ ----------- -----
statistics_level                     string      ALL

2. 次のようにSTATISTICS_LEVELをBASICに設定します。

sys@PROD> ALTER SYSTEM SET STATISTICS_LEVEL ='BASIC';

System altered.

関連項目:

詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください

自動SQLチューニング・タスクの構成

この項では、自動SQLチューニング・タスクに関する設定の構成方法について説明します。

Cloud Controlを使用した自動SQLチューニング・タスクの構成

Cloud Controlを使用して、自動SQLチューニング・タスクを含む、すべての自動メンテナンス・タスクを有効および無効にできます。操作をSYSとして実行するか、PL/SQLパッケージDBMS_AUTO_SQLTUNEに対するEXECUTE権限を持っている必要があります。

Cloud Controlを使用して自動SQLチューニング・タスクを構成する手順は次のとおりです。

1. 「Cloud Controlのデータベース・ホーム・ページへのアクセス」の説明に従って、「データベース・ホーム」ページにアクセスします。

2. 「管理」メニューの「Oracle Scheduler」をクリックし、「自動化メンテナンス・タスク」をクリックします。
自動化メンテナンス・タスク・ページが表示されます。

このページには、事前定義されたタスクが表示されます。対応するリンクをクリックして各タスクにアクセスすると、そのタスク自体の詳細を確認できます。

3. 「自動SQLチューニング」をクリックします。
「自動SQLチューニング結果のサマリー」ページが表示されます。

4. タスク設定で、「自動SQLチューニング」(SYS_AUTO_SQL_TUNING_TASK)の横にある「構成」をクリックします。
「自動化メンテナンス・タスク構成」ページが表示されます。

5. タスク設定で、「自動SQLチューニング」の横にある「構成」をクリックします。
自動SQLチューニング設定ページが表示されます。

6. 必要な変更を行い、「適用」をクリックします。

コマンドラインを使用した自動SQLチューニング・タスクの構成

DBMS_AUTO_SQLTUNEパッケージを使用すると、SET_AUTO_TUNING_TASK_PARAMETERプロシージャを使用してタスク・パラメータを指定することによって、自動SQLチューニングを構成できます。タスクはSYSが所有しているため、SYSのみがタスク・パラメータを設定できます。

ACCEPT_SQL_PROFILEチューニング・タスク・パラメータは、SQLプロファイルを自動的に実装する(true)か、ユーザーの操作を必要とする(false)かを指定します。デフォルトのAUTOに設定した場合、1つ以上のSQL文がSQLプロファイルとともに存在する場合はtrue、この条件が満たされない場合はfalseになります。

注意:

自動実装が有効になっている場合、アドバイザはSQLプロファイルを作成するための推奨事項のみを実装します。新しい索引の作成、オプティマイザ統計の収集、SQL計画ベースラインの作成などの推奨事項は、自動的には実装されません。

前提条件

このチュートリアルでは、次のことが前提となっています。

- データベースでSQLプロファイルを自動的に実装しますが、実装するのは実行ごとに50以下のSQLプロファイル、およびデータベースで合計50以下のプロファイルとします。

- 実行ごとに1200秒経過したら、タスクをタイムアウトする。

自動SQLチューニング・タスク・パラメータを設定する手順は次のとおりです。

1. SQL*Plusを適切な権限でデータベースに接続し、オプションで現在のタスク設定を問い合せます。
たとえば、管理者権限でSQL*Plusをデータベースに接続し、次の問合せを実行します。

COL PARAMETER_NAME FORMAT a25
COL VALUE FORMAT a10

SELECT PARAMETER_NAME, PARAMETER_VALUE AS "VALUE"
FROM   DBA_ADVISOR_PARAMETERS
WHERE  ( (TASK_NAME = 'SYS_AUTO_SQL_TUNING_TASK') AND
( (PARAMETER_NAME LIKE '%PROFILE%') OR
(PARAMETER_NAME = 'LOCAL_TIME_LIMIT') OR
(PARAMETER_NAME = 'EXECUTION_DAYS_TO_EXPIRE') ) );

出力例は次のように表示されます。

PARAMETER_NAME            VALUE
------------------------- ----------
EXECUTION_DAYS_TO_EXPIRE  30
LOCAL_TIME_LIMIT          1000
ACCEPT_SQL_PROFILES       FALSE
MAX_SQL_PROFILES_PER_EXEC 20
MAX_AUTO_SQL_PROFILES     10000

2. 次の形式のPL/SQLコードを使用してパラメータを設定します。

BEGIN
DBMS_SQLTUNE.SET_TUNING_TASK_PARAMETER (
task_name => 'SYS_AUTO_SQL_TUNING_TASK'
,   parameter => parameter_name
,   value     => value
);
END;
/

関連項目:

DBMS_AUTO_SQLTUNEの詳細な参照情報については、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

例20-3 SQLチューニング・タスク・パラメータの設定

次のPL/SQLブロックでは、時間制限を20分に設定し、自動的にSQLプロファイルを実装して、それらのプロファイルの制限を設定します。

BEGIN
DBMS_SQLTUNE.SET_TUNING_TASK_PARAMETER('SYS_AUTO_SQL_TUNING_TASK',
'LOCAL_TIME_LIMIT', 1200);
DBMS_SQLTUNE.SET_TUNING_TASK_PARAMETER('SYS_AUTO_SQL_TUNING_TASK',
'ACCEPT_SQL_PROFILES', 'true');
DBMS_SQLTUNE.SET_TUNING_TASK_PARAMETER('SYS_AUTO_SQL_TUNING_TASK',
'MAX_SQL_PROFILES_PER_EXEC', 50);
DBMS_SQLTUNE.SET_TUNING_TASK_PARAMETER('SYS_AUTO_SQL_TUNING_TASK',
'MAX_AUTO_SQL_PROFILES', 10002);
END;
/

自動SQLチューニング・レポートの表示

自動SQLチューニング・タスクの実行中または実行後の任意のタイミングで、チューニング・レポートを表示できます。このレポートには、自動SQLチューニング・タスクのすべての実行に関する情報が含まれます。

レポートに含まれるセクションに応じて、次のセクションで情報を参照できます。

- 一般情報
このセクションには、自動SQLチューニング・タスクの概要(レポートに指定された入力に関する情報、メンテナンス中にチューニングされたSQL文の数、作成されたSQLプロファイルの数など)が含まれます。

- サマリー
このセクションには、メンテナンス・ウィンドウ内にチューニングされたSQL文(SQL識別子別)と各SQLプロファイルのメリットの見積り、またはそのSQLプロファイルを使用したSQL文のテスト実行後の実行統計がリストされます。

- チューニングの結果
このセクションには、SQLチューニング・アドバイザによって分析された各SQL文に関する次の情報が含まれます。

- 各SQL文に関連付けられたすべての検出結果

- プロファイルがデータベースに実装されたかどうか、およびその理由

- データベースでSQLプロファイルが現在有効であるかどうか

- SQLプロファイルのテスト時に取得された実行統計の詳細

- 実行計画
このセクションには、SQLチューニング・アドバイザにより分析された各SQL文で使用された新旧のEXPLAIN PLANが表示されます。

- エラー
このセクションには、自動SQLチューニング・タスクで発生したすべてのエラーがリストされます。

コマンドラインを使用した自動SQLチューニング・レポートの表示

SQLチューニング・レポートをCLOBとして生成するには、DBMS_SQLTUNE.REPORT_AUTO_TUNING_TASKファンクションを実行します。CLOBを変数に格納した後、その変数を出力してレポートを表示できます。詳細な参照情報については、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

前提条件

この項では、実装されなかった推奨事項を含め、最新の実行において分析されたすべてのSQL文を表示するものとします。

自動SQLチューニング・アドバイザ・レポートを作成し、それにアクセスする手順は次のとおりです。

1. 管理者権限でデータベースにSQL*Plusを接続し、DBMS_SQLTUNE.REPORT_AUTO_TUNING_TASKファンクションを実行します。
次の例では、実装されなかった推奨事項を含め、最新の実行において分析されたすべてのSQL文を表示するテキスト・レポートが生成されます。

VARIABLE my_rept CLOB;
BEGIN
:my_rept :=DBMS_SQLTUNE.REPORT_AUTO_TUNING_TASK (
begin_exec   => NULL
,   end_exec     => NULL
,   type         => 'TEXT'
,   level        => 'TYPICAL'
,   section      => 'ALL'
,   object_id    => NULL
,   result_limit => NULL
);
END;
/

PRINT :my_rept

2. 一般情報セクションを参照し、チューニングの実行の概要を確認します。
次の例は、わずか7分間で17のSQL文を分析した自動SQLチューニング・タスクを示しています。

MY_REPT
---------------------------------------------------------------------------
GENERAL INFORMATION SECTION
---------------------------------------------------------------------------
Tuning Task Name                        : SYS_AUTO_SQL_TUNING_TASK
Tuning Task Owner                       : SYS
Workload Type                           : Automatic High-Load SQL Workload
Execution Count                         : 6
Current Execution                       : EXEC_170
Execution Type                          : TUNE SQL
Scope                                   : COMPREHENSIVE
Global Time Limit(seconds)              : 3600
Per-SQL Time Limit(seconds)             : 1200
Completion Status                       : COMPLETED
Started at                              : 04/16/2012 10:00:00
Completed at                            : 04/16/2012 10:07:11
Number of Candidate SQLs                : 17
Cumulative Elapsed Time of SQL (s)      : 8

3. 結果と推奨事項を見つけます。
SQLチューニング・アドバイザから推奨事項が作成された場合、それを受け入れることのメリットとデメリットを検討します。

次の例は、SQLチューニング・アドバイザが、既存の計画よりも優れている可能性がある文の計画を見つけたことを示しています。アドバイザはSQLプロファイルの実装を推奨します。

---------------------------------------------------------------------------
SQLs with Findings Ordered by Maximum (Profile/Index) Benefit, Object ID
---------------------------------------------------------------------------
ob ID  SQL ID        statistics profile(benefit) index(benefit) restructure
------ ------------- ---------- ---------------- -------------- -----------
82 dqjcc345dd4ak                      58.03%
72 51bbkcd9zwsjw                                                      2
81 03rxjf8gb18jg

---------------------------------------------------------------------------
DETAILS SECTION
---------------------------------------------------------------------------
Statements with Results Ordered by Max (Profile/Index) Benefit, Object ID
---------------------------------------------------------------------------
Object ID  : 82
Schema Name: DBA1
SQL ID     : dqjcc345dd4ak
SQL Text   : SELECT status FROM dba_autotask_client WHERE client_name=:1

---------------------------------------------------------------------------
FINDINGS SECTION (1 finding)
---------------------------------------------------------------------------

1- SQL Profile Finding (see explain plans section below)
--------------------------------------------------------
A potentially better execution plan was found for this statement.
The SQL profile was not automatically created because the verified
benefit was too low.

Recommendation (estimated benefit: 58.03%)
------------------------------------------
- Consider accepting the recommended SQL profile.
execute dbms_sqltune.accept_sql_profile(task_name =>
'SYS_AUTO_SQL_TUNING_TASK', object_id => 82, replace => TRUE);

Validation results
------------------
The SQL profile was tested by executing both its plan and the original
plan and measuring their respective execution statistics. A plan
may have been only partially executed if the other could be run
to completion in less time.

Original Plan  With SQL Profile  % Improved
-------------  ----------------  ----------
Completion Status:            COMPLETE          COMPLETE
Elapsed Time(us):               26963              8829      67.25 %
CPU Time(us):                   27000              9000      66.66 %
User I/O Time(us):                 25                14         44 %
Buffer Gets:                      905               380      58.01 %
Physical Read Requests:             0                 0
Physical Write Requests:            0                 0
Physical Read Bytes:                0                 0
Physical Write Bytes:            7372              7372          0 %
Rows Processed:                     1                 1
Fetches:                            1                 1
Executions:                         1                 1

Notes
-----
1. The original plan was first executed to warm the buffer cache.
2. Statistics for original plan were averaged over next 9 executions.
3. The SQL profile plan was first executed to warm the buffer cache.
4. Statistics for the SQL profile plan were averaged over
next 9 executions.

オンデマンドでのSQLチューニング・アドバイザの実行

この項の内容は次のとおりです。

- オンデマンドSQLチューニングについて

- SQLチューニング・タスクの作成

- SQLチューニング・タスクの構成

- SQLチューニング・タスクの実行

- SQLチューニング・タスクの監視

- SQLチューニング・タスクの結果の表示

オンデマンドSQLチューニングについて

ここでのオンデマンドSQLチューニングは、自動SQLチューニング・タスクの結果として行われるのではないSQLチューニング・アドバイザの起動として定義されます。

オンデマンドSQLチューニングの目的

通常、次の場合にSQLチューニング・アドバイザをオンデマンドで起動します。

- プロアクティブにADDMを実行し、一部のSQL文がパフォーマンス要件を満たしていないことが報告された場合。

- SQLのパフォーマンスが低いというユーザーからの苦情を受けて、SQL文をチューニングする場合。

どちらの場合も、通常はSQLチューニング・アドバイザを実行することが、SQLのパフォーマンスに関する予期しない問題を最もすばやく解決する方法になります。

オンデマンドSQLチューニングのユーザー・インタフェース

手動でSQLチューニング・アドバイザを実行するための推奨インタフェースは、Cloud Controlです。

Cloud Controlを使用したSQLチューニング・アドバイザへのアクセス

自動データベース診断モニター(ADDM)は、自動的に高負荷SQL文を識別します。ADDMがこのような文を識別した場合は、「推奨事項の詳細」ページの「SQLチューニング・アドバイザのスケジュール」または「SQLチューニング・アドバイザの実行」をクリックして、SQLチューニング・アドバイザを実行します。

SQLチューニング・アドバイザを使用したSQL文のチューニング手順:

1. 適切な資格証明を使用してCloud Controlにログインします。

2. 「ターゲット」メニューの下で、「データベース」を選択します。

3. データベース・ターゲットのリストで、管理対象のOracle Databaseインスタンスのターゲットを選択します。

4. データベースの資格証明の入力を求められた場合は、実行するタスクに必要な最小限の資格証明を入力します。

5. 「パフォーマンス」メニューの「SQL」をクリックし、「SQLチューニング・アドバイザ」をクリックします。
「SQLチューニング・アドバイザのスケジュール」ページが表示されます。

関連項目:

Cloud Controlを使用したSQLチューニング・アドバイザの構成および実行方法の詳細は、『Oracle Database 2日でパフォーマンス・チューニング・ガイド』を参照してください。

オンデマンドSQLチューニングへのコマンドライン・インタフェース

Cloud Controlが使用可能でない場合、DBMS_SQLTUNEパッケージのプロシージャを使用してSQLチューニング・アドバイザを実行できます。このAPIを使用するには、ユーザーがADVISOR権限を持っている必要があります。

関連項目:

詳細な参照情報については、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

オンデマンドSQLチューニングの基本タスク

この項では、DBMS_SQLTUNEパッケージを使用してSQLチューニング・アドバイザを実行する際の基本タスクについて説明します。

次の図は、PL/SQL APIを使用する場合の基本ワークフローを示しています。

図20-11 SQLチューニング・アドバイザAPI

図20-11に示した基本手順は、次のとおりです。

1. SQLチューニング・アドバイザへの入力を準備または作成します。入力には次のいずれかを使用できます。

- 単一のSQL文のテキスト

- 1つ以上の文を含むSQLチューニング・セット

2. SQLチューニング・タスクを作成します。
「SQLチューニング・タスクの作成」を参照してください。

3. オプションで、作成したSQLチューニング・タスクを構成します。
「SQLチューニング・タスクの構成」を参照してください。

4. SQLチューニング・タスクを実行します。
「SQLチューニング・タスクの実行」を参照してください。

5. オプションで、SQLチューニング・タスクのステータスまたは進行状況をチェックします。
「SQLチューニング・タスクの監視」を参照してください。

6. SQLチューニング・タスクの結果を表示します。
「SQLチューニング・タスクの結果の表示」を参照してください。

7. 必要に応じて推奨事項を実装します。

関連項目:

Cloud Controlを使用したSQLのチューニング方法の詳細は、『Oracle Database 2日でパフォーマンス・チューニング・ガイド』を参照してください。

SQLチューニング・タスクの作成

SQLチューニング・タスクを作成するには、DBMS_SQLTUNE.CREATE_TUNING_TASKファンクションを実行します。チューニング・タスクは、次のいずれかから作成できます。

- 単一のSQL文のテキスト

- 複数の文を含むSQLチューニング・セット

- 共有SQL領域からSQL識別子によって選択されたSQL文

- AWRからSQL識別子によって選択されたSQL文

scopeパラメータは、このファンクションにとって最も重要なパラメータの1つです。このパラメータは、次の値に設定できます。

- LIMITED
SQLチューニング・アドバイザでは、統計チェック、アクセス・パス分析およびSQL構造分析に基づいて推奨事項が生成されます。SQLプロファイルの推奨事項は生成されません。

- COMPREHENSIVE
SQLチューニング・アドバイザでは、制限付きの有効範囲で実行されるすべての分析と、SQLプロファイリングが実行されます。

前提条件

このチュートリアルでは、次のことが前提となっています。

- ADVISOR権限を持つユーザーhrとしてチューニングを実行します。

- 次の問合せをチューニングします。

SELECT /*+ ORDERED */ *
FROM   employees e, locations l, departments d
WHERE  e.department_id = d.department_id
AND    l.location_id = d.location_id
AND    e.employee_id < :bnd;

- バインド変数100を前述の問合せに渡します。

- SQLチューニング・アドバイザでSQLプロファイリングを実行します。

- タスクの実行時間は60秒以内です。

SQLチューニング・タスクを作成する手順は次のとおりです。

1. 適切な権限でデータベースにSQL*Plusを接続し、DBMS_SQLTUNE.CREATE_TUNING_TASKファンクションを実行します。
たとえば、次のPL/SQLプログラムを実行します。

DECLARE
my_task_name VARCHAR2(30);
my_sqltext   CLOB;
BEGIN
my_sqltext := 'SELECT /*+ ORDERED */ * '                      ||
'FROM employees e, locations l, departments d ' ||
'WHERE e.department_id = d.department_id AND '  ||
'l.location_id = d.location_id AND '      ||
'e.employee_id < :bnd';

my_task_name := DBMS_SQLTUNE.CREATE_TUNING_TASK (
sql_text    => my_sqltext
,         bind_list   => sql_binds(anydata.ConvertNumber(100))
,         user_name   => 'HR'
,         scope       => 'COMPREHENSIVE'
,         time_limit  => 60
,         task_name   => 'STA_SPECIFIC_EMP_TASK'
,         description => 'Task to tune a query on a specified employee'
);
END;
/

2. オプションで、タスクのステータスを問い合せます。
次の例では、現行のユーザー(この例ではhr)によって所有されているすべてのタスクのステータスを問い合せます。

COL TASK_ID FORMAT 999999
COL TASK_NAME FORMAT a25
COL STATUS_MESSAGE FORMAT a33

SELECT TASK_ID, TASK_NAME, STATUS, STATUS_MESSAGE
FROM   USER_ADVISOR_LOG;

出力例は次のように表示されます。

TASK_ID TASK_NAME                 STATUS      STATUS_MESSAGE
------- ------------------------- ----------- --------------
884 STA_SPECIFIC_EMP_TASK     INITIAL

前述の出力において、INITIALステータスはタスクの実行が開始されていないことを示しています。

関連項目:

DBMS_SQLTUNE.CREATE_TUNING_TASKファンクションについては、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

SQLチューニング・タスクの構成

チューニング・タスクの作成後に、そのパラメータを変更するには、DBMS_SQLTUNE.SET_TUNING_TASK_PARAMETERファンクションを実行します。

前提条件

このチュートリアルでは、次のことが前提となっています。

- ADVISOR権限を持つユーザーhrとしてチューニングを実行します。

- 「SQLチューニング・タスクの作成」で作成したSTA_SPECIFIC_EMP_TASKをチューニングします。

- SQLチューニング・タスクの最大実行時間を300秒に変更します。

SQLチューニング・タスクを構成する手順は次のとおりです。

1. 適切な権限でデータベースにSQL*Plusを接続し、DBMS_SQLTUNE.SET_TUNING_TASK_PARAMETERファンクションを実行します。
たとえば、次のPL/SQLプログラムを実行すると、チューニング・タスクの時間制限を300秒に変更できます。

BEGIN
DBMS_SQLTUNE.SET_TUNING_TASK_PARAMETER (
task_name => 'STA_SPECIFIC_EMP_TASK'
,   parameter => 'TIME_LIMIT'
,   value     => 300
);
END;
/

2. オプションで、タスク・パラメータが変更されたことを確認します。
次の例では、タスクSTA_SPECIFIC_EMP_TASKで使用されているすべてのパラメータの値を問い合せます。

COL PARAMETER_NAME FORMAT a25
COL VALUE FORMAT a15

SELECT PARAMETER_NAME, PARAMETER_VALUE AS "VALUE"
FROM   USER_ADVISOR_PARAMETERS
WHERE  TASK_NAME = 'STA_SPECIFIC_EMP_TASK'
AND    PARAMETER_VALUE != 'UNUSED'
ORDER BY PARAMETER_NAME;

出力例は次のように表示されます。

PARAMETER_NAME            VALUE
------------------------- ---------------
DAYS_TO_EXPIRE            30
DEFAULT_EXECUTION_TYPE    TUNE SQL
EXECUTION_DAYS_TO_EXPIRE  UNLIMITED
JOURNALING                INFORMATION
MODE                      COMPREHENSIVE
SQL_LIMIT                 -1
SQL_PERCENTAGE            1
TARGET_OBJECTS            1
TEST_EXECUTE              AUTO
TIME_LIMIT                300

関連項目:

詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

SQLチューニング・タスクの実行

SQLチューニング・タスクを実行するには、DBMS_SQLTUNE.EXECUTE_TUNING_TASKファンクションを使用します。最も重要なパラメータは、task_nameです。

注意:

また、EXECUTE_TUNING_TASK APIを使用して自動チューニング・タスクSYS_AUTO_SQL_TUNING_TASKを実行することもできます。SQLチューニング・アドバイザは、自動的に実行する場合と同じ分析およびアクションを実行します。

前提条件

このチュートリアルでは、次のことが前提となっています。

- ADVISOR権限を持つユーザーhrとしてチューニングを実行します。

- 「SQLチューニング・タスクの作成」で作成したSTA_SPECIFIC_EMP_TASKを実行します。

SQLチューニング・タスクを実行する手順は次のとおりです。

1. 適切な権限でデータベースにSQL*Plusを接続し、DBMS_SQLTUNE.EXECUTE_TUNING_TASKファンクションを実行します。
たとえば、次のPL/SQLプログラムを実行します。

BEGIN
DBMS_SQLTUNE.EXECUTE_TUNING_TASK(task_name=>'STA_SPECIFIC_EMP_TASK');
END;
/

2. オプションで、タスクのステータスを問い合せます。
次の例では、現行のユーザー(この例ではhr)によって所有されているすべてのタスクのステータスを問い合せます。

COL TASK_ID FORMAT 999999
COL TASK_NAME FORMAT a25
COL STATUS_MESSAGE FORMAT a33

SELECT TASK_ID, TASK_NAME, STATUS, STATUS_MESSAGE
FROM   USER_ADVISOR_LOG;

出力例は次のように表示されます。

TASK_ID TASK_NAME                 STATUS      STATUS_MESSAGE
------- ------------------------- ----------- --------------
884 STA_SPECIFIC_EMP_TASK     COMPLETED

関連項目:

DBMS_SQLTUNE.EXECUTE_TUNING_TASKファンクションの詳細な参照情報については、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

SQLチューニング・タスクの監視

Cloud ControlでSQLチューニング・タスクを作成する場合、別途の監視手順は必要ありません。Cloud Controlによって自動的にステータス・ページが表示されます。

Cloud Controlを使用しない場合、データ・ディクショナリおよび動的パフォーマンス・ビューを問い合せることによって、現在実行中のSQLチューニング・タスクを監視できます。表20-2に、関連するビューの説明を示します。

表20-2 DBMS_SQLTUNE.EXECUTE_TUNING_TASKパラメータ

ビュー

説明

USER_ADVISOR_TASKS

現行のユーザーが所有するタスクに関する情報を示します。このビューは、タスクごとに1行の情報を示します。各タスクには、所有者固有の名前が含まれています。タスク名は、情報を提供するのみで、他のネームスペース内部で一意性が施行されることはありません。

V$ADVISOR_PROGRESS

アドバイザの実行の進行状況に関する情報を示します。

前提条件

このチュートリアルでは、次のことが前提となっています。

- ADVISOR権限を持つユーザーhrとしてチューニングを実行します。

- 「SQLチューニング・タスクの実行」で実行したSTA_SPECIFIC_EMP_TASKを監視します。

SQLチューニング・タスクを監視する手順は次のとおりです。

1. 適切な権限でデータベースにSQL*Plusを接続し、タスクが実行中であるか完了しているかを確認します。
たとえば、次のようにSTA_SPECIFIC_EMP_TASKのステータスを問い合せます。

SELECT STATUS
FROM   USER_ADVISOR_TASKS
WHERE  TASK_NAME = 'STA_SPECIFIC_EMP_TASK';

次に、タスクが完了していることを示す出力例を示します。

STATUS
-----------
EXECUTING

2. 実行中のタスクの進行状況を確認します。
次の例では、タスクID 884のタスクのステータスを問い合せます。

VARIABLE my_tid NUMBER;
EXEC :my_tid := 884
COL ADVISOR_NAME FORMAT a20
COL SOFAR FORMAT 999
COL TOTALWORK FORMAT 999

SELECT TASK_ID, ADVISOR_NAME, SOFAR, TOTALWORK,
ROUND(SOFAR/TOTALWORK*100,2) "%_COMPLETE"
FROM   V$ADVISOR_PROGRESS
WHERE  TASK_ID = :my_tid;

出力例は次のように表示されます。

TASK_ID ADVISOR_NAME         SOFAR TOTALWORK %_COMPLETE
---------- -------------------- ----- --------- ----------
884 SQL Tuning Advisor       1         2         50

関連項目:

V$ADVISOR_PROGRESSビューの詳細は、『Oracle Databaseリファレンス』を参照してください

SQLチューニング・タスクの結果の表示

チューニング・タスクの結果をレポートするには、DBMS_SQLTUNE.REPORT_TUNING_TASKファンクションを使用します。このレポートには、SQLチューニング・アドバイザのすべての検出結果および推奨事項が含まれます。提案される推奨事項ごとに、その実装に必要なSQL文、理論的根拠およびメリットが提供されます。

前提条件

このチュートリアルでは、次のことが前提となっています。

- ADVISOR権限を持つユーザーhrとしてチューニングを実行します。

- 「SQLチューニング・タスクの実行」で実行したSTA_SPECIFIC_EMP_TASKのレポートにアクセスします。

SQLチューニング・タスクのレポートを表示する手順は次のとおりです。

1. 適切な権限でデータベースにSQL*Plusを接続し、DBMS_SQLTUNE.REPORT_TUNING_TASKファンクションを実行します。
たとえば、次の文を実行します。

SET LONG 1000
SET LONGCHUNKSIZE 1000
SET LINESIZE 100
SELECT DBMS_SQLTUNE.REPORT_TUNING_TASK( 'STA_SPECIFIC_EMP_TASK' )
FROM   DUAL;

出力例の一部を次に示します。

DBMS_SQLTUNE.REPORT_TUNING_TASK('STA_SPECIFIC_EMP_TASK')
---------------------------------------------------------------------------
GENERAL INFORMATION SECTION
---------------------------------------------------------------------------
Tuning Task Name   : STA_SPECIFIC_EMP_TASK
Tuning Task Owner  : HR
Workload Type      : Single SQL Statement
Execution Count    : 11
Current Execution  : EXEC_1057
Execution Type     : TUNE SQL
Scope              : COMPREHENSIVE
Time Limit(seconds): 300
Completion Status  : COMPLETED
Started at         : 04/22/2012 07:35:49
Completed at       : 04/22/2012 07:35:50

---------------------------------------------------------------------------
Schema Name: HR
SQL ID     : dg7nfaj0bdcvk
SQL Text   : SELECT /*+ ORDERED */ * FROM employees e, locations l,
departments d WHERE e.department_id = d.department_id AND
l.location_id = d.location_id AND e.employee_id < :bnd
Bind Variables :
1 -  (NUMBER):100

---------------------------------------------------------------------------
FINDINGS SECTION (4 findings)
-----------------------------------------------

2. 「コマンドラインを使用した自動SQLチューニング・レポートの表示」.の説明に従って、結果を解釈します。

関連項目:

詳細な参照情報については、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

21 SQLアクセス・アドバイザを使用したアクセス・パスの最適化

この章の内容は次のとおりです。

- SQLアクセス・アドバイザについて

- SQLアクセス・アドバイザの使用: 基本タスク

- SQLアクセス・アドバイザ・クイック・チューニングの実行

- SQLアクセス・アドバイザの使用: 詳細タスク

- SQLアクセス・アドバイザの例

- SQLアクセス・アドバイザ・リファレンス

SQLアクセス・アドバイザについて

SQLアクセス・アドバイザは、SQLチューニング・セットを含む複数のソースから入力を受け入れ、推奨事項を発行します。

この項の内容は次のとおりです。

- SQLアクセス・アドバイザの目的

- SQLアクセス・アドバイザのアーキテクチャ

- SQLアクセス・アドバイザのユーザー・インタフェース

注意:

SQLアクセス・アドバイザをプラガブル・データベースとともに使用すると、データの可視性と権限の要件が一致しない場合があります。

関連項目:

コンテナ・データベース(CDB)内での管理機能の動作をまとめた表が記載されている『Oracle Database管理者ガイド』を参照してください

SQLアクセス・アドバイザの目的

SQLアクセス・アドバイザでは、特定のワークロードに関するマテリアライズド・ビュー、マテリアライズド・ビュー・ログ、パーティションおよび索引の適切なセットを推奨して、パフォーマンスの目標達成を支援します。データ集中型の複雑な問合せの実行時に最適なパフォーマンスを実現できるようにデータベースをチューニングする場合、マテリアライズド・ビュー、パーティションおよび索引が必要不可欠です。

SQLアクセス・アドバイザは、入力として実際のワークロードを使用するか、またはスキーマから仮想ワークロードを導出します。アドバイザは、次に、高速実行パスのアクセス構造を推奨します。アドバイザには、次の利点があります。

- 専門知識が必要ありません。

- オプティマイザのルールに基づいて決定されます。

- 単一アドバイザで、SQLアクセスのあらゆる側面をカバーします。

- Cloud Controlでは、簡単で使いやすいGUIウィザードを提供します。

- 推奨事項を実装するスクリプトを生成します。

関連項目:

Cloud Controlを使用してSQLアクセス・アドバイザを使用する方法は、『Oracle Database 2日でパフォーマンス・チューニング・ガイド』を参照してください。

SQLアクセス・アドバイザのアーキテクチャ

自動チューニング・オプティマイザは、SQLアクセス・アドバイザで使用する重要なツールです。

アドバイザは、図21-1に示すソースから入力としてSQL文を受け入れ、オプティマイザを使用してこれらの文を分析して推奨できます。

図21-1は、SQLアクセス・アドバイザの基本アーキテクチャを示しています。

図21-1 SQLアクセス・アドバイザのアーキテクチャ

関連項目:

「自動チューニング・オプティマイザについて」

SQLアクセス・アドバイザへの入力

SQLアクセス・アドバイザでは、1つ以上のSQL文と、各文を完全に説明する統計情報および属性で構成されているワークロードが必要です。全ワークロードには、対象となるビジネス・アプリケーションのすべてのSQL文が含まれます。部分ワークロードには、SQL文のサブセットが含まれます。

図21-1のように、SQLアクセス・アドバイザの入力は、次の複数のソースから取り込むことができます。

- 共有SQL領域
データベースでは、共有SQL領域を使用して、V$SQLに現在ある新しいSQL文を分析します。

- SQLチューニング・セット
SQLチューニング・セット(STS)は、SQL文とその実行コンテキストを格納するデータベース・オブジェクトです。SQL文のセットを入力として使用する場合、最初にSTSを作成し、使用する必要があります。

注意:

最良の結果を得るには、ワークロードをSQLチューニング・セットとして提供します。DBMS_SQLTUNEパッケージに提供されているヘルパー・ファンクションにより、一般的なワークロード・ソース(SQLキャッシュ、表に格納されたユーザー定義のワークロード、仮想ワークロードなど)からSQLチューニング・セットを作成できます。

- 仮想ワークロード
ディメンションと制約を分析することで、スキーマから仮想ワークロードを作成できます。このオプションは、アプリケーションの初期の設計時に役立ちます。

関連項目:

- 共有SQL領域の詳細は、『Oracle Database概要』を参照してください。

- 「SQLチューニング・セットについて」

SQLアクセス・アドバイザのフィルタ・オプション

図21-1のように、ワークロードにフィルタを適用して分析対象を制限できます。たとえば、オプティマイザ・コストに基づいて、ワークロードの上位30のリソース集中型文のみを確認するようアドバイザを指定します。こうして制限することで、様々なワークロード・シナリオに基づいた推奨事項のセットを生成できます。

SQLアクセス・アドバイザ・パラメータは、ワークロードの推奨プロセスとカスタマイズを制御します。これらのパラメータは、必要な推奨事項のタイプや推奨内容のネーミング規則など、プロセスの様々な側面を制御します。

これらのパラメータを設定するには、DBMS_ADVISOR.SET_TASK_PARAMETERプロシージャを使用します。パラメータは、タスクの存続期間は設定されたままであるという点において永続的です。DBMS_ADVISOR.SET_TASK_PARAMETERを使用してパラメータ値を設定した場合、このプロシージャをもう1回コールするまで、その値は変わりません。

関連項目:

DBMS_ADVISOR.SET_TASK_PARAMETERプロシージャの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

SQLアクセス・アドバイザ推奨事項

タスクの推奨事項は、簡単なソリューションから複雑なソリューションにまで及ぶことがあります。アドバイザは、次のようなデータベース・オブジェクトの作成を推奨できます。

- 索引
SQLアクセス・アドバイザの索引の推奨事項には、ビットマップ索引、ファンクション索引およびBツリー索引が含まれます。ビットマップ索引を使用すると、多くのタイプの非定型問合せのレスポンス時間が短縮され、その他の索引付けの方法と比べて記憶域要件が軽減されます。Bツリー索引は、一意またはほぼ一意のキーに索引を付ける方法で、データ・ウェアハウスで最も一般的に使用されています。SQLアクセス・アドバイザのマテリアライズド・ビューの推奨には、通常のリライトまたはテキストの完全一致リライトでの、高速リフレッシュおよび完全リフレッシュの可能なMVの推奨も含まれます。

- マテリアライズド・ビュー
SQLアクセス・アドバイザでは、TUNE_MVIEWプロシージャを使用することで、高速リフレッシュが可能で、通常のクエリー・リライトを活用できるマテリアライズド・ビューの最適化の方法も推奨されます。

- マテリアライズド・ビュー・ログ
マテリアライズド・ビュー・ログは、マテリアライズド・ビューのマスター・サイトまたはマスター・マテリアライズド・ビュー・サイトの表で、マスター表またはマスター・マテリアライズド・ビューに対するDML変更をすべて記録します。マテリアライズド・ビューの高速リフレッシュは、マテリアライズド・ビューのマスターにマテリアライズド・ビュー・ログが存在する場合のみ可能です。

- パーティション
SQLアクセス・アドバイザは、既存のパーティション化されていない実表のパーティション化によるパフォーマンスの改善を推奨する場合があります。さらに、パーティション化された新しい索引およびマテリアライズド・ビューを推奨することもあります。

パーティション化された新しい索引およびマテリアライズド・ビューの作成は、パーティション化されていない場合と同じですが、既存の実表のパーティション化は慎重に実行する必要があります。表に索引、ビュー、制約またはトリガーが定義されている場合は、特に慎重に行う必要があります。

推奨する際に、SQLアクセス・アドバイザは、ディメンション・レベルの列、JOIN KEY列およびファクト表のキー列における表および索引のカーディナリティに関する構造の統計情報に依存します。DBMS_STATSパッケージを使用して、正確な統計または見積り統計を収集できます(「DBMS_STATSを使用した手動統計収集について」)を参照。

統計の収集は時間のかかる処理であり、完全な統計精度は必要ないため、通常は統計を見積ることをお薦めします。特定の表に関する統計情報を収集しない場合、その表を参照する問合せはワークロードで無効とマークされ、それらの問合せについては推奨事項は生成されません。また、既存のすべての索引とマテリアライズド・ビューを分析しておくこともお薦めします。

関連項目:

- マテリアライズド・ビューの詳細は、『Oracle Databaseデータ・ウェアハウス・ガイド』を参照してください。

- パーティションの詳細は、『Oracle Database VLDBおよびパーティショニング・ガイド』を参照してください。

SQLアクセス・アドバイザ・アクション

一般に、各推奨事項は、1つ以上の問合せに対して利点をもたらします。利点を最大限に得るには、推奨事項の個々のアクションをすべてまとめて実装する必要があります。複数の推奨事項でアクションを共有できます。

たとえば、CREATE INDEX文は複数の問合せに対して利点をもたらしますが、それらの問合せの一部は、他のCREATE MATERIALIZED VIEW文から利点を得ることがあります。その場合、アドバイザは2つの推奨事項を生成します。索引のみを必要とする問合せセット用と、索引とマテリアライズド・ビューの両方を必要とする問合せセット用です。

アクションのタイプ

SQLアクセス・アドバイザの推奨事項には、次のタイプのアクションがあります。

- PARTITION BASE TABLE
このアクションは、既存のパーティション化されていない実表をパーティション化します。

- CREATE|DROP|RETAIN {MATERIALIZED VIEW|MATERIALIZED VIEW LOG|INDEX}
CREATEアクションは、新しいアクセス構造に対応します。RETAINは、既存のアクセス構造の維持を推奨します。SQLアクセス・アドバイザは、WORKLOAD_SCOPEパラメータがFULLに設定されている場合、DROPのみを推奨します。

- GATHER STATS
このアクションは、DBMS_STATSプロシージャへのコールを生成し、新しく生成されたアクセス構造に関する統計を収集します(「DBMS_STATSを使用した手動統計収集について」)を参照。

複数の推奨事項が同じアクションを参照する場合があります。ただし、推奨事項のスクリプトの生成では、各アクションは1回のみ表示されます。

関連項目:

アクションおよび推奨事項を表示する方法は、「SQLアクセス・アドバイザ・タスクの結果の表示」を参照してください

パーティション化の推奨事項の解釈のガイドライン

SQLアクセス・アドバイザは、実表のパーティション化によってパフォーマンスが向上すると判断した場合、その表を参照する問合せが含まれるすべての推奨事項にパーティション・アクションを追加します。この方法により、索引およびマテリアライズド・ビューの推奨事項が、適切にパーティション化された表に実装されます。

SQLアクセス・アドバイザは、問合せパフォーマンスを向上させるために既存のパーティション化されていない実表のパーティション化を推奨することがあります。アドバイザの実装スクリプトにパーティション推奨事項が含まれる場合は、次の問題に注意してください。

- 既存の表のパーティション化は複雑で広範な作業であるため、新しい索引やマテリアライズド・ビューを実装するよりも非常に時間がかかる場合があります。この推奨事項の実装には、時間を十分に取っておく必要があります。

- 索引およびマテリアライズド・ビューの推奨事項は、索引やビューを削除すれば簡単に元に戻せますが、表をパーティション化すると簡単には元の状態に戻せません。このため、パーティション化の推奨が含まれるスクリプトを実行する前に、データベースのバックアップが必要です。

- 実表を再パーティション化する際に、SQLアクセス・アドバイザのスクリプトにより、元の表の一時コピーが作成されますが、その一時コピーは元の表と同じ容量の領域を使用します。そのため、再パーティション化プロセスには、再パーティション化する最も大きな表のコピーをもう1つ作成できる程度に十分な空きディスク領域が必要です。実装スクリプトを実行する前に、使用可能な領域を確保しておく必要があります。
パーティション実装スクリプトは、索引、マテリアライズド・ビューおよび制約などの依存オブジェクトの移行を試みます。しかし、一部のオブジェクトは、自動的に移行できません。たとえば、再パーティション化された実表に対するPL/SQLストアド・プロシージャの定義は、通常では無効になり、再コンパイルが必要です。

- アドバイザのパーティション化の推奨を実装しない場合、同じスクリプトの同じ表に対するその他のすべての推奨事項(CREATE INDEXおよびCREATE MATERIALIZED VIEWなどの推奨)は、パーティション化の推奨に依存していることに注意してください。正確な推奨を得るには、パーティション化の推奨をスクリプトから単純に削除しないでください。かわりに、パーティション化を無効にしてアドバイザを再実行します(たとえば、ANALYSIS_SCOPEパラメータの値にTABLEキーワードを含めないなど)。

関連項目:

- CREATE DIRECTORYの構文の詳細は、Oracle Database SQL言語リファレンスを参照してください

- DBMS_ADVISOR.GET_TASK_SCRIPTファンクションの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください

SQLアクセス・アドバイザ・リポジトリ

SQLアクセス・アドバイザによって生成されたすべての必要情報は、データ・ディクショナリのアドバイザ・リポジトリに格納されます。リポジトリには、次の利点があります。

- SQLアクセス・アドバイザの完全なワークロードが収集されます。

- 履歴データがサポートされます。

- データベースで管理されます。

SQLアクセス・アドバイザのユーザー・インタフェース

Cloud Controlで利用可能なGUIウィザードを介して、SQLアクセス・アドバイザを使用することをお薦めします。SQLアクセス・アドバイザ・ウィザードを使用する方法は、『Oracle Database 2日でパフォーマンス・チューニング・ガイド』を参照してください。

DBMS_ADVISORパッケージを介してSQLアクセス・アドバイザを起動することもできます。この章では、APIの使用方法について説明します。セマンティクスおよび構文の詳細は、Oracle Database PL/SQLパッケージおよびタイプ・リファレンスを参照してください。

Cloud Controlを使用した「SQLアクセス・アドバイザ: 初期オプション」ページへのアクセス

Cloud Controlの「SQLアクセス・アドバイザ: 初期オプション」ページは、推奨事項を取得するプロセスを示すウィザードの開始ページです。

「SQLアクセス・アドバイザ: 初期オプション」ページにアクセスする手順は、次のとおりです。

1. 「Cloud Controlのデータベース・ホーム・ページへのアクセス」の説明に従って、「データベース・ホーム」ページにアクセスします。

2. 「パフォーマンス」メニューから「SQL」を選択し、さらに「SQLアクセス・アドバイザ」を選択します。
図21-2のように、「SQLアクセス・アドバイザ: 初期オプション」ページが表示されます。

図21-2 SQLアクセス・アドバイザ: 初期オプション

ほとんどのSQL計画管理タスクは、このページ、またはこのページからアクセスするページで実行できます。

関連項目:

- 「SQLアクセス・アドバイザ: 初期オプション」ページのオプションの詳細は、Cloud Controlの状況依存オンライン・ヘルプを参照してください。

- Cloud Controlを使用したSQLチューニング・アドバイザの構成および実行方法の詳細は、『Oracle Database 2日でパフォーマンス・チューニング・ガイド』を参照してください。

SQLチューニング・セットへのコマンドライン・インタフェース

コマンドラインで、DBMS_ADVISORパッケージを使用してSQLチューニング・アドバイザを管理できます。

DBMS_ADVISORパッケージは、任意のPL/SQLプログラムからコール可能な分析およびアドバイザ用のファンクションおよびプロシージャの集合です。DBMS_ADVISORを使用するには、ADVISOR権限が必要です。

関連項目:

DBMS_ADVISORの詳細は、Oracle Database PL/SQLパッケージおよびタイプ・リファレンスを参照してください

SQLアクセス・アドバイザの使用: 基本タスク

基本タスクには、STSの作成、STSのロード、SQLアクセス・アドバイザ・タスクの作成およびタスクの実行が含まれます。

次の図は、SQLアクセス・アドバイザの基本ワークフローを示しています。

図21-3 SQLアクセス・アドバイザの使用

通常、次の手順を実行して、SQLアクセス・アドバイザを使用します。

1. SQLチューニング・セットの作成
SQLアクセス・アドバイザの入力ワークロード・ソースは、SQLチューニング・セットです(STS)。DBMS_SQLTUNE.CREATE_SQLSETを使用して、SQLチューニング・セットを作成します。

このタスクについては、「SQLアクセス・アドバイザの入力としてのSQLチューニング・セットの作成」を参照してください。

2. SQLチューニング・セットのロード
SQLアクセス・アドバイザのパフォーマンスは、実際の使用状況に基づいたワークロードが使用可能な場合に最も高くなります。DBMS_SQLTUNE.LOAD_SQLSETを使用し、ユーザー定義のワークロードをSQLチューニング・セットに移入します。

このタスクについては、「ユーザー定義のワークロードのSQLチューニング・セットへの移入」を参照してください。

3. タスクの作成および構成
タスクでは、SQLアクセス・アドバイザが分析する内容と分析結果の格納場所を定義します。タスクを作成するには、DBMS_ADVISOR.CREATE_TASKプロシージャを使用します。タスクのパラメータを定義するにはSET_TASK_PARAMETERプロシージャを使用し、タスクをSTSにリンクするにはDBMS_ADVISOR.ADD_STS_REFプロシージャを使用します。

このタスクについては、「SQLアクセス・アドバイザ・タスクの作成および構成」を参照してください。

4. タスクの実行
推奨事項を生成するには、DBMS_ADVISOR.EXECUTE_TASKプロシージャを実行します。各推奨事項には、1つ以上のアクションが指定されます。たとえば、1つの推奨事項には、複数のマテリアライズド・ビュー・ログの作成、マテリアライズド・ビューの作成、およびその分析による統計の収集が含まれます。

このタスクについては、「SQLアクセス・アドバイザ・タスクの実行」を参照してください。

5. 推奨事項の表示
データ・ディクショナリ・ビューを問い合せて、推奨事項を表示できます。

このタスクについては、「SQLアクセス・アドバイザ・タスクの結果の表示」を参照してください。

6. オプション: 推奨事項を実装するSQLスクリプトの生成および実行。
このタスクについては、「タスク・スクリプトの生成および実行」を参照してください。

SQLアクセス・アドバイザの入力としてのSQLチューニング・セットの作成

SQLアクセス・アドバイザの入力ワークロード・ソースは、STSです。STSは、個別のエンティティとして格納されているため、複数のアドバイザ・タスクが共有できます。STSを作成するには、DBMS_SQLTUNE.CREATE_SQLSET文を使用します。

アドバイザ・タスクがSTSを参照した後は、すべてのアドバイザ・タスクからSTSに対する依存性が削除されるまで、STSを削除または変更できません。ワークロード参照が削除されるのは、親アドバイザ・タスクが削除された場合、またはアドバイザ・タスクからワークロード参照が手動で削除された場合です。

前提条件

STSを作成するユーザーには、ADMINISTER SQL TUNING SET権限が付与されている必要があります。他のユーザーが所有するSQLチューニング・セットでSQLアクセス・アドバイザを実行するには、ADMINISTER ANY SQL TUNING SET権限が必要です。

前提条件

このチュートリアルでは、次のことが前提となっています。

- MY_STS_WORKLOADという名前のSTSを作成します。

- shスキーマから導出されたワークロードへの入力としてこのSTSを使用します。

STSを作成する手順は次のとおりです。

1. ユーザーshとしてSQL*Plusをデータベースに接続して、SQL*Plus変数を設定します。
たとえば、次のコマンドを入力します。

CONNECT SH
Password: ********
SET SERVEROUTPUT ON;
VARIABLE task_id NUMBER;
VARIABLE task_name VARCHAR2(255);
VARIABLE workload_name VARCHAR2(255);

2. SQLチューニング・セットを作成します。
たとえば、値をworkload_name変数に割り当て、STSを作成するには次のように行います。

EXECUTE :workload_name := 'MY_STS_WORKLOAD';
EXECUTE DBMS_SQLTUNE.CREATE_SQLSET(:workload_name, 'test purpose');

関連項目:

- 「SQLチューニング・セットについて」

- CREATE_SQLSETの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

ユーザー定義のワークロードのSQLチューニング・セットへの移入

ワークロードは、1つ以上のSQL文と、各文を完全に説明する統計情報および属性で構成されます。全ワークロードには、対象となるビジネス・アプリケーションのすべてのSQL文が含まれます。部分ワークロードには、SQL文のサブセットが含まれます。これらの違いは、全ワークロードの場合、使用されていないマテリアライズド・ビューと索引を削除するようSQLアクセス・アドバイザが推奨する点にあります。

ワークロードなしでSQLアクセス・アドバイザを使用することはできません。SQLアクセス・アドバイザは特定の統計、ビジネスの重要性、またはその2つの組合せに応じてエントリにランクを付けます。これにより、アドバイザは最も重要なSQL文を先に処理できるようになります。

SQLアクセス・アドバイザのパフォーマンスは、実際の使用状況に基づいたワークロードを使用する場合に最も高くなります。複数のワークロードをSQLチューニング・セットとして保存することにより、長期およびデータベース・インスタンスの起動から停止までの全ライフサイクルにわたって、実際のデータ・ウェアハウスまたはOLTP環境の様々な使用状況を参照できます。

表21-1では、ユーザー定義のワークロードをSTSに移入する際に使用できるプロシージャを説明します。

表21-1 STSのロードのプロシージャ

プロシージャ

説明

DBMS_SQLTUNE.LOAD_SQLSET

選択したSQLのセットをSQLチューニング・セットに移入します。このプロシージャを複数回コールすると、新しいSQL文の追加または既存の文の属性の置換を行うことができます。『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

DBMS_ADVISOR.COPY_SQLWKLD_TO_STS

SQLワークロード・データをユーザーが指定したSQLチューニング・セットにコピーします。ユーザーには、SQLチューニング・セットの権限とADVISOR権限が必要です。『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

前提条件

このチュートリアルでは、次の操作を行うものとします。

- sh.user_workloadという名前の表を作成し、SQL文に関する情報を格納します。

- sh.user_workload表にshスキーマ内の表の3つの問合せに関する情報をロードします。

- 「SQLアクセス・アドバイザの入力としてのSQLチューニング・セットの作成」で作成されたSTSに、sh.user_workloadに格納されているワークロードを移入します。

ユーザー定義ワークロードをSTSに移入する手順は次のとおりです。

1. ユーザーshとしてSQL*Plusをデータベースに接続して、user_workload表を作成します。
たとえば、次のコマンドを入力します。

DROP TABLE user_workload;
CREATE TABLE user_workload
(
username             varchar2(128),   /* User who executes statement */
module               varchar2(64),        /* Application module name */
action               varchar2(64),        /* Application action name */
elapsed_time         number,               /* Elapsed time for query */
cpu_time             number,                   /* CPU time for query */
buffer_gets          number,        /* Buffer gets consumed by query */
disk_reads           number,         /* Disk reads consumed by query */
rows_processed       number,         /* # of rows processed by query */
executions           number,            /* # of times query executed */
optimizer_cost       number,             /* Optimizer cost for query */
priority             number,             /* User-priority (1,2 or 3) */
last_execution_date  date,               /* Last time query executed */
stat_period          number,          /* Window exec time in seconds */
sql_text             clob                           /* Full SQL Text */
);

2. 問合せに関する情報をuser_workload表にロードします。
たとえば、次の文を実行します。

-- aggregation with selection
INSERT INTO user_workload (username, module, action, priority, sql_text)
VALUES ('SH', 'Example1', 'Action', 2,
'SELECT   t.week_ending_day, p.prod_subcategory,
SUM(s.amount_sold) AS dollars, s.channel_id, s.promo_id
FROM     sales s, times t, products p
WHERE    s.time_id = t.time_id
AND      s.prod_id = p.prod_id
AND      s.prod_id > 10
AND      s.prod_id < 50
GROUP BY t.week_ending_day, p.prod_subcategory, s.channel_id, s.promo_id')
/

-- aggregation with selection
INSERT INTO user_workload (username, module, action, priority, sql_text)
VALUES ('SH', 'Example1', 'Action', 2,
'SELECT   t.calendar_month_desc, SUM(s.amount_sold) AS dollars
FROM     sales s , times t
WHERE    s.time_id = t.time_id
AND      s.time_id BETWEEN TO_DATE(''01-JAN-2000'', ''DD-MON-YYYY'')
AND      TO_DATE(''01-JUL-2000'', ''DD-MON-YYYY'')
GROUP BY t.calendar_month_desc')
/

-- order by
INSERT INTO user_workload (username, module, action, priority, sql_text)
VALUES ('SH', 'Example1', 'Action', 2,
'SELECT   c.country_id, c.cust_city, c.cust_last_name
FROM     customers c
WHERE    c.country_id IN (52790, 52789)
ORDER BY c.country_id, c.cust_city, c.cust_last_name')
/
COMMIT;

3. PL/SQLプログラムを実行して、user_workload表の行でカーソルを埋めて、このカーソルの内容をMY_STS_WORKLOADという名前のSTSにロードします。
たとえば、次のPL/SQLプログラムを実行します。

DECLARE
sqlset_cur DBMS_SQLTUNE.SQLSET_CURSOR;
BEGIN
OPEN sqlset_cur FOR
SELECT SQLSET_ROW(null,null, SQL_TEXT, null, null, 'SH', module,
'Action', 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, null, 2, 3,
sysdate, 0, 0, null, 0, null, null)
FROM USER_WORKLOAD;
DBMS_SQLTUNE.LOAD_SQLSET('MY_STS_WORKLOAD', sqlset_cur);
END;
/

SQLアクセス・アドバイザ・タスクの作成および構成

DBMS_ADVISOR.CREATE_TASKプロシージャを使用して、SQLアクセス・アドバイザ・タスクを作成します。

SQLアクセス・アドバイザでは、アドバイザが分析する内容と分析結果の格納場所を定義します。ユーザーは、それぞれが特化した複数のタスクを作成できます。これらすべてのタスクは同じアドバイザ・タスク・モデルに基づいており、同じリポジトリを共有します。

タスクを構成する手順は次のとおりです。

- タスク・パラメータの定義
推奨事項の生成時に、ワークロードにフィルタを適用して分析対象を制限できます。こうして制限することで、様々なワークロード・シナリオに基づいた推奨事項のセットを生成できます。

SQLアクセス・アドバイザ・パラメータは、ワークロードの推奨プロセスとカスタマイズを制御します。これらのパラメータは、必要な推奨事項のタイプや推奨内容のネーミング規則など、プロセスの様々な側面を制御します。

パラメータの定義がない場合、データベースはデフォルトを使用します。タスクのパラメータを設定するには、DBMS_ADVISOR.SET_TASK_PARAMETERプロシージャを使用します。パラメータは、タスクの存続期間は設定されたままであるという点において永続的です。SET_TASK_PARAMETERを使用してパラメータ値を設定した場合、このプロシージャをもう1回コールするまで、その値は変わりません。

- ワークロードへのタスクのリンク
ワークロードは独立しているため、DBMS_ADVISOR.ADD_STS_REFプロシージャを使用してタスクにリンクする必要があります。このリンクが確立された後は、すべてのアドバイザ・タスクからワークロードに対する依存性が削除されるまで、ワークロードを削除または変更できません。ユーザーが親アドバイザ・タスクを削除するか、DBMS_ADVISOR.DELETE_STS_REFプロシージャを使用してタスクからワークロード参照を手動で削除すると、ワークロード参照は削除されます。

前提条件

タスクを作成するユーザーには、ADVISOR権限が付与されている必要があります。

前提条件

このチュートリアルでは、次のことが前提となっています。

- MYTASKという名前のタスクを作成します。

- このタスクを使用して、「ユーザー定義のワークロードのSQLチューニング・セットへの移入」で定義されたワークロードを分析します。

- 実行に30分以上かかる場合は、タスクを終了します。

- SQLアクセス・アドバイザで、索引のみが考慮されるようにします。

SQLアクセス・アドバイザ・タスクを作成および構成する手順は次のとおりです。

1. ユーザーshとしてSQL*Plusをデータベースに接続して、タスクを作成します。
たとえば、次のコマンドを入力します。

EXECUTE :task_name := 'MYTASK';
EXECUTE DBMS_ADVISOR.CREATE_TASK('SQL Access Advisor', :task_id, :task_name);

2. タスク・パラメータを設定します。
たとえば、次の文を実行します。

EXECUTE DBMS_ADVISOR.SET_TASK_PARAMETER(:task_name, 'TIME_LIMIT', 30);
EXECUTE DBMS_ADVISOR.SET_TASK_PARAMETER(:task_name, 'ANALYSIS_SCOPE', 'ALL');

3. ワークロードへタスクをリンクします。
たとえば、次の文を実行します。

EXECUTE DBMS_ADVISOR.ADD_STS_REF(:task_name, 'SH', :workload_name);

関連項目:

- 「SQLアクセス・アドバイザのタスク・パラメータのカテゴリ」

- 「SQLアクセス・アドバイザ・タスクの削除」

- DBMS_ADVISOR.CREATE_TASK、DBMS_ADVISOR.SET_TASK_PARAMETERおよびDBMS_ADVISOR.ADD_STS_REFプロシージャの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください

SQLアクセス・アドバイザ・タスクの実行

DBMS_ADVISOR.EXECUTE_TASKプロシージャにより、指定したタスクがSQLアクセス・アドバイザによって分析または評価されます。タスクの実行は同期処理であるため、処理が完了するか、ユーザーによる割込みが検出されるまで、制御はユーザーに戻されません。タスクが戻されるか実行されると、実行ステータスについてDBA_ADVISOR_LOG表をチェックできます。

推奨事項を生成するには、EXECUTE_TASKを実行します。推奨事項には、マテリアライズド・ビュー・ログまたはマテリアライズド・ビューの作成などの1つ以上のアクションが含まれます。

前提条件と制限

ワークロードを処理する際、SQLアクセス・アドバイザは表と列の参照を識別するために各文の検証を試みます。検証では、本来のユーザーが文を実行する場合と同様に各文が処理されます。

ユーザーに特定の表に対するSELECT権限がない場合、SQLアクセス・アドバイザはその表を参照している文をバイパスします。この動作によって、多くの文が分析から除外される可能性があります。SQLアクセス・アドバイザがワークロードのすべての文を除外した場合、ワークロードは無効になります。SQLアクセス・アドバイザは、次のメッセージを戻します。

QSM-00774, there are no SQL statements to process for task TASK_NAME

重要なワークロード問合せが欠落しないようにするには、現在のデータベース・ユーザーが、マテリアライズド・ビューの分析対象の表に対するSELECT権限を持っている必要があります。これらの表では、ロールを通じてこれらのSELECT権限を取得することはできません。

前提条件

このチュートリアルでは、「SQLアクセス・アドバイザ・タスクの作成および構成」で構成されたタスクを実行するものとします。

SQLアクセス・アドバイザ・タスクを作成および構成する手順は次のとおりです。

1. ユーザーshとしてSQL*Plusをデータベースに接続して、タスクを実行します。
たとえば、次の文を実行します。

EXECUTE DBMS_ADVISOR.EXECUTE_TASK(:task_name);

2. オプションで、USER_ADVISOR_LOGを問い合せて、タスクのステータスを確認できます。
たとえば、次の文を実行します(出力例も示します)。

COL TASK_ID FORMAT 999
COL TASK_NAME FORMAT a25
COL STATUS_MESSAGE FORMAT a25

SELECT TASK_ID, TASK_NAME, STATUS, STATUS_MESSAGE
FROM   USER_ADVISOR_LOG;

TASK_ID TASK_NAME                 STATUS      STATUS_MESSAGE
------- ------------------------- ----------- -------------------------
103 MYTASK                    COMPLETED   Access advisor execution
completed

関連項目:

EXECUTE_TASKプロシージャとそのパラメータの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

SQLアクセス・アドバイザ・タスクの結果の表示

SQLアクセス・アドバイザにより生成された各推奨事項は、いくつかのデータ・ディクショナリ・ビューを使用して表示できます。

ビューについては、表21-2を参照してください。ただし、DBMS_ADVISOR.GET_TASK_SCRIPTプロシージャまたはCloud Controlを使用する方が簡単です。この場合、推奨事項がグラフィック表示され、推奨事項の利点を得るSQL文を簡単に参照するためのハイパーリンクが用意されています。

SQLアクセス・アドバイザによって生成された各推奨事項は、その利点を得るSQL文にリンクされています。各推奨事項には、1つ以上のアクションが対応します。各アクションには、1つ以上の属性があります。

各アクションには、アクセス構造のプロパティに関連する複数の属性があります。適用可能な各アクセス構造の名前と表領域は、USER_ADVISOR_ATTRIBUTESのATTR1列およびATTR2列にあります(「DBA_ADVISOR_ACTIONSビューのアクション属性」を参照)。新しい各アクセス構造が占有する領域は、NUM_ATTR1列にあります。その他の属性は、アクションごとに異なります。

表21-2 タスクの結果の表示ビュー

データ・ディクショナリ・ビュー(DBA、USER)

説明

DBA_ADVISOR_TASKS

アドバイザ・タスクに関する情報を示します。SQLアクセス・アドバイザ・タスクを参照するには、ADVISOR_NAME = 'SQL Access Advisor'の場所を選択します。

DBA_ADVISOR_RECOMMENDATIONS

データベース内のすべての推奨項目の分析結果を示します。推奨項目には、複数のアクションを対応付けることができます。このアクションについては、DBA_ADVISOR_ACTIONSビューを参照してください。推奨項目は、その正当な理由を表す一連の根拠も示します。この根拠については、DBA_ADVISOR_RATIONALEビューを参照してください。

DBA_ADVISOR_ACTIONS

データベース内のすべての推奨項目に関連付けられたアクションに関する情報を示します。各アクションは、COMMAND列およびATTR1からATTR6列で指定されます。各コマンドは、属性列の使用方法を定義します。

DBA_ADVISOR_RATIONALE

データベース内のすべての推奨項目の根拠に関する情報を示します。

DBA_ADVISOR_SQLA_WK_STMTS

SQLアクセス・アドバイザの分析後、データベース内のすべてのワークロード・オブジェクトに関する情報を示します。事前コストと事後コストの数は、推奨されたアクセス構造がある場合とない場合とで見積られたオプティマイザのコスト(EXPLAIN PLANを参照)に関するものです。

前提条件

このチュートリアルでは、「SQLアクセス・アドバイザ・タスクの実行」で実行されたタスクの結果を表示するものとします。

SQLアクセス・アドバイザ・タスクの結果を表示する手順は、次のとおりです。

1. 適切な権限でSQL*Plusをデータベースに接続して、アドバイザの推奨事項を問い合せます。
たとえば、次の文を実行します(出力例も示します)。

VARIABLE workload_name VARCHAR2(255);
VARIABLE task_name VARCHAR2(255);
EXECUTE :task_name := 'MYTASK';
EXECUTE :workload_name := 'MY_STS_WORKLOAD';

SELECT REC_ID, RANK, BENEFIT
FROM   USER_ADVISOR_RECOMMENDATIONS
WHERE  TASK_NAME = :task_name
ORDER BY RANK;

REC_ID       RANK    BENEFIT
---------- ---------- ----------
1          1        236
2          2        356

前述の出力は、SQLアクセス・アドバイザの実行によって生成された推奨事項(rec_id)とそのランクおよび全利点を示しています。ランクとは、推奨事項がサポートする問合せの重要性の尺度です。利点とは、推奨事項を使用したすべての問合せの実行コスト(オプティマイザのコストの観点から)における改善結果です。

2. 推奨事項が役立つ問合せを識別します。
たとえば、次のUSER_ADVISOR_SQLA_WK_STMTSの問合せを実行します(出力例も示します)。

SELECT SQL_ID, REC_ID, PRECOST, POSTCOST,
(PRECOST-POSTCOST)*100/PRECOST AS PERCENT_BENEFIT
FROM   USER_ADVISOR_SQLA_WK_STMTS
WHERE  TASK_NAME = :task_name
AND    WORKLOAD_NAME = :workload_name
ORDER BY percent_benefit DESC;

SQL_ID            REC_ID    PRECOST   POSTCOST PERCENT_BENEFIT
------------- ---------- ---------- ---------- ---------------
fn4bsxdm98w3u          2        578        222      61.5916955
29bbju72rv3t2          1       5750       5514      4.10434783
133ym38r6gbar          0        772        772               0

事前コストと事後コストの数は、推奨されたアクセス構造の変更がある場合とない場合とで見積られたオプティマイザのコスト(EXPLAIN PLANを参照)に関するものです。

3. この一連の推奨事項について個別アクションの数を示します。
たとえば、次の問合せを使用します(出力例も示します)。

SELECT 'Action Count', COUNT(DISTINCT action_id) cnt
FROM   USER_ADVISOR_ACTIONS
WHERE  TASK_NAME = :task_name;

'ACTIONCOUNT        CNT
------------ ----------
Action Count          4

4. この一連の推奨事項に対するアクションを示します。
たとえば、次の問合せを使用します(出力例も示します)。

SELECT REC_ID, ACTION_ID, SUBSTR(COMMAND,1,30) AS command
FROM   USER_ADVISOR_ACTIONS
WHERE  TASK_NAME = :task_name
ORDER BY rec_id, action_id;

REC_ID  ACTION_ID COMMAND
---------- ---------- ------------------------------
1          1 PARTITION TABLE
1          2 RETAIN INDEX
2          1 PARTITION TABLE
2          3 RETAIN INDEX
2          4 RETAIN INDEX

5. 推奨事項の属性を示します。
たとえば、次のアクションの属性を参照するには、次のPL/SQLプロシージャshow_recmを作成して実行します。

CREATE OR REPLACE PROCEDURE show_recm (in_task_name IN VARCHAR2) IS
CURSOR curs IS
SELECT DISTINCT action_id, command, attr1, attr2, attr3, attr4
FROM user_advisor_actions
WHERE task_name = in_task_name
ORDER BY action_id;
v_action        number;
v_command     VARCHAR2(32);
v_attr1       VARCHAR2(4000);
v_attr2       VARCHAR2(4000);
v_attr3       VARCHAR2(4000);
v_attr4       VARCHAR2(4000);
v_attr5       VARCHAR2(4000);
BEGIN
OPEN curs;
DBMS_OUTPUT.PUT_LINE('=========================================');
DBMS_OUTPUT.PUT_LINE('Task_name = ' || in_task_name);
LOOP
FETCH curs INTO
v_action, v_command, v_attr1, v_attr2, v_attr3, v_attr4 ;
EXIT when curs%NOTFOUND;
DBMS_OUTPUT.PUT_LINE('Action ID: ' || v_action);
DBMS_OUTPUT.PUT_LINE('Command : ' || v_command);
DBMS_OUTPUT.PUT_LINE('Attr1 (name)      : ' || SUBSTR(v_attr1,1,30));
DBMS_OUTPUT.PUT_LINE('Attr2 (tablespace): ' || SUBSTR(v_attr2,1,30));
DBMS_OUTPUT.PUT_LINE('Attr3             : ' || SUBSTR(v_attr3,1,30));
DBMS_OUTPUT.PUT_LINE('Attr4             : ' || v_attr4);
DBMS_OUTPUT.PUT_LINE('Attr5             : ' || v_attr5);
DBMS_OUTPUT.PUT_LINE('----------------------------------------');
END LOOP;
CLOSE curs;
DBMS_OUTPUT.PUT_LINE('=========END RECOMMENDATIONS============');
END show_recm;
/

SET SERVEROUTPUT ON SIZE 99999
EXECUTE show_recm(:task_name);

次の出力は、推奨事項のアクションの属性を示しています。

=========================================
Task_name = MYTASK
Action ID: 1
Command : PARTITION TABLE
Attr1 (name)      : "SH"."SALES"
Attr2 (tablespace):
Attr3             : ("TIME_ID")
Attr4             : INTERVAL
Attr5             :
----------------------------------------
Action ID: 2
Command : RETAIN INDEX
Attr1 (name)      : "SH"."PRODUCTS_PK"
Attr2 (tablespace):
Attr3             : "SH"."PRODUCTS"
Attr4             : BTREE
Attr5             :
----------------------------------------
Action ID: 3
Command : RETAIN INDEX
Attr1 (name)      : "SH"."TIMES_PK"
Attr2 (tablespace):
Attr3             : "SH"."TIMES"
Attr4             : BTREE
Attr5             :
----------------------------------------
Action ID: 4
Command : RETAIN INDEX
Attr1 (name)      : "SH"."SALES_TIME_BIX"
Attr2 (tablespace):
Attr3             : "SH"."SALES"
Attr4             : BITMAP
Attr5             :
----------------------------------------
=========END RECOMMENDATIONS============

関連項目:

Attr5およびAttr6の詳細は、Oracle Database PL/SQLパッケージおよびタイプ・リファレンスを参照してください

タスク・スクリプトの生成および実行

DBMS_ADVISOR.GET_TASK_SCRIPTプロシージャを使用して、SQLアクセス・アドバイザの推奨事項に対するSQL文のスクリプトを作成できます。スクリプトは実行可能SQLファイルで、DROP文、CREATE文およびALTER文を含めることができます。

新しいオブジェクトの場合、マテリアライズド・ビューの名前、マテリアライズド・ビュー・ログおよび索引は、ユーザー指定の名前テンプレートを使用して自動的に生成されます。生成されたSQLスクリプトは、実行する前に見直します。

前提条件

このチュートリアルでは、「SQLアクセス・アドバイザ・タスクの実行」で生成された推奨事項を含むスクリプトの保存および実行を行うものとします。

SQLスクリプトを保存および実行する手順は次のとおりです。

1. 管理者としてSQL*Plusをデータベースに接続します。

2. ディレクトリ・オブジェクトを作成し、読取り/書込みを行う権限を付与します。
たとえば、次の文を使用します。

CREATE DIRECTORY ADVISOR_RESULTS AS '/tmp';
GRANT READ ON DIRECTORY ADVISOR_RESULTS TO PUBLIC;
GRANT WRITE ON DIRECTORY ADVISOR_RESULTS TO PUBLIC;

3. データベースにshとして接続し、ファイルにスクリプトを保存します。
たとえば、次の文を使用します。

EXECUTE DBMS_ADVISOR.CREATE_FILE(DBMS_ADVISOR.GET_TASK_SCRIPT('MYTASK'),
'ADVISOR_RESULTS', 'advscript.sql');

4. テキスト・エディタを使用して、スクリプトの内容を表示します。
次の例は、このプロシージャよって生成されたスクリプトのフラグメントです。

Rem  Username:        SH
Rem  Task:            MYTASK
Rem  Execution date:
Rem

Rem
Rem  Repartitioning table "SH"."SALES"
Rem

SET SERVEROUTPUT ON
SET ECHO ON

Rem
Rem Creating new partitioned table
Rem
CREATE TABLE "SH"."SALES1"
(    "PROD_ID" NUMBER,
"CUST_ID" NUMBER,
"TIME_ID" DATE,
"CHANNEL_ID" NUMBER,
"PROMO_ID" NUMBER,
"QUANTITY_SOLD" NUMBER(10,2),
"AMOUNT_SOLD" NUMBER(10,2)
) PCTFREE 5 PCTUSED 40 INITRANS 1 MAXTRANS 255
NOCOMPRESS  NOLOGGING
TABLESPACE "EXAMPLE"
PARTITION BY RANGE ("TIME_ID") INTERVAL( NUMTOYMINTERVAL( 1, 'MONTH'))
( PARTITION VALUES LESS THAN (TO_DATE(' 1998-02-01 00:00:00',
'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIAN')) );
.
.
.

5. オプションとして、SQL*PlusでSQLスクリプトを実行できます。
たとえば、次のコマンドを入力します。

@/tmp/advscript.sql

関連項目:

- CREATE DIRECTORYの構文の詳細は、Oracle Database SQL言語リファレンスを参照してください

- GET_TASK_SCRIPTファンクションの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください

SQLアクセス・アドバイザ・クイック・チューニングの実行

単一のSQL文をチューニングするには、task_nameと単一のSQL文を入力として受け入れるDBMS_ADVISOR.QUICK_TUNEプロシージャを使用します。このプロシージャは、タスクとワークロードを作成し、そのタスクを実行します。EXECUTE_TASKとQUICK_TUNEでは、同じ結果が得られます。ただし、単一のSQL文をチューニングする場合、QUICK_TUNEがより簡単です。

前提条件

このチュートリアルでは、次のことが前提となっています。

- 単一のSQL文をチューニングします。

- タスクにMY_QUICKTUNE_TASKという名前を付けます。

テンプレートを作成し、このテンプレートをタスクのベースとする手順は次のとおりです。

1. ユーザーshとしてSQL*Plusをデータベースに接続して、SQL文とタスク名に対してSQL*Plus変数を初期化します。
たとえば、次のコマンドを入力します。

VARIABLE t_name VARCHAR2(255);
VARIABLE sq VARCHAR2(4000);
EXEC :sq := 'SELECT COUNT(*) FROM customers WHERE cust_state_province =''CA''';
EXECUTE :t_name := 'MY_QUICKTUNE_TASK';

2. クィック・チューニングを実行します。
たとえば、次の文はMY_QUICKTUNE_TASKを実行します。

EXEC DBMS_ADVISOR.QUICK_TUNE(DBMS_ADVISOR.SQLACCESS_ADVISOR,:t_name,:sq);

関連項目:

QUICK_TUNEプロシージャとそのパラメータの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

SQLアクセス・アドバイザの使用: 詳細タスク

この項の内容は次のとおりです。

- 既存のアクセス構造の評価

- SQLアクセス・アドバイザのタスク属性の更新

- SQLアクセス・アドバイザのタスク・テンプレートの作成および使用

- SQLアクセス・アドバイザ・タスクの実行終了

- SQLアクセス・アドバイザ・タスクの削除

- SQLアクセス・アドバイザ推奨事項のマーク

- SQLアクセス・アドバイザ推奨事項の変更

既存のアクセス構造の評価

SQLアクセス・アドバイザは、問題解決モードと評価モードの2つのモードで動作します。SQLアクセス・アドバイザは、デフォルトでは、アクセス方法の問題を解決するために、索引構造、パーティション、マテリアライズド・ビューおよびマテリアライズド・ビュー・ログの拡張を求めます。たとえば、問題解決モードで実行すると、新しい索引の作成やマテリアライズド・ビュー・ログへの新しい列の追加などが推奨されます。

ANALYSIS_SCOPEパラメータをEVALUATIONに設定すると、SQLアクセス・アドバイザは、指定されたワークロードがどのアクセス構造を使用するかについてのみコメントします。評価のみの実行では、索引の保持やマテリアライズド・ビューの保持などの推奨のみとなります。評価モードでは、ワークロードがどの索引およびマテリアライズド・ビューを使用するのか正確に知ることができます。SQLアクセス・アドバイザは、既存の実表のパーティション化によるパフォーマンスへの影響は評価されません。

タスクを作成して評価モードに設定する手順は、次のとおりです。

1. 適切な権限でSQL*Plusをデータベースに接続して、タスクを作成します。
たとえば、次の文を入力します。t_nameはタスクの名前に設定されたSQL*Plus変数です。

EXECUTE DBMS_ADVISOR.EXECUTE_TASK(:t_name);

2. クィック・チューニングを実行します。
たとえば、次の文は、前述のタスクを評価モードに設定します。

EXECUTE DBMS_ADVISOR.SET_TASK_PARAMETER(:t_name,'ANALYSIS_SCOPE','EVALUATION');

関連項目:

SET_TASK_PARAMETERプロシージャとそのパラメータの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

SQLアクセス・アドバイザのタスク属性の更新

DBMS_ADVISOR.UPDATE_TASK_ATTRIBUTESプロシージャを使用して、次のことができます。

- タスク名の変更。

- タスクの説明の付加。

- タスクの読取り専用(変更不可)設定。

- 他のタスクを定義できるテンプレートとしてのタスクの作成(「SQLアクセス・アドバイザのタスク・テンプレートの作成および使用」を参照)。

- タスクやタスク・テンプレートの様々な属性の変更。

前提条件

このチュートリアルでは、次のことが前提となっています。

- 既存のタスクMYTASKの名前をTUNING1に変更します。

- タスクTUNING1を読取り専用にします。

タスクの属性を更新する手順は次のとおりです。

1. ユーザーshとしてSQL*Plusをデータベースに接続して、タスクの名前を変更します。
たとえば、次の文を使用します。

EXECUTE DBMS_ADVISOR.UPDATE_TASK_ATTRIBUTES('MYTASK', 'TUNING1');

2. タスクを読取り専用に設定します。
たとえば、次の文を使用します。

EXECUTE DBMS_ADVISOR.UPDATE_TASK_ATTRIBUTES('TUNING1',
read_only => 'true');

関連項目:

UPDATE_TASK_ATTRIBUTESプロシージャとそのパラメータの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

SQLアクセス・アドバイザのタスク・テンプレートの作成および使用

タスク・テンプレートは、構成を保存したもので、今後のタスクおよびワークロードのベースとなります。タスクまたはワークロードをテンプレートとして設定すると、今後のタスクの作成で、出発点またはテンプレートとして使用できます。テンプレートを設定することにより、チューニング分析の実行時間を短縮できます。また、このアプローチにより、ビジネス・オペレーションに適合したチューニング分析が可能になります。

物理的に、タスクとテンプレートは同じです。ただし、テンプレートは実行できません。テンプレートからタスクを作成するには、新しいタスクの作成時に使用するテンプレートを指定します。このとき、SQLアクセス・アドバイザは、新しく作成されたタスクにテンプレートからデータおよびパラメータ設定をコピーします。また、既存のタスクをテンプレートとして設定するには、タスクの作成時にテンプレート属性を設定するか、後でUPDATE_TASK_ATTRIBUTEプロシージャを使用します。

表21-3では、タスク・テンプレートを管理する際に使用できるプロシージャを説明します。

表21-3 タスク・テンプレートのDBMS_ADVISORプロシージャ

プロシージャ

説明

CREATE_TASK

templateパラメータは、既存のタスクまたはタスク・テンプレートのオプションのタスク名です。SQLアクセス・アドバイザの組込みテンプレートを指定するには、表21-6の説明に従って、テンプレート名を使用します。is_templateはオプションのパラメータで、新たに作成されたタスクをテンプレートとして設定できます。有効な値は、trueとfalseです。

SET_TASK_PARAMETER

INDEX_NAME_TEMPLATEパラメータは、新しい索引名を構成する方法を指定します。MVIEW_NAME_TEMPLATEパラメータは、新しいマテリアライズド・ビュー名を構成する方法を指定します。PARTITION_NAME_TEMPLATEパラメータは、新しいパーティション名を構成する方法を指定します。タスク・パラメータの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

UPDATE_TASK_ATTRIBUTES

is_templateは、タスクをテンプレートとしてマークします。物理的にタスクとテンプレートの違いはありませんが、テンプレートは実行できません。設定可能な値はtrueおよびfalseです。値がNULLか、またはADVISOR_UNUSEDが格納されている場合、設定は変更されません。

前提条件

このチュートリアルでは、次のことが前提となっています。

- MY_TEMPLATEという名前のテンプレートを作成します。

- MY_TEMPLATEに基づいてタスクによって推奨される索引およびマテリアライズド・ビューのネーミング規則を設定します。

- MY_TEMPLATEに基づいてNEWTASKタスクを作成します。

テンプレートを作成し、このテンプレートをタスクのベースとする手順は次のとおりです。

1. ユーザーshとしてSQL*Plusをデータベースに接続して、タスクをテンプレートとして作成します。
たとえば、次のようにMY_TEMPLATEという名前のテンプレートを作成します。

VARIABLE template_id NUMBER;
VARIABLE template_name VARCHAR2(255);
EXECUTE :template_name := 'MY_TEMPLATE';
BEGIN
DBMS_ADVISOR.CREATE_TASK (
'SQL Access Advisor'
,   :template_id
,   :template_name
,   is_template => 'true'
);
END;

2. テンプレートのパラメータを設定します。
たとえば、次の文は、推奨される索引およびマテリアライズド・ビューのネーミング規則を設定します。

-- set naming conventions for recommended indexes/mvs
BEGIN
DBMS_ADVISOR.SET_TASK_PARAMETER (
:template_name
,   'INDEX_NAME_TEMPLATE'
,   'SH_IDX$$_<SEQ>'
);
END;

BEGIN
DBMS_ADVISOR.SET_TASK_PARAMETER (
:template_name
,   'MVIEW_NAME_TEMPLATE'
,   'SH_MV$$_<SEQ>'
);
END;

3. 既存のテンプレートに基づいてタスクを作成します。
たとえば、次のコマンドを入力して、MY_TEMPLATEに基づいたNEWTASKを作成します。

VARIABLE task_id NUMBER;
VARIABLE task_name VARCHAR2(255);
EXECUTE :task_name := 'NEWTASK';
BEGIN
DBMS_ADVISOR.CREATE_TASK (
'SQL Access Advisor'
,   :task_id
,   :task_name
,   template=>'MY_TEMPLATE'
);
END;

関連項目:

- CREATE_TASKプロシージャとそのパラメータの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

- SET_TASK_PARAMETERプロシージャとそのパラメータの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

SQLアクセス・アドバイザ・タスクの実行終了

SQLアクセス・アドバイザにより、推奨プロセスへの割込みまたは推奨プロセスの完了が可能になります。割込みによって、SQLアクセス・アドバイザは処理を停止し、タスクはINTERRUPTEDとマークされます。その時点で、推奨事項の属性を更新してスクリプトを生成できます。

中間結果は、その時点までのワークロードの内容に対する推奨事項を示しています。推奨事項がワークロード全体の影響を受けやすい場合は、タスクを完了させることをお薦めします。また、推奨プロセスの初期段階でアドバイザによって作成される推奨事項には、実表のパーティション化に関する推奨は含まれません。パーティション化分析では、パーティション化が有効かどうかを決定する前に、ワークロードの大部分を処理する必要があります。したがって、SQLアクセス・アドバイザが利点を検出した場合は、より遅い段階での中間結果に実表のパーティション化に関する推奨事項が含まれます。

この項では、SQLアクセス・アドバイザ・タスクの実行を終了する2つの方法を説明します。

- SQLアクセス・アドバイザ・タスクへの割込み

- SQLアクセス・アドバイザ・タスクの取消し

SQLアクセス・アドバイザ・タスクへの割込み

DBMS_ADVISOR.INTERRUPT_TASKプロシージャを使用すると、SQLアクセス・アドバイザ・タスクの実行は正常終了に達したものとして終了されます。これにより、ユーザーには、割込みポイントまでに構成された推奨事項が表示されます。割り込まれたタスクは再開できません。構文は、次のとおりです。

DBMS_ADVISOR.INTERRUPT_TASK (task_name IN VARCHAR2);

前提条件

このチュートリアルでは、次のことが前提となっています。

- 処理時間の長いタスクMYTASKが現在実行中です。

- このタスクに割り込んで、推奨事項を表示します。

現在実行中のタスクに割り込む手順は次のとおりです。

1. ユーザーshとしてSQL*Plusをデータベースに接続して、タスクに割り込みます。
たとえば、次のようにMY_TEMPLATEという名前のテンプレートを作成します。

EXECUTE DBMS_ADVISOR.INTERRUPT_TASK ('MYTASK');

関連項目:

INTERRUPT_TASKプロシージャの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

SQLアクセス・アドバイザ・タスクの取消し

タスクの実行を停止するには、DBMS_ADVISOR.CANCEL_TASKプロシージャをコールして、この推奨プロセスのタスク名を渡します。SQLアクセス・アドバイザがこのリクエストに応答するのに数秒かかることがあります。すべてのアドバイザ・タスクのプロシージャは同期操作であるため、操作を取り消すには、別のデータベース・セッションを使用する必要があります。CANCEL_TASKを使用した場合、SQLアクセス・アドバイザの推奨事項はありません。

取消コマンドは、取り消された操作の開始前の状態にタスクを効率的にリストアします。そのため、取り消されたタスクまたはデータ・オブジェクトは再開できません。ただし、DBMS_ADVISOR.RESET_TASKを使用してタスクをリセットすると、再実行できます。CANCEL_TASKの構文は次のとおりです。

DBMS_ADVISOR.CANCEL_TASK (task_name   IN  VARCHAR2);

RESET_TASKプロシージャは、タスクを初期の開始ポイントにリセットします。これにより、すべての推奨事項と中間データがタスクから削除されます。タスクのステータスは、INITIALに設定されます。構文は、次のとおりです。

DBMS_ADVISOR.RESET_TASK (task_name     IN VARCHAR2);

前提条件

このチュートリアルでは、次のことが前提となっています。

- 処理時間の長いタスクMYTASKが現在実行中です。このタスクは、推奨事項のパーティション化を行うために設定されます。

- このタスクを取り消して、タスクが索引のみ推奨するようにリセットします。

現在実行中のタスクを取り消す手順は次のとおりです。

1. ユーザーshとしてSQL*Plusをデータベースに接続して、タスクを取り消します。
たとえば、次のようにMY_TEMPLATEという名前のテンプレートを作成します。

EXECUTE DBMS_ADVISOR.CANCEL_TASK ('MYTASK');

2. タスクをリセットします。
たとえば、RESET_TASKプロシージャを次のように実行します。

EXECUTE DBMS_ADVISOR.RESET_TASK('MYTASK');

3. タスク・パラメータを設定します。
たとえば、分析の有効範囲を次のようにINDEXに変更します。

EXECUTE DBMS_ADVISOR.SET_TASK_PARAMETER(:task_name, 'ANALYSIS_SCOPE', 'INDEX');

4. タスクを実行します。
たとえば、MYTASKを次のように実行します。

EXECUTE DBMS_ADVISOR.EXECUTE_TASK ('MYTASK');

関連項目:

- RESET_TASKプロシージャとそのパラメータの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

- CANCEL_TASKプロシージャとそのパラメータの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

SQLアクセス・アドバイザ・タスクの削除

DBMS_ADVISOR.DELETE_TASKプロシージャでは、SQLアクセス・アドバイザの既存のタスクがリポジトリから削除されます。構文は、次のとおりです。

DBMS_ADVISOR.DELETE_TASK (task_name  IN VARCHAR2);

タスクがSTSワークロードにリンクされている場合、タスクまたはワークロードを削除するには、DELETE_STS_REFプロシージャを使用してタスクとワークロード間のリンクを削除する必要があります。次の例では、タスクMYTASKと現在のユーザーのSQLチューニング・セットMY_STS_WORKLOADの間のリンクを削除します。

EXECUTE DBMS_ADVISOR.DELETE_STS_REF('MYTASK', null, 'MY_STS_WORKLOAD');

前提条件

このチュートリアルでは、次のことが前提となっています。

- ユーザーshが、現在複数のSQLアクセス・アドバイザ・タスクを所有しています。

- MYTASKを削除します。

- MYTASKタスクは、現在 MY_STS_WORKLOADワークロードにリンクしています。

SQLアクセス・アドバイザ・タスクを削除する手順は次のとおりです。

1. ユーザーshとしてSQL*Plusをデータベースに接続して、SQLアクセス・アドバイザの既存のタスクを問い合せます。
たとえば、データ・ディクショナリを次のように問い合せます(出力例も示します)。

SELECT TASK_NAME
FROM   USER_ADVISOR_TASKS
WHERE  ADVISOR_NAME = 'SQL Access Advisor';

TASK_NAME
-------------------------
MYTASK
NEWTASK

2. MYTASKと MY_STS_WORKLOAD間のリンクを削除します。
たとえば、リファレンスを次のように削除します。

EXECUTE DBMS_ADVISOR.DELETE_STS_REF('MYTASK', null, 'MY_STS_WORKLOAD');

3. 目的のタスクを削除します。
たとえば、MYTASKを次のように削除します。

EXECUTE DBMS_ADVISOR.DELETE_TASK('MYTASK');

関連項目:

DELETE_TASKプロシージャとそのパラメータの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

SQLアクセス・アドバイザ推奨事項のマーク

デフォルトでは、SQLアクセス・アドバイザのすべての推奨事項は実装可能な状態にあります。ただし、DBMS_ADVISOR.MARK_RECOMMENDATIONプロシージャを使用して、選択した推奨事項のスキップまたは除外を選択できます。MARK_RECOMMENDATIONでは、ユーザーがREJECTまたはIGNORE設定を使用して推奨事項に注釈を付けることができます。実装プロシージャを生成する際に、GET_TASK_SCRIPTは、注釈の付けられた推奨事項をスキップします。

SQLアドバイザにより、パーティション化されていない1つ以上の実表のパーティション化が推奨された場合、その推奨事項をスキップする前に慎重に検討してください。表のパーティション化スキームを変更すると、その表に定義されたすべての問合せ、索引およびマテリアライズド・ビューのコストに影響を及ぼします。このため、パーティション化の推奨事項をスキップした場合は、その表に対してアドバイザが行ったその他の推奨も最適ではありません。パーティション化を含めずにワークロードの推奨事項を確認するには、ANALYSIS_SCOPEパラメータを変更してパーティション化の推奨を除外し、アドバイザ・タスクをリセットして、再度タスクを実行します。

構文は、次のとおりです。

DBMS_ADVISOR.MARK_RECOMMENDATION (
task_name          IN VARCHAR2
id                 IN NUMBER,
action             IN VARCHAR2);

前提条件

このチュートリアルでは、次のことが前提となっています。

- チュートリアルの「SQLアクセス・アドバイザ・タスクの結果の表示」の説明に従って、推奨事項を確認します。

- 最初の推奨事項(表をパーティション化する)を拒否します。

推奨事項をマークする手順は次のとおりです。

1. ユーザーshとしてSQL*Plusをデータベースに接続して、推奨事項をマークします。
たとえば、1の推奨事項を次のように拒否します。

EXECUTE DBMS_ADVISOR.MARK_RECOMMENDATION('MYTASK', 1, 'REJECT');

この推奨事項およびこれに依存する推奨事項は、スクリプトに表示されません。

2. 「タスク・スクリプトの生成および実行」の説明に従って、スクリプトを生成します。

関連項目:

MARK_RECOMMENDATIONSプロシージャとそのパラメータの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

SQLアクセス・アドバイザ推奨事項の変更

UPDATE_REC_ATTRIBUTESプロシージャを使用すると、SQLアクセス・アドバイザでは、分析時に索引やマテリアライズド・ビューなどの新しいオブジェクトに名前が付けられ、所有者が割り当てられます。ただし、必ずしも適切な名前が選択されるとはかぎらないため、新しいオブジェクトの所有者、名前および表領域の値を手動で設定できます。既存のデータベース・オブジェクトを参照している推奨事項の場合、所有者と名前の値は変更できません。構文は、次のとおりです。

DBMS_ADVISOR.UPDATE_REC_ATTRIBUTES (
task_name            IN VARCHAR2
rec_id               IN NUMBER,
action_id            IN NUMBER,
attribute_name       IN VARCHAR2,
value                IN VARCHAR2);

attribute_nameパラメータには、次の値を使用できます。

- OWNER
推奨オブジェクトの所有者名を指定します。

- NAME
推奨オブジェクトの名前を指定します。

- TABLESPACE
推奨オブジェクトの表領域を指定します。

前提条件

このチュートリアルでは、次のことが前提となっています。

- チュートリアルの「SQLアクセス・アドバイザ・タスクの結果の表示」の説明に従って、推奨事項を確認します。

- 推奨事項1、アクション1の表領域をSH_MVIEWSに変更します。

推奨事項をマークする手順は次のとおりです。

1. ユーザーshとしてSQL*Plusをデータベースに接続して、推奨事項の属性を更新します。
たとえば、表領域の名前を次のようにSH_MVIEWSに変更します。

BEGIN
DBMS_ADVISOR.UPDATE_REC_ATTRIBUTES (
'MYTASK'
,   1
,   1
,   'TABLESPACE'
,   'SH_MVIEWS'
);
END;

2. 「タスク・スクリプトの生成および実行」の説明に従って、スクリプトを生成します。

関連項目:

UPDATE_REC_ATTRIBUTESプロシージャとそのパラメータの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

SQLアクセス・アドバイザの例

Oracle Databaseでは、テスト・データベースで実行できるSQLアクセス・アドバイザの複数の例を含むスクリプトが提供されています。スクリプトには、ORACLE_HOME/rdbms/demo/aadvdemo.sqlという名前が付けられています。

SQLアクセス・アドバイザ・リファレンス

この項の内容は次のとおりです。

- DBA_ADVISOR_ACTIONSビューのアクション属性

- SQLアクセス・アドバイザのタスク・パラメータのカテゴリ

- SQLアクセス・アドバイザの定数

DBA_ADVISOR_ACTIONSビューのアクション属性

表21-4では、SQLアクセス・アドバイザ・アクションをDBA_ADVISOR_ACTIONSビューの属性列にマップします。表内のMVは、マテリアライズド・ビューを意味します。

表21-4 SQLアクセス・アドバイザのアクション属性

アクション

ATTR1列

ATTR2列

ATTR3列

ATTR4列

ATTR5列

ATTR6列

NUM_ATTR1列

CREATE INDEX

索引名

索引表領域

ターゲット表

BITMAP orBTREE

索引列リスト/式

未使用

索引の記憶域のサイズ(バイト単位)

CREATE MATERIALIZED VIEW

MV名

MV表領域

REFRESH COMPLETE、REFRESH FAST、REFRESH FORCE、NEVER REFRESH

ENABLE QUERY REWRITE、DISABLE QUERY REWRITE

SQL SELECT文

未使用

MVの記憶域のサイズ(バイト単位)

CREATE MATERIALIZED VIEW LOG

ターゲット表名

MVログ表領域

ROWID PRIMARY KEY、SEQUENCE OBJECT ID

INCLUDING NEW VALUES、EXCLUDING NEW VALUES

表列リスト

パーティション副次句

未使用

CREATE REWRITE EQUIVALENCE

等価名

チェックサム値

未使用

未使用

ソースSQL文

等価SQL文

未使用

DROP INDEX

索引名

未使用

未使用

未使用

索引列

未使用

索引の記憶域のサイズ(バイト単位)

DROP MATERIALIZED VIEW

MV名

未使用

未使用

未使用

未使用

未使用

MVの記憶域のサイズ(バイト単位)

DROP MATERIALIZED VIEW LOG

ターゲット表名

未使用

未使用

未使用

未使用

未使用

未使用

PARTITION TABLE

表名

RANGE、INTERVAL、LIST、HASH、RANGE-HASH、RANGE-LIST

パーティション化のパーティション・キー(列名または列名のリスト)

サブパーティション化のパーティション・キー(列名または列名のリスト)

SQL PARTITION句

SQL SUBPARTITION句

未使用

PARTITION INDEX

索引名

LOCAL、RANGE、HASH

パーティション化のパーティション・キー(列名のリスト)

未使用

SQL PARTITION句

未使用

未使用

PARTITION ON MATERIALIZED VIEW

MV名

RANGE、INTERVAL、LIST、HASH、RANGE-HASH、RANGE-LIST

パーティション化のパーティション・キー(列名または列名のリスト)

サブパーティション化のパーティション・キー(列名または列名のリスト)

SQL SUBPARTITION句

SQL SUBPARTITION句

未使用

RETAIN INDEX

索引名

未使用

ターゲット表

BITMAPまたはBTREE

索引列

未使用

索引の記憶域のサイズ(バイト単位)

RETAIN MATERIALIZED VIEW

MV名

未使用

REFRESH COMPLETEまたはREFRESH FAST

未使用

SQL SELECT文

未使用

MVの記憶域のサイズ(バイト単位)

RETAIN MATERIALIZED VIEW LOG

ターゲット表名

未使用

未使用

未使用

未使用

未使用

未使用

SQLアクセス・アドバイザのタスク・パラメータのカテゴリ

表21-5では、最も関連性の高いSQLアクセス・アドバイザのタスク・パラメータをカテゴリにグループ化します。ワークロード・フィルタのタスク・パラメータはすべて非推奨です。

表21-5 アドバイザのタスク・パラメータのタイプとその使用方法

ワークロード・フィルタ

タスク構成

スキーマ属性

推奨オプション

END_TIME

DAYS_TO_EXPIRE

DEF_INDEX_OWNER

ANALYSIS_SCOPE

INVALID_ACTION_LIST

JOURNALING

DEF_INDEX_TABLESPACE

COMPATIBILITY

INVALID_MODULE_LIST

REPORT_DATE_FORMAT

DEF_MVIEW_OWNER

CREATION_COST

INVALID_SQLSTRING_LIMIT

DEF_MVIEW_TABLESPACE

DML_VOLATILITY

INVALID_TABLE_LIST

DEF_MVLOG_TABLESPACE

LIMIT_PARTITION_SCHEMES

INVALID_USERNAME_LIST

DEF_PARTITION_TABLESPACE

MODE

RANKING_MEASURE

INDEX_NAME_TEMPLATE

PARTITIONING_TYPES

SQL_LIMIT

MVIEW_NAME_TEMPLATE

REFRESH_MODE

START_TIME

STORAGE_CHANGE

TIME_LIMIT

USE_SEPARATE_TABLESPACES

VALID_ACTION_LIST

WORKLOAD_SCOPE

VALID_MODULE_LIST

VALID_SQLSTRING_LIST

VALID_TABLE_LIST

VALID_USERNAME_LIST

SQLアクセス・アドバイザの定数

SQLアクセス・アドバイザでは、表21-6に示されている定数を使用できます。

表21-6 SQLアクセス・アドバイザの定数

定数

説明

ADVISOR_ALL

すべての可能な値を示す値。文字列パラメータでは、この値はワイルドカード文字である%と同等です。

ADVISOR_CURRENT

現在の時刻またはアクティブな要素セットを示します。通常、これは時間パラメータで使用します。

ADVISOR_DEFAULT

デフォルト値を示します。通常、タスクまたはワークロード・パラメータの設定時に使用します。

ADVISOR_UNLIMITED

無制限な数値を表す値です。

ADVISOR_UNUSED

未使用のエンティティを表す値。パラメータがADVISOR_UNUSEDに設定されている場合、現在の処理はこのパラメータの影響を受けません。通常、この定数を使用して、パラメータに依存する処理でパラメータを未使用に設定します。

SQLACCESS_GENERAL

SQLアクセスの汎用タスク・テンプレートのデフォルト名を指定します。このテンプレートは、DML_VOLATILITYタスク・パラメータをtrueに設定し、ANALYSIS_SCOPEをINDEX、MVIEWに設定します。

SQLACCESS_OLTP

SQLアクセスのOLTPタスク・テンプレートのデフォルト名を指定します。このテンプレートは、DML_VOLATILITYタスク・パラメータをtrueに設定し、ANALYSIS_SCOPEをINDEXに設定します。

SQLACCESS_WAREHOUSE

SQLアクセスのウェアハウス・タスク・テンプレートのデフォルト名を指定します。このテンプレートは、DML_VOLATILITYタスク・パラメータをfalseに設定し、EXECUTION_TYPEをINDEX、MVIEWに設定します。

SQLACCESS_ADVISOR

SQLアクセス・アドバイザの正式名称を格納します。プロシージャでアドバイザ名を引数として指定する必要がある場合、この名前を指定できます。

第IX部 SQLの管理

この部では、SQLプロファイルおよびSQL計画ベースラインを管理する方法、およびストアド・アウトラインをSQL計画ベースラインに移行する方法について説明します。

次の章が含まれます。

- SQLプロファイルの管理

- SQL計画ベースラインの管理

- ストアド・アウトラインのSQL計画ベースラインへの移行

22 SQLプロファイルの管理

この章の内容は次のとおりです。

- SQLプロファイルについて

- SQLプロファイルの実装

- SQLプロファイルのリスト

- SQLプロファイルの変更

- SQLプロファイルの削除

- SQLプロファイルの転送

SQLプロファイルについて

SQLプロファイルは、SQL文に固有の補足統計を含むデータベース・オブジェクトです。

概念上、SQL文に対するSQLプロファイルの役割は、表または索引に対するオブジェクト・レベルの統計情報の役割と同じです。DBAによりSQLチューニング・アドバイザが起動されると、SQLプロファイルが作成されます。

この項の内容は次のとおりです。

- SQLプロファイルの目的

- SQLプロファイルの概念

- SQLプロファイルのユーザー・インタフェース

- SQLプロファイルの基本タスク

関連項目:

「SQLチューニング・アドバイザについて」

SQLプロファイルの目的

SQL文をプロファイルする場合、SQLチューニング・アドバイザは特定のバインド値のセットを入力として使用します。

アドバイザは、データ・サンプルの文のフラグメントの実行によって取得した値とオプティマイザの見積りを比較します。差異が大きいと検出された場合、SQLチューニング・アドバイザはSQLプロファイルに修正アクションをバンドルし、その受入れを推奨します。

SQLプロファイルで統計が修正されることにより、オプティマイザのカーディナリティの予測が改善され、より適切な計画を選択できるようになります。SQLプロファイルには、他の計画改善の方法より優れた次の利点があります。

- SQLプロファイルは、ヒントおよびストアド・アウトラインとは異なり、オプティマイザを特定の計画またはサブプランに結び付けません。SQLプロファイルは、不適切な見積りを修正し、それぞれの状況に合った最適な計画を選択する柔軟性をオプティマイザに提供します。

- SQLプロファイルを使用する場合は、ヒントとは異なり、アプリケーション・ソース・コードの変更は不要です。データベースによるSQLプロファイルの使用は、ユーザーに対して透過的です。

関連項目:

- 「ヒントによるオプティマイザへの影響」

- SQLチューニング・アドバイザを使用したSQLの分析

SQLプロファイルの概念

SQLプロファイルは問合せに関する補助統計のコレクションであり、問合せで参照される表および列のすべてが含まれます。プロファイルはデータ・ディクショナリに格納されます。オプティマイザは、最適化時にこの情報を使用して、最適な計画を特定します。

注意:

SQLプロファイルには、個々の計画ではなく、すべての文に対する補助統計が含まれます。プロファイル自体が特定の計画を判断することはありません。

SQLプロファイルには、統計の中でも特に、一連のカーディナリティの調整が含まれます。カーディナリティの測定は、統計予測ではなくWHERE句のサンプリングに基づきます。プロファイルは問合せの各部分を使用して、見積られたカーディナリティが実際のカーディナリティに近いかどうかを判断します。一致しない場合、修正されたカーディナリティを使用します。たとえば、SQLプロファイルがSELECT * FROM t WHERE x=5 AND y=10に対して存在すると、プロファイルには、実際に戻された行数が格納されます。

オプティマイザには、計画を選択する際に、次の情報ソースがあります。

- データベース構成、バインド変数値、オプティマイザ統計、データ・セットなどを含む環境。

- SQLプロファイルの補足的な統計情報。

図22-1に、SQL文とSQLプロファイルの関係を示します。オプティマイザは、SQLプロファイルと環境を使用して実行計画を生成します。この例では、文の計画は、SQL計画ベースラインにあります。

図22-1 SQLプロファイル

オプティマイザの環境またはSQLプロファイルが変化した場合、オプティマイザは新しい計画を作成できます。表が大きくなり、索引が作成または削除されると、SQLプロファイルの計画が変化する可能性があります。対応する文のデータ配分やアクセス・パスに変更があっても、プロファイルは引き続き関連付けられています。一般に、SQLプロファイルをリフレッシュする必要はありません。

長い間に、プロファイルの内容は古くなる可能性があります。この場合、SQL文のパフォーマンスが低下する場合があります。文は、負荷の高いSQLまたは上位SQLとして現れる場合があります。この場合、自動SQLチューニング・タスクが文を高負荷のSQLとして再び取得します。文の新しいSQLプロファイルを実装できます。

SQLプロファイルは、内部では、異なるタイプの問題を解決するヒントを使用して実装されます。これらのヒントは特定の計画を指定しません。ヒントは、最適ではない計画が生成される原因となる、オプティマイザの見積りアルゴリズムのエラーを修正します。たとえば、統計が欠落している場合や失効している場合、プロファイルは、TABLE_STATSヒントを使用して表にオブジェクト統計を設定します。

関連項目:

- 「SQL計画ベースラインとSQLプロファイルの違い」

- 「オプティマイザ統計の概要」

SQLプロファイルの推奨事項

「SQLプロファイリング」で説明したとおり、SQLチューニング・アドバイザは、自動チューニング・オプティマイザを起動してSQLプロファイルの推奨事項を生成します。SQLプロファイルを実装する推奨事項は、結果で生成され、SQLチューニング・アドバイザ・レポートの個別のセクションに表示されます。

SQLプロファイルを実装(または承諾)した場合、プロファイルが作成されてデータ・ディクショナリに永続的に保存されます。ただし、SQLプロファイルの情報は、通常のディクショナリ・ビューには表示されません。

関連項目:

- 自動DOPの詳細は、『Oracle Database VLDBおよびパーティショニング・ガイド』を参照してください。

- DBMS_SQLTUNE.ACCEPT_SQL_PROFILEプロシージャの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

例22-1 SQLプロファイルの推奨事項

この例では、コストの高いいくつかの結合を使用するSELECT文に対して、よりよい計画が検出されています。プロファイルを実装するDBMS_SQLTUNE.ACCEPT_SQL_PROFILEの実行が推奨されています。これにより、文の実行が98.53%高速化します。

-------------------------------------------------------------------------------
FINDINGS SECTION (2 findings)
-------------------------------------------------------------------------------

1- SQL Profile Finding (see explain plans section below)
--------------------------------------------------------
A potentially better execution plan was found for this statement. Choose
one of the following SQL profiles to implement.

Recommendation (estimated benefit: 99.45%)
------------------------------------------
- Consider accepting the recommended SQL profile.
execute dbms_sqltune.accept_sql_profile(task_name => 'my_task',
object_id => 3, task_owner => 'SH', replace => TRUE);

Validation results
------------------
The SQL profile was tested by executing both its plan and the original plan
and measuring their respective execution statistics. A plan may have been
only partially executed if the other could be run to completion in less time.

Original Plan  With SQL Profile  % Improved
-------------  ----------------  ----------
Completion Status:             PARTIAL          COMPLETE
Elapsed Time(us):            15467783            226902      98.53 %
CPU Time(us):                15336668            226965      98.52 %
User I/O Time(us):                  0                 0
Buffer Gets:                  3375243             18227      99.45 %
Disk Reads:                         0                 0
Direct Writes:                      0                 0
Rows Processed:                     0               109
Fetches:                            0               109
Executions:                         0                 1

Notes
-----
1. The SQL profile plan was first executed to warm the buffer cache.
2. Statistics for the SQL profile plan were averaged over next 3 executions.

SQLチューニング・アドバイザは、自動並列度(自動DOP)機能を使用するプロファイルの実装を推奨する場合もあります。パラレル問合せプロファイルは、元の計画がシリアルの場合で、パラレル実行により実行時間の長い問合せの経過時間を大幅に削減できる場合にのみ推奨されます。

SQLチューニング・アドバイザが自動DOPを使用するプロファイルを推奨する場合、SQL文にパラレル実行を使用した場合のパフォーマンスのオーバーヘッドの詳細がレポートで提供されます。パラレル実行の推奨では、SQLチューニング・アドバイザは、2つのSQLプロファイルの推奨(シリアル実行とパラレル実行に各1個)を提供する場合があります。

次の例は、パラレル問合せの推奨を示します。この例では、並列度が7の場合、レスポンス時間が大幅に改善されますが、リソースの消費がほぼ25%増加します。ユーザーは、データベース・スループットの削減がレスポンス時間の増加に値するかどうかを判断する必要があります。

Recommendation (estimated benefit: 99.99%)
------------------------------------------
- Consider accepting the recommended SQL profile to use parallel execution
for this statement.
execute dbms_sqltune.accept_sql_profile(task_name => 'gfk_task',
object_id => 3, task_owner => 'SH', replace => TRUE,
profile_type => DBMS_SQLTUNE.PX_PROFILE);

Executing this query parallel with DOP 7 will improve its response time
82.22% over the SQL profile plan. However, there is some cost in enabling
parallel execution. It will increase the statement's resource consumption by
an estimated 24.43% which may result in a reduction of system throughput.
Also, because these resources are consumed over a much smaller duration, the
response time of concurrent statements might be negatively impacted if
sufficient hardware capacity is not available.

The following data shows some sampled statistics for this SQL from the past
week and projected weekly values when parallel execution is enabled.

Past week sampled statistics for this SQL
-----------------------------------------
Number of executions                                                   0
Percent of total activity                                            .29
Percent of samples with #Active Sessions > 2*CPU                       0
Weekly DB time (in sec)                                            76.51

Projected statistics with Parallel Execution
--------------------------------------------
Weekly DB time (in sec)                                            95.21

SQLプロファイルおよびSQL計画ベースライン

SQLプロファイルは、SQL計画管理とともに使用することも、SQL計画管理なしで使用することもできます。SQLプロファイルと計画ベースラインの間に厳密な関係は存在しません。SQLプロファイルを使用することにより、オプティマイザはベースラインで最小コストの計画を選択できるため、SQL計画ベースラインに文の計画が複数存在する場合は、SQLプロファイルが役に立ちます。

関連項目:

SQL計画ベースラインの管理

SQLプロファイルのユーザー・インタフェース

Oracle Enterprise Manager Cloud Control (Cloud Control)は、通常、自動SQLチューニングの一部としてSQLプロファイルを処理します。

コマンドラインでは、DBMS_SQLTUNEパッケージを使用してSQLプロファイルを管理できます。APIを使用するには、ADMINISTER SQL MANAGEMENT OBJECT権限が必要です。

関連項目:

- DBMS_SQLTUNEパッケージについては、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

- Cloud Controlを使用してSQLプロファイルを管理する方法は、『Oracle Database 2日でパフォーマンス・チューニング・ガイド』を参照してください。

SQLプロファイルの基本タスク

基本タスクには、SQLプロファイルの承諾(実装)、変更、リストおよび削除が含まれます。

次の図は、基本ワークフローを示しています。

図22-2 SQLプロファイルの管理

通常、SQLプロファイルを管理する順序は次のとおりです。

1. 推奨されたSQLプロファイルを実装します。
このタスクについては、「SQLプロファイルの実装」を参照してください。

2. データベースに格納されているSQLプロファイルの情報を取得します。
このタスクについては、「SQLプロファイルのリスト」を参照してください。

3. オプションで、実装されたSQLプロファイルを変更できます。
このタスクについては、「SQLプロファイルの変更」を参照してください。

4. 実装されたSQLプロファイルが必要ない場合は、削除します。
このタスクについては、「SQLプロファイルの削除」を参照してください。

別のデータベースでSQL文をチューニングするには、別のデータベースにSQLチューニング・セットおよびSQLプロファイルを転送します。このタスクについては、「SQLプロファイルの転送」を参照してください。

関連項目:

DBMS_SQLTUNEパッケージの詳細は、Oracle Database PL/SQLパッケージ・プロシージャおよびタイプ・リファレンスを参照

SQLプロファイルの実装

SQLプロファイルを実装(または承諾)した場合、データベースに永続的に格納されます。計画の生成時、オプティマイザが入力として使用する前にプロファイルを実装する必要があります。

SQLプロファイルの実装について

通常では、SQLチューニング・アドバイザが推奨するSQLプロファイルを実装します。

索引およびSQLプロファイルが推奨されている場合は、両方とも使用するか、SQLプロファイルのみを使用します。索引を作成した場合、オプティマイザは、新しい索引を選択するためにプロファイルが必要になる場合があります。

場合によっては、SQLチューニング・アドバイザは、改善されたシリアル計画よりも、さらに良いパラレル計画を検出する場合もあります。この場合は、標準およびパラレルのSQLプロファイルが推奨され、文に対する最善のシリアル計画と最善のパラレル計画のいずれかを選択できます。パラレル計画は、レスポンス時間の増加がスループットの低下に値する場合にのみ実装します。

SQLプロファイルを実装するには、DBMS_SQLTUNE.ACCEPT_SQL_PROFILEプロシージャを実行します。重要なパラメータは次のとおりです。

- profile_type
パラレル実行を変更しないSQLプロファイルの場合はREGULAR_PROFILE、またはパラレル実行を変更するSQLプロファイルの場合はPX_PROFLEにこのパラメータを設定します。

- force_match
このパラメータは、文の一致を制御します。通常、SQLプロファイルを受け入れると、ハッシュ関数を使用して生成されるSQLシグネチャを通じてSQL文に関連付けられます。このハッシュ関数は、シグネチャを生成する前に、SQL文を大文字に変更し、余分な空白をすべて削除します。したがって、大/小文字および空白のみが異なるすべてのSQL文で同じSQLプロファイルを使用できます。

force_matchをtrueに設定した場合、WHERE句のリテラル値をバインド変数に置換した後、同じテキストを持つすべてのSQL文がSQLプロファイルの追加の対象となります。この設定により、テキストのリテラル値のみが異なるSQLでは、SQLプロファイルの共有が可能になります。そのため、この設定は、リテラル値のみを使用するアプリケーションで役に立ちます。SQLテキストにリテラル値とバインド変数の両方が使用されている場合、またはforce_matchパラメータがfalse(デフォルト値)に設定されている場合、WHERE句のリテラル値はバインド変数に置換されません。

関連項目:

ACCEPT_SQL_PROFILEプロシージャの詳細は、Oracle Database PL/SQLパッケージおよびタイプ・リファレンスを参照してください。

SQLプロファイルの実装

この項では、ACCEPT_SQL_PROFILEプロシージャを使用してSQLプロファイルを実装する方法を説明します。

前提条件

このチュートリアルでは、次のことが前提となっています。

- SQLチューニング・アドバイザ・タスクSTA_SPECIFIC_EMP_TASKには、SQLプロファイルを作成する推奨事項が含まれます。

- SQLプロファイルの名前は、my_sql_profileです。

- PL/SQLブロックは、パラレル実行を使用するプロファイルを受け入れます(profile_type)。

- プロファイルは強制一致を使用します。

SQLプロファイルを実装するには、次のようにします。

- 適切な権限でSQL*Plusをデータベースに接続して、ACCEPT_SQL_PROFILEファンクションを実行します。
たとえば、次のPL/SQLを実行します。

DECLARE
my_sqlprofile_name VARCHAR2(30);
BEGIN
my_sqlprofile_name := DBMS_SQLTUNE.ACCEPT_SQL_PROFILE (
task_name    => 'STA_SPECIFIC_EMP_TASK'
,   name         => 'my_sql_profile'
,   profile_type => DBMS_SQLTUNE.PX_PROFILE
,   force_match  => true
);
END;
/

関連項目:

DBMS_SQLTUNE.ACCEPT_SQL_PROFILEプロシージャの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

SQLプロファイルのリスト

データ・ディクショナリ・ビューDBA_SQL_PROFILESでは、データベースにSQLプロファイルを永続的に格納します。統計は、Oracle内部フォーマットであるため、プロファイルを直接問い合せることはできません。ただし、プロファイルをリストできます。

SQLプロファイルをリストするには、次のようにします。

- 適切な権限でSQL*Plusをデータベースに接続して、DBA_SQL_PROFILESビューを問い合せます。
たとえば、次の問合せを実行します。

COLUMN category FORMAT a10
COLUMN sql_text FORMAT a20

SELECT NAME, SQL_TEXT, CATEGORY, STATUS
FROM   DBA_SQL_PROFILES;

出力例は次のように表示されます。

NAME                           SQL_TEXT             CATEGORY   STATUS
------------------------------ -------------------- ---------- --------
SYS_SQLPROF_01285f6d18eb0000   select promo_name, c DEFAULT    ENABLED
ount(*) c from promo
tions p, sales s whe
re s.promo_id = p.pr
omo_id and p.promo_c
ategory = 'internet'
group by p.promo_na
me order by c desc

関連項目:

DBA_SQL_PROFILESビューの詳細は、『Oracle Databaseリファレンス』を参照してください。

SQLプロファイルの変更

ALTER_SQL_PROFILEプロシージャのattribute_nameパラメータを使用して、既存のSQLプロファイルの属性を変更できます。

CATEGORY属性により、プロファイルを適用できるユーザー・セッションが決まります。DBA_SQL_PROFILES.CATEGORYへの問合せによって、CATEGORY属性を参照します。デフォルトでは、すべてのプロファイルはDEFAULTカテゴリです。これは、SQLTUNE_CATEGORY初期化パラメータがDEFAULTに設定されたすべてのセッションがプロファイルを使用できることを意味します。

SQLプロファイルのカテゴリを変更することで、どのセッションが作成するプロファイルの影響を受けるかを確認します。たとえば、カテゴリをDEVに設定すると、SQLTUNE_CATEGORY初期化パラメータがDEVに設定されているセッションのみがプロファイルを使用できます。他のすべてのセッションは、SQLプロファイルにアクセスできないため、SQL文の実行計画がSQLプロファイルの影響を受けることはありません。この方法によって、限定的な環境でプロファイルをテストしてから、他のセッションで使用することができます。

この項の例では、SQLプロファイルのカテゴリがTESTに設定されているセッションでのみ使用されるようにSQLプロファイルのカテゴリを変更し、SQL文を実行して、プロファイルのカテゴリをDEFAULTに戻します。

SQLプロファイルを変更するには、次のようにします。

1. 適切な権限でSQL*Plusをデータベースに接続し、ALTER_SQL_PROFILEプロシージャを使用してattribute_nameを設定します。
たとえば、次のコードを実行し、CATEGORY属性をTESTに設定します。

VARIABLE pname my_sql_profile
BEGIN DBMS_SQLTUNE.ALTER_SQL_PROFILE (
name            =>  :pname
,  attribute_name  =>  'CATEGORY'
,  value           =>  'TEST'
);
END;

2. 現在のデータベース・セッションの初期化パラメータ設定を変更します。
たとえば、次のSQLを実行します。

ALTER SESSION SET SQLTUNE_CATEGORY = 'TEST';

3. プロファイルされたSQL文をテストします。

4. ALTER_SQL_PROFILEプロシージャを使用して、attribute_nameを設定します。
たとえば、次のコードを実行し、CATEGORY属性をDEFAULTに設定します。

VARIABLE pname my_sql_profile
BEGIN
DBMS_SQLTUNE.ALTER_SQL_PROFILE (
name            =>  :pname
,    attribute_name  =>  'CATEGORY'
,    value           =>  'DEFAULT'
);
END;

関連項目:

- SQLTUNE_CATEGORY初期化パラメータの詳細は、『Oracle Databaseリファレンス』を参照してください。

- ALTER_SQL_PROFILEプロシージャの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

SQLプロファイルの削除

DROP_SQL_PROFILEプロシージャを使用して、SQLプロファイルを削除できます。

前提条件

この項では、次のことが前提となっています。

- my_sql_profileを削除します。

- 名前が存在しない場合に発生するエラーを無視します。

SQLプロファイルを削除するには、次のようにします。

- 適切な権限でSQL*Plusをデータベースに接続して、DBMS_SQLTUNE.DROP_SQL_PROFILEプロシージャをコールします。
次の例では、my_sql_profileというプロファイルを削除します。

BEGIN
DBMS_SQLTUNE.DROP_SQL_PROFILE (
name => 'my_sql_profile'
);
END;
/

関連項目:

- DROP_SQL_PROFILEプロシージャの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

- SQLTUNE_CATEGORY初期化パラメータの詳細は、『Oracle Databaseリファレンス』を参照してください

SQLプロファイルの転送

SQLプロファイルをデータベースのSYSスキーマからステージング表にエクスポートした後、ステージング表から別のデータベースにインポートできます。SQLプロファイルは、同じリリースまたはそれ以降のリリースで作成された任意のOracleデータベースに転送できます。

表22-1に、SQLプロファイルを管理する主なプロシージャおよびファンクションを示します。

表22-1 SQLプロファイルの転送API

プロシージャまたはファンクション

説明

CREATE_STGTAB_SQLPROF

システム間でのSQLプロファイルのコピーに使用されるステージング表を作成します。

PACK_STGTAB_SQLPROF

プロファイル・データをSYSスキーマからステージング表に移動します。

UNPACK_STGTAB_SQLPROF

ステージング表に格納されたプロファイル・データを使用して、システムでプロファイルを作成します。

次の図に、SQLプロファイルの転送の基本ワークフローを示します。

図22-3 SQLプロファイルの転送

前提条件

このチュートリアルでは、次のことが前提となっています。

- my_profileを本番データベースからテスト・データベースに転送します。

- dba1スキーマにステージング表を作成します。

SQLプロファイルを転送するには、次のようにします。

1. 適切な権限でSQL*Plusをデータベースに接続し、CREATE_STGTAB_SQLPROFプロシージャを使用して、SQLプロファイルを保持するステージング表を作成します。
次の例では、dba1スキーマにmy_staging_tableを作成します。

BEGIN
DBMS_SQLTUNE.CREATE_STGTAB_SQLPROF (
table_name  => 'my_staging_table'
,   schema_name => 'dba1'
);
END;
/

2. PACK_STGTAB_SQLPROFプロシージャを使用して、SQLプロファイルをステージング表にエクスポートします。
次の例では、SQLプロファイルmy_profileをdba1.my_staging_tableに移入します。

BEGIN
DBMS_SQLTUNE.PACK_STGTAB_SQLPROF (
profile_name         => 'my_profile'
,   staging_table_name   => 'my_staging_table'
,   staging_schema_owner => 'dba1'
);
END;
/

3. SQLプロファイルの解凍先となるデータベースにステージング表を移動します。
適切なユーティリティを使用して表を移動します。たとえば、Oracle Data Pumpまたはデータベース・リンクを使用します。

4. SQLプロファイルのインポート先となるデータベースで、UNPACK_STGTAB_SQLPROFを使用してステージング表からSQLプロファイルを解凍します。
次の例は、ステージング表にあるSQLプロファイルを解凍する方法を示しています。

BEGIN
DBMS_SQLTUNE.UNPACK_STGTAB_SQLPROF(
replace            => true
,    staging_table_name => 'my_staging_table'
);
END;
/

関連項目:

- DBMS_SQLTUNEの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

- Oracle Data Pumpを使用する方法の詳細は、『Oracle Databaseユーティリティ』を参照してください。

23 SQL計画ベースラインの管理

SQL計画ベースラインは、DBMS_SPMパッケージを使用して管理できます。

この章の内容は次のとおりです。

- SQL計画管理について

- SQL計画管理の構成

- SQL計画ベースラインでの計画の表示

- SQL計画ベースラインのロード

- SQL計画ベースラインの手動での展開

- SQL計画ベースラインの削除

- SQL管理ベースの管理

関連項目:

"ストアド・アウトラインのSQL計画ベースラインへの移行"

SQL計画管理について

SQL計画管理は、データベースで既知の計画または確認済の計画のみが使用されるようにオプティマイザで実行計画を自動的に管理する予防的なメカニズムです。

SQL計画管理では、SQL計画ベースラインと呼ばれるメカニズムを使用します。計画ベースラインは、SQL文に対してオプティマイザで使用できる一連の承認済の計画です。通常のユースケースの場合、データベースで計画の正常な実行が検証された後のみ、計画が計画ベースラインに承認されます。このコンテキストで、計画には、オプティマイザで実行計画を再現するために必要な計画に関連するすべての情報(たとえば、SQL計画識別子、一連のヒント、バインド値、オプティマイザ環境など)が含まれます。

SQL計画管理の主要コンポーネントは次のとおりです。

- 計画の取得
このコンポーネントは、一連のSQL文に対する計画に関連する情報を保存します。「計画の取得」を参照してください。

- 計画の選択
このコンポーネントは、保存された計画履歴に基づいたオプティマイザによる計画変更の検出、およびパフォーマンスが低下する可能性を回避するための適切な計画の選択でのSQL計画ベースラインの使用です。「計画の選択」を参照してください。

- 計画の展開
このコンポーネントは、手動または自動での、既存のSQL計画ベースラインへの新規計画の追加プロセスです。「計画の展開」を参照してください。

この項の内容は次のとおりです。

- SQL計画管理の目的

- 計画の取得

- 計画の選択

- 計画の展開

- SQL計画管理の記憶域アーキテクチャ

- SQL計画管理のユーザー・インタフェース

- SQL計画管理の基本タスク

SQL計画管理の目的

SQL計画管理の主な目的は、計画の変更によって発生するパフォーマンスの低下を防ぐことです。2つ目の目的は、計画変更を検証し、パフォーマンスを改善させる計画変更のみを承認することにより、新しいオプティマイザ統計や索引などの変更にスムーズに適応することです。

注意:

SQL計画ベースラインでは、索引の削除などによる元に戻せない実行計画の変更を防止することはできません。

SQL計画管理の利点

SQL計画の管理により、データベース・アップグレードおよびシステムとデータの変更でSQLパフォーマンスを向上または維持できます。

特に、次の利点が得られます。

- 新しいバージョンのオプティマイザをインストールするデータベースのアップグレードでは、通常、ほんのわずかなSQL文に対して計画の変更が発生します。
ほとんどの計画変更において、パフォーマンスの向上が見られるか、または変化がありません。ただし、一部の計画の変更は、パフォーマンスの低下の原因となることがあります。SQL計画ベースラインにより、アップグレードがもたらす低下の可能性を最小限に抑えられます。

アップグレード時には、データベースにより計画ベースラインからの計画のみが使用されます。データベースは現在のベースラインに含まれない新しい計画を保持領域に入れ、後でそれらを評価し、ベースラインに含まれる現在の計画よりも少ないリソースを使用するかどうかを判断します。それらの計画のパフォーマンスがより優れている場合は、それらの計画をベースラインに昇格させます。そうでない場合は昇格させません。

- 継続的なシステムおよびデータの変更は、一部のSQL文の計画に影響を及ぼし、パフォーマンスの低下を招く可能性があります。
SQL計画ベースラインにより、パフォーマンスの低下を最小限に抑えて安定したSQLパフォーマンスを維持できます。

- 新しいアプリケーション・モジュールのデプロイメントは、新しいSQL文をデータベースに導入します。
アプリケーション・ソフトウェアは、新しい文に対して標準のテスト構成で作成された適切なSQL実行計画を使用できます。システム構成がテスト構成と大幅に異なる場合、データベースはSQL計画ベースラインを時間の経過とともに進化させてパフォーマンスを改善します。

関連項目:

Oracleデータベースのアップグレード方法については、『Oracle Databaseアップグレード・ガイド』を参照してください。

SQL計画ベースラインとSQLプロファイルの違い

SQLプロファイルとSQL計画ベースラインのどちらも、オプティマイザで最適な計画のみが使用されるようにすることによりSQL文のパフォーマンスを向上させます。

プロファイルとベースラインはどちらも、ヒントを使用して内部的に実装されます。ただし、これらのメカニズムは次のような点で大きく異なります。

- 一般的に、SQL計画ベースラインは事前対応型であるのに対し、SQLプロファイルは事後対応型です。
通常、SQL計画ベースラインは重大なパフォーマンスの問題が発生する前に作成します。SQL計画ベースラインは、オプティマイザが最適ではない計画を将来的に使用することを防ぎます。

SQLプロファイルは、SQLチューニング・アドバイザを起動するとデータベースにより作成されます。通常、チューニング・アドバイザは、SQL文により高負荷の兆候が示された後にのみ起動します。SQLプロファイルは主に、最適ではない計画につながったオプティマイザのミスを継続的に解決するために使用できます。SQLプロファイル・メカニズムは事後対応であるため、データベースに重大な変更が生じた場合は安定したパフォーマンスを保証できません。

図23-1 SQL計画ベースラインとSQLプロファイル

- SQL計画ベースラインは特定の計画を再現するのに対し、SQLプロファイルはオプティマイザのコスト見積りを修正します。
SQL計画ベースラインは一連の承認済計画から構成されます。各計画は、特定の計画を完全に指定するアウトライン・ヒントのセットを使用して実装されます。SQLプロファイルもヒントを使用して実装されますが、これらのヒントでは特定の計画は指定されません。これらのヒントは、最適ではない計画につながったオプティマイザの見積りの計算ミスを修正します。たとえば、ヒントにより表のカーディナリティ予測が修正されます。

プロファイルによりオプティマイザは特定の1つの計画に制限されないため、SQLプロファイルはSQL計画ベースラインよりも柔軟です。たとえば、初期化パラメータやオプティマイザ統計を変更することで、オプティマイザはより最適な計画を選択できます。

SQLチューニング・アドバイザを使用することをお薦めします。これにより、SQLプロファイルと計画ベースラインのどちらが各SQL文に最適なメカニズムであるのかを自分で判断せずに、アドバイザの推奨事項に従うことができます。

関連項目:

- 「オプティマイザ・ヒントについて」

- 「SQLプロファイルの管理」

- SQLチューニング・アドバイザを使用したSQLの分析

計画の取得

SQL計画の取得とは、一連のSQL文に対して、計画に関連する情報を取得し、SQL管理ベースに保存するための方法を指します。計画の取得とは、SQL計画管理にこの計画を認識させることを意味します。

初期化パラメータを設定することにより初期計画の取得が自動的に発生するように構成するか、DBMS_SPMパッケージを使用して計画を手動で取得できます。

初期計画の自動取得

OPTIMIZER_CAPTURE_SQL_PLAN_BASELINES初期化パラメータをtrueに設定することで(デフォルトはfalse)、初期計画の自動取得を有効にします。有効時には、データベースで実行される繰返し可能なSQL文のSQL計画ベースラインが自動的に作成されます。

OPTIMIZER_CAPTURE_SQL_PLAN_BASELINESとOPTIMIZER_USE_SQL_PLAN_BASELINESの設定は独立しています。たとえば、OPTIMIZER_CAPTURE_SQL_PLAN_BASELINESがtrueの場合、OPTIMIZER_USE_SQL_PLAN_BASELINESの設定がtrueとfalseのいずれでも、初期計画ベースラインが作成されます。

関連項目:

OPTIMIZER_USE_SQL_PLAN_BASELINES初期化パラメータの詳細は、『Oracle Databaseリファレンス』を参照してください

計画の手動取得

SQL計画管理では、計画の手動取得とは、ユーザーによるSQL計画ベースラインへの既存計画の一括ロードを指します。

SQL文に対する実行計画をSQLチューニング・セット(STS)、共有SQL領域、ステージング表またはストアド・アウトラインからロードするには、Cloud ControlまたはPL/SQLを使用します。

次の図は、SQL計画ベースラインへの計画のロードを示しています。

図23-2 SQL計画ベースラインへの計画のロード

ロード動作は、一括ロードに含まれる各文に対してSQL計画ベースラインが存在するかどうかによって異なります。

- 文に対するベースラインが存在しない場合、データベースは次の処理を行います。

1. 文に対する計画履歴と計画ベースラインを作成します。

2. 文に対する最初の計画を承認済とマークします。

3. 計画を新しいベースラインに追加します。

- 文に対するベースラインが存在する場合、データベースは次の処理を行います。

1. ロードした計画を承認済とマークします。

2. 計画のパフォーマンスを検証せずに、計画を文に対する計画ベースラインに追加します。

オプティマイザは管理者により手動でロードされた計画のパフォーマンスは許容範囲にあると見なすため、手動でロードされた計画は常に承認済とマークされます。

関連項目:

DBMS_SPM.LOAD_PLANS_FROM_%ファンクションの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

計画の選択

SQL 計画の選択とは、保存された計画履歴に基づいて計画変更を検出するオプティマイザの機能、およびパフォーマンスが低下する可能性を回避するために適切な計画を選択するSQL計画ベースラインの使用を指します。

データベースがSQL文のハード解析を実行すると、オプティマイザは最適なコスト計画を生成します。デフォルトでは、オプティマイザは次に、文に対するSQL計画ベースライン内で一致する計画を探します。計画ベースラインが存在しない場合は、データベースは最適なコスト計画を使用して文を実行します。

計画ベースラインが存在する場合は、オプティマイザの動作は、新たに生成された計画が計画ベースラインに含まれるかどうかによって決まります。

- 新しい計画がベースラインに含まれる場合、データベースは検出した計画を使用して文を実行します。

- 新しい計画がベースラインに含まれない場合、オプティマイザは新たに生成された計画を未承認とマークし、計画履歴に追加します。オプティマイザの動作は、計画ベースラインの内容によって決まります。

- 計画ベースラインに固定計画が含まれる場合、オプティマイザはコストが最も低い固定計画を使用します。

- 計画ベースラインに固定計画が含まれない場合、オプティマイザはコストが最も低いベースライン計画を使用します。

- 計画ベースライン内に再現可能な計画が含まれない場合(これはベースライン内のすべての計画が削除された索引を参照している場合に発生します)、オプティマイザは新たに生成されたコストベースの計画を使用します。

図23-3 SQL計画選択のデシジョン・ツリー

関連項目:

"固定計画"

計画の展開

一般的に、SQL計画の展開は、オプティマイザが新しい計画を検証して既存のSQL計画ベースラインに追加するためのプロセスです。

具体的には、計画の展開は次の個別のステップで構成されます。

1. 承認されていない計画がSQL計画ベースラインに含まれる承認済の計画と少なくとも同じパフォーマンスであることを検証します(計画の検証と呼ばれます)。

2. データベースにより承認済の計画と同じパフォーマンスであることが証明された場合、承認されていない計画を承認済の計画として計画ベースラインに追加します。

計画の展開の標準的なケースでは、オプティマイザは前述の手順を順番に実行します。したがって、オプティマイザがSQL計画ベースラインと比較して計画のパフォーマンスを検証するまで、SQL計画管理で新しい計画は使用できません。ただし、 一方の手順を実行せずにもう一方の手順を実行するようにSQL計画管理を構成できます。次の図は、計画の展開で使用可能なパスを示しています。

図23-4 計画の展開

計画の展開の目的

通常、SQL文のSQL計画ベースラインは、単一の承認済の計画から開始します。ただし、様々な条件の異なる計画とともに実行されると、SQL文の実行が良くなる場合があります。

たとえば、値が異なる選択性になるバインド変数を使用したSQL文は、いくつかの最適な計画を持つ場合があります。マテリアライズド・ビューまたは索引の作成あるいは表の再パーティション化により、現在の計画が他の計画よりコストが高くなる場合があります。

新しい計画がSQL計画ベースラインに一度も追加されなかった場合、一部のSQL文のパフォーマンスが低下する可能性があります。したがって、新しい承認済の計画をSQL計画ベースラインに展開する必要がある場合があります。計画の展開は、SQL計画ベースラインに含める前に新しい計画のパフォーマンスを検証して、パフォーマンスの低下を防止します。

計画の展開用のPL/SQLサブプログラム

DBMS_SPMパッケージは、計画の展開で使用できるプロシージャとファンクションを提供します。

これらのサブプログラムはタスク・インフラストラクチャを使用します。たとえば、CREATE_EVOLVE_TASKは展開タスクを作成し、EXECUTE_EVOLVE_TASKはそれを実行します。すべてのタスク展開サブプログラムの名前には、文字列EVOLVE_TASKが含まれます。

展開プロシージャを必要に応じて使用するか、サブプログラムが自動的に実行されるように構成します。自動メンテナンス・タスクSYS_AUTO_SPM_EVOLVE_TASKは、スケジュールされているメンテナンス・ウィンドウで毎日実行されます。このタスクにより次の処理が自動的に実行されます。

1. 承認されていない計画を選択し、検証用にランク付けします。

2. パフォーマンスしきい値を満たしていれば、各計画を承認します。

関連項目:

- 「SPM展開アドバイザのタスクの管理」

- 「SQL計画ベースラインの手動での展開」

- DBMS_SPMパッケージの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

SQL計画管理の記憶域アーキテクチャ

SQL計画管理インフラストラクチャでは、解析された文のシグネチャおよび承認済の計画と未承認の計画の両方が記録されます。

この項の内容は次のとおりです。

- SQL管理ベース

- SQL文のログ

- SQL計画履歴

SQL管理ベース

SQL管理ベース(SMB)は、データ・ディクショナリ内の論理リポジトリです。

SMBには、次のものが含まれます。

- SQL文のログ(SQL IDのみを含む)

- SQL計画履歴(SQL計画ベースラインを含む)

- SQLプロファイル

- SQLパッチ

SMBには、SQLパフォーマンスの維持または向上のためにオプティマイザで使用できる情報が保存されます。

SMBはSYSAUX表領域内にあり、自動セグメント領域管理を使用します。SMB全体がSYSAUX表領域内に存在するため、この表領域が使用可能でない場合、データベースはSQL計画管理およびSQLチューニング機能を使用しません。

図23-5 SMBのアーキテクチャ

注意:

SMBをプラガブル・データベースとともに使用すると、データの可視性と権限の要件が一致しない場合があります。コンテナ・データベース(CDB)内での管理機能の動作をまとめた表が記載されている『Oracle Database管理者ガイド』を参照してください。

関連項目:

SYSAUX表領域の詳細は、『Oracle Database管理者ガイド』を参照してください。

SQL文のログ

SQL計画の自動取得が有効になっている場合、SQL文のログには、オプティマイザがこれまでに評価してきた文のシグネチャが含まれます。

SQLシグネチャは、大/小文字および空白が正規化されているSQL文のテキストを使用して計算されたハッシュ値です。オプティマイザは文を解析する際、シグネチャを作成します。

自動取得中、データベースはこのシグネチャをSQL文のログ(SQLLOG$)に照らして照合し、シグネチャが以前に検出されているかどうかを判別します。検出されていない場合、データベースはシグネチャをログに追加します。シグネチャがすでにログに存在する場合、データベースは文が繰返し可能なSQL文であることを確認します。

注意:

フィルタによって文が除外された場合は、そのシグネチャもログから除外されます。

例23-1 SQL文のロギング

この例は、データベースがどのように文のログ内で文を追跡し、繰返し可能な文に対して自動的にベースラインを作成するかを示しています。文のログの最初の問合せでは、追跡されたSQL文は1つもないことが示されます。AD_PRESに対するhr.jobsの問合せ後、ログには文が1つ追跡されていることが示されます。

SQL> ALTER SYSTEM SET OPTIMIZER_CAPTURE_SQL_PLAN_BASELINES=true;

System altered.

SQL> SELECT * FROM SQLLOG$;

no rows selected

SQL> SELECT job_title FROM hr.jobs WHERE job_id = 'AD_PRES';

JOB_TITLE
-----------------------------------
President

SQL> SELECT * FROM SQLLOG$;

SIGNATURE     BATCH#
---------- ----------
1.8096E+19          1

次に、セッションは別のjobs問合せを実行します。ログには2つの文が追跡されていることが示されます。

SQL> SELECT job_title FROM hr.jobs WHERE job_id='PR_REP';

JOB_TITLE
-----------------------------------
Public Relations Representative

SQL> SELECT * FROM SQLLOG$;

SIGNATURE     BATCH#
---------- ----------
1.7971E+19          1
1.8096E+19          1

DBA_SQL_PLAN_BASELINESの問合せでは、どちらの文に対してもベースラインが存在しないことが示されます。これは、どちらの文も繰返し可能ではないためです。

SQL> SELECT SQL_HANDLE, SQL_TEXT
2  FROM DBA_SQL_PLAN_BASELINES
3  WHERE SQL_TEXT LIKE 'SELECT job_title%';

no rows selected

セッションがjob_id='PR_REP'に対する問合せを再度実行します。これでこの文は繰返し可能になり、またSQL計画の自動取得が有効になっているため、データベースによりこの文に対する計画ベースラインが作成されます。job_id='AD_PRES'に対する問合せは一度しか実行されていないため、これに対する計画ベースラインは存在しません。

SQL> SELECT job_title FROM hr.jobs WHERE job_id='PR_REP';

JOB_TITLE
-----------------------------------
Public Relations Representative

SQL> SELECT SQL_HANDLE, SQL_TEXT
2  FROM DBA_SQL_PLAN_BASELINES
3  WHERE SQL_TEXT LIKE 'SELECT job_title%';

SQL_HANDLE           SQL_TEXT
-------------------- --------------------
SQL_f9676a330f972dd5 SELECT job_title FRO
M hr.jobs WHERE job_
id='PR_REP'

関連項目:

- 「初期計画の自動取得」

- DBA_SQL_PLAN_BASELINESの詳細は、『Oracle Databaseリファレンス』を参照してください。

SQL計画履歴

SQL計画履歴は、取得された一連のSQL実行計画です。この履歴には、SQL計画ベースラインおよび未承認の計画が含まれます。

SQL計画管理では、データベースが既存のSQL計画ベースラインの新しいSQL実行計画を検出し、展開(検証)できるように新しい計画を履歴に記録します。展開はデータベースによって自動的に開始されるか、DBAが手動で開始します。

Oracle Database 12c以降、すべてのSQL文の実行計画はSMBによりSQL計画履歴に保存されます。DBMS_XPLAN.DISPLAY_SQL_PLAN_BASELINEファンクションは、SMBから計画をフェッチして表示します。Oracle Database 12cより前に作成された計画については、SMBに保存されていないため、ファンクションはSQL文をコンパイルして計画を生成する必要があります。

関連項目:

- 「SQL計画ベースラインでの計画の表示」

- DBMS_XPLAN.DISPLAY_SQL_PLAN_BASELINEファンクションの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

有効化された計画

有効な計画は、オプティマイザの使用対象となります。

enabledパラメータをYES (デフォルト)に設定して計画をロードした場合、データベースは結果のSQL計画ベースラインを、承認されていない場合でも、自動的に有効とマークします。有効な計画を手動で無効な計画に変更できます。この場合、計画が承認済でもオプティマイザはその計画を使用できなくなります。

承認済の計画

承認済の計画は、SQL文のSQL計画ベースラインに存在し、オプティマイザで使用できる計画です。承認済の計画には、ヒント・セット、計画のハッシュ値、計画に関連するその他の情報が含まれます。

SQL文に対する計画履歴には、すべての計画(承認済と未承認の両方の計画)が含まれます。オプティマイザが計画ベースライン内に最初の承認済の計画を生成すると、それ以降のすべての承認されていない計画は計画履歴に追加され、検証を待ちますが、SQL計画ベースラインには追加されません。

固定計画

固定計画は、優先としてマークされた承認済の計画です。これにより、オプティマイザはベースライン内の固定計画のみを考慮するようになります。固定計画は、オプティマイザの計画選択プロセスに影響します。

ある文に対するSQL計画ベースラインに3つの計画が存在するとします。オプティマイザに、その内の2つの計画のみを優先させたいとします。次の図に示すように、この2つの計画を固定とマークすることにより、オプティマイザがこれらの計画からの最適な計画のみを使用し、残りの計画は無視するようにします。

図23-6 固定計画

1つ以上の有効な固定計画を含むベースラインに新しい計画を追加した場合、それらの計画を手動で固定と宣言しないかぎり、オプティマイザはそれらの計画を使用することはできません。

SQL計画管理のユーザー・インタフェース

DBMS_SPMパッケージには、Cloud Controlまたはコマンドラインを通してアクセスします。

Cloud Controlでの「SQL計画ベースライン」ページへのアクセス

Cloud Controlの「SQL計画管理」ページは、SQLプロファイル、SQLパッチおよびSQL計画ベースラインに関する情報を示すGUIです。

「SQL計画ベースライン」ページにアクセスする手順は次のとおりです。

1. 適切な資格証明を使用してCloud Controlにログインします。

2. 「ターゲット」メニューの下で、「データベース」を選択します。

3. データベース・ターゲットのリストで、管理対象のOracle Databaseインスタンスのターゲットを選択します。

4. データベースの資格証明の入力を求められた場合は、実行するタスクに必要な最小限の資格証明を入力します。

5. 「パフォーマンス」メニューから、「SQL」、「SQL計画管理」の順に選択します。
「SQL計画管理」ページが表示されます。

6. 「ファイル」をクリックして、図23-7に示す「SQL計画ベースライン」ページを表示します。

図23-7 「SQL計画ベースライン」サブページ

ほとんどのSQL計画管理タスクは、このページ、またはこのページからアクセスするページで実行できます。

関連項目:

- 「SQL計画ベースライン」サブページのオプションの詳細は、Cloud Control状況依存オンライン・ヘルプを参照してください。

- 「SPM展開アドバイザのタスクの管理」

DBMS_SPMパッケージ

コマンドラインでは、DBMS_SPMおよびDBMS_XPLAN PL/SQLパッケージを使用して、ほとんどのSQL計画管理タスクを実行します。

次の表に、SQL計画ベースラインを作成、削除およびロードするための主なDBMS_SPMプロシージャとファンクションを示します。

表23-1 DBMS_SPMプロシージャとファンクション

パッケージ

プロシージャまたはファンクション

説明

DBMS_SPM

CONFIGURE

このプロシージャは、名前/値の形式でSMBに対する構成オプションを変更します。

DBMS_SPM

CREATE_STGTAB_BASELINE

このプロシージャは、SQL計画ベースラインを1つのデータベースから別のデータベースへと移植することを可能にするステージング表を作成します。

DBMS_SPM

DROP_SQL_PLAN_BASELINE

このファンクションは、計画ベースライン内の一部またはすべての計画を削除します。

DBMS_SPM

LOAD_PLANS_FROM_CURSOR_CACHE

このファンクションは、共有SQL領域(カーソル・キャッシュとも呼ばれます)内の計画をSQL計画ベースラインにロードします。

DBMS_SPM

LOAD_PLANS_FROM_SQLSET

このファンクションは、STSに保存されている計画をSQL計画ベースラインにロードします。

DBMS_SPM

PACK_STGTAB_BASELINE

このファンクションは、SQL計画ベースラインをパックします。つまり、SMBからステージング表にコピーします。

DBMS_SPM

UNPACK_STGTAB_BASELINE

このファンクションは、SQL計画ベースラインをアンパックします。つまり、SQL計画ベースラインをステージング表からSMBにコピーします。

DBMS_XPLAN

DISPLAY_SQL_PLAN_BASELINE

このファンクションは、SQLハンドルによって識別されるSQL文の1つ以上の実行計画を表示します。

関連項目:

- SQL計画の展開に関連するファンクションの詳細は、「DBMS_SPM展開ファンクションについて」を参照してください。

- DBMS_SPMパッケージの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

SQL計画管理の基本タスク

この項では、計画のパフォーマンスの低下を防ぎ、オプティマイザによる新しい計画の検討を可能にするためにSQL計画管理を使用する際の基本的なタスクについて説明します。

タスクは次のとおりです。

- データベースがSQL計画ベースラインを取得して使用するかどうか、また新しい計画を展開するかどうかを制御する初期化パラメータを設定する。
「SQL計画管理の構成」を参照してください。

- SQL計画ベースラインに計画を表示する。
「SQL計画ベースラインでの計画の表示」を参照してください。

- 計画をSQL計画ベースラインに手動でロードする。
SQLチューニング・セット、共有SQL領域、ステージング表またはストアド・アウトラインから計画をロードします。

「SQL計画ベースラインのロード」を参照してください。

- 計画をSQL計画ベースラインに手動で展開する。
PL/SQLを使用して、指定した計画のパフォーマンスを検証し、計画ベースラインに追加します。

「SQL計画ベースラインの手動での展開」を参照してください。

- SQL計画ベースライン内の一部またはすべての計画を削除する。
「SQL計画ベースラインの削除」を参照してください。

- SMBを管理する。
ディスク領域制限および計画保存ポリシーの期間を変更します。

「SQL管理ベースの管理」を参照してください。

- ストアド・アウトラインをSQL計画ベースラインに移行する。
「ストアド・アウトラインのSQL計画ベースラインへの移行」を参照してください。

SQL計画管理の構成

この項の内容は次のとおりです。

- SQL計画ベースラインの取得と使用の構成

- SPM展開アドバイザのタスクの管理

SQL計画ベースラインの取得と使用の構成

SQL計画管理は初期化パラメータを使用して制御します。

デフォルト値は次のとおりです。

- OPTIMIZER_CAPTURE_SQL_PLAN_BASELINES=false
計画履歴に存在しない繰返し可能なSQL文の場合、その文に対する初期SQL計画ベースラインは自動的に作成されません。

- OPTIMIZER_USE_SQL_PLAN_BASELINES=true
既存のSQL計画ベースラインがあるSQL文の場合、新しい計画が未承認の計画としてSQL計画ベースラインに自動的に追加されます。

注意:

前述のパラメータの設定は、互いに独立しています。たとえば、OPTIMIZER_CAPTURE_SQL_PLAN_BASELINESがtrueの場合、OPTIMIZER_USE_SQL_PLAN_BASELINESがfalseでも、新しい文に対して初期計画ベースラインが作成されます。

デフォルト動作が希望の動作であれば、この項はスキップしてください。

次の各項では、コマンドラインからデフォルトのパラメータ設定を変更する方法について説明します。Cloud Controlを使用している場合は、これらのパラメータは「SQL計画ベースライン」サブページで設定します。

関連項目:

- 「初期計画の自動取得」

- 「計画の選択」

- 図23-7

SQL計画管理での初期計画自動取得の有効化

計画履歴に存在しないSQL文に初期SQL計画ベースラインを自動的に作成するために必要な手順は、OPTIMIZER_CAPTURE_SQL_PLAN_BASELINES初期化パラメータをtrueに設定するのみです。このパラメータは、前に作成されたSQL計画ベースラインへの新しく検出された計画の自動的な追加を制御しません。

SQL計画管理に対して初期計画の自動取得を有効にする手順は次のとおりです。

注意:

自動ベースライン取得が有効になっていると、データベースはすべての再帰的SQLおよび監視SQLを含む、すべての繰返し可能な文に対してSQL計画ベースラインを作成します。したがって、自動取得により、非常に多くの計画ベースラインが作成される可能性があります。

1. SQL*Plusを起動し、必要な権限でデータベースにログインします。

2. SQL計画管理の現在の設定を表示します。
たとえば、管理者権限でSQL*Plusをデータベースに接続し、次のコマンドを実行します(出力例も示します)。

SQL> SHOW PARAMETER SQL_PLAN

NAME                                 TYPE        VALUE
------------------------------------ ----------- -----
optimizer_capture_sql_plan_baselines boolean     FALSE
optimizer_use_sql_plan_baselines     boolean     TRUE

パラメータが希望どおりに設定されていれば、残りの手順はスキップしてください。

3. 繰返し可能なSQL文の自動認識およびこれらの文に対するSQL計画ベースラインの生成を有効にするには、次の文を入力します。

SQL> ALTER SYSTEM SET OPTIMIZER_CAPTURE_SQL_PLAN_BASELINES=true;

すべてのSQL計画ベースラインの無効化

OPTIMIZER_USE_SQL_PLAN_BASELINES初期化パラメータをfalseに設定すると、データベースはデータベース内のいずれの計画ベースラインも使用しません。

通常は、1つまたは2つの計画ベースラインを無効化しますが、すべては無効化しません。可能なユースケースとしては、SQL計画管理の利点のテストがあげられます。

データベース内のすべてのSQL計画ベースラインを無効化する手順は次のとおりです。

1. SQL*Plusを適切な権限でデータベースに接続し、SQL計画管理に対する現在の設定を表示します。
たとえば、管理者権限でSQL*Plusをデータベースに接続し、次のコマンドを実行します(出力例も示します)。

SQL> SHOW PARAMETER SQL_PLAN

NAME                                 TYPE        VALUE
------------------------------------ ----------- -----
optimizer_capture_sql_plan_baselines boolean     FALSE
optimizer_use_sql_plan_baselines     boolean     TRUE

パラメータが希望どおりに設定されていれば、残りの手順はスキップしてください。

2. すべての既存の計画ベースラインを無視するには、次の文を入力します。

SQL> ALTER SYSTEM SET OPTIMIZER_USE_SQL_PLAN_BASELINES=false

関連項目:

SQL計画ベースライン初期化パラメータの詳細は、『Oracle Databaseリファレンス』を参照してください。

SPM展開アドバイザのタスクの管理

SPM展開アドバイザは、SQL計画ベースラインに最近追加された計画を展開するSQLアドバイザです。アドバイザを使用することにより手動で実行する必要がなくなるため、計画の展開が容易になります。

SPM展開アドバイザのタスクの有効化と無効化

SPM展開アドバイザの自動タスクに対する個別のスケジューラ・クライアントは存在しません。

1つのクライアントが、自動SQLチューニング・アドバイザと自動SPM展開アドバイザの両方を制御します。したがって、同じタスクにより両方のアドバイザが有効化または無効化されます。

関連項目:

自動SPM展開アドバイザの有効化および無効化方法については、「自動SQLチューニング・タスクの有効化と無効化」を参照してください

SPM展開アドバイザの自動タスクの構成

DBMS_SPMパッケージでは、SET_EVOLVE_TASK_PARAMETERプロシージャを使用してタスク・パラメータを指定することにより、計画の自動展開を構成できます。タスクはSYSが所有しているため、SYSのみがタスク・パラメータを設定できます。

ACCEPT_PLANSチューニング・タスク・パラメータは、推奨された計画を自動的に承認するかどうかを指定します。ACCEPT_PLANSがtrueに設定されている場合(デフォルト)、SQL計画管理はタスクにより推奨されたすべての計画を自動的に承認します。falseに設定されている場合は、タスクは計画を検証し、検証結果についてのレポートを生成しますが、計画の展開は行いません。

前提条件

この項のチュートリアルでは、次のことが前提となっています。

- データベースにより自動的に計画を展開しない。

- 実行ごとに1200秒経過したら、タスクをタイムアウトする。

自動展開タスクのパラメータを設定する手順は次のとおりです。

1. SQL*Plusを適切な権限でデータベースに接続し、オプションで現在のタスク設定を問い合せます。
たとえば、管理者権限でSQL*Plusをデータベースに接続し、次の問合せを実行します。

COL PARAMETER_NAME FORMAT a25
COL VALUE FORMAT a10
SELECT PARAMETER_NAME, PARAMETER_VALUE AS "VALUE"
FROM   DBA_ADVISOR_PARAMETERS
WHERE  ( (TASK_NAME = 'SYS_AUTO_SPM_EVOLVE_TASK') AND
( (PARAMETER_NAME = 'ACCEPT_PLANS') OR
(PARAMETER_NAME = 'TIME_LIMIT') ) );

出力例は次のように表示されます。

PARAMETER_NAME            VALUE
------------------------- ----------
ACCEPT_PLANS              TRUE
TIME_LIMIT                3600

2. 次の形式のPL/SQLコードを使用してパラメータを設定します。

BEGIN
DBMS_SPM.SET_EVOLVE_TASK_PARAMETER(
task_name => 'SYS_AUTO_SPM_EVOLVE_TASK'
,   parameter => parameter_name
,   value     => value
);
END;
/

たとえば、次のPL/SQLブロックは時間制限を20分に設定し、計画を自動的に承認します。

BEGIN
DBMS_SPM.SET_EVOLVE_TASK_PARAMETER(
task_name => 'SYS_AUTO_SPM_EVOLVE_TASK'
,   parameter => 'LOCAL_TIME_LIMIT'
,   value     => 1200
);
DBMS_SPM.SET_EVOLVE_TASK_PARAMETER(
task_name => 'SYS_AUTO_SPM_EVOLVE_TASK'
,   parameter => 'ACCEPT_PLANS'
,   value     => 'true'
);
END;
/

関連項目:

DBMS_SPMパッケージの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください

SQL計画ベースラインでの計画の表示

特定の文についてSQL計画ベースラインに保存された計画を表示するには、DBMS_XPLAN.DISPLAY_SQL_PLAN_BASELINEファンクションを使用します。このファンクションは、計画履歴に保存された計画の情報を使用して計画を表示します。

次の表は、DBMS_XPLAN.DISPLAY_SQL_PLAN_BASELINEファンクションの関連するパラメータを示しています。

表23-2 DBMS_XPLAN.DISPLAY_SQL_PLAN_BASELINEパラメータ

ファンクション・パラメータ

説明

sql_handle

文のSQLハンドル。PLAN_NAME列でV$SQL.SQL_PLAN_BASELINEとDBA_SQL_PLAN_BASELINESビューを結合することにより、SQLハンドルを取得します。

plan_name

文に対する計画の名前。

この項では、コマンドラインからベースライン内の計画を表示する方法について説明します。Cloud Controlを使用する場合は、「SQL計画ベースライン」サブページ(図23-7を参照)から計画ベースラインを表示します。

SQL計画ベースラインに計画を表示するには、次の手順を実行します。

1. SQL*Plusを適切な権限でデータベースに接続し、計画を表示する問合せのSQL IDを取得します。
たとえば、SQL IDが31d96zzzpcys9のSELECT文に対するSQL計画ベースラインが存在するとします。

2. SQL IDを使用して計画を問い合せます。
次の問合せは、SQL IDが31d96zzzpcys9の文に対する実行計画を表示します。

SELECT PLAN_TABLE_OUTPUT
FROM   V$SQL s, DBA_SQL_PLAN_BASELINES b,
TABLE(
DBMS_XPLAN.DISPLAY_SQL_PLAN_BASELINE(b.sql_handle,b.plan_name,'basic')
) t
WHERE  s.EXACT_MATCHING_SIGNATURE=b.SIGNATURE
AND    b.PLAN_NAME=s.SQL_PLAN_BASELINE
AND    s.SQL_ID='31d96zzzpcys9';

この問合せ例の結果は次のようになります。

PLAN_TABLE_OUTPUT
---------------------------------------------------------------------------

---------------------------------------------------------------------------
SQL handle: SQL_513f7f8a91177b1a
SQL text: select * from hr.employees where employee_id=100
---------------------------------------------------------------------------

---------------------------------------------------------------------------
Plan name: SQL_PLAN_52gvzja8jfysuc0e983c6         Plan id: 3236529094
Enabled: YES     Fixed: NO      Accepted: YES     Origin: AUTO-CAPTURE
---------------------------------------------------------------------------

Plan hash value: 3236529094

-----------------------------------------------------
| Id  | Operation                   | Name          |
-----------------------------------------------------
|   0 | SELECT STATEMENT            |               |
|   1 |  TABLE ACCESS BY INDEX ROWID| EMPLOYEES     |
|   2 |   INDEX UNIQUE SCAN         | EMP_EMP_ID_PK |
-----------------------------------------------------

結果は、SQL ID 31d96zzzpcysに対する計画の名前はSQL_PLAN_52gvzja8jfysuc0e983c6であり、自動的に取得されたことを示しています。

関連項目:

- 「SQL管理ベース」

- DISPLAY_SQL_PLAN_BASELINEファンクションで使用する追加のパラメータの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください

SQL計画ベースラインのロード

DBMS_SPMを使用すると、SQL計画ベースラインへの既存計画セットの一括ロードを開始できます。

この項の内容は次のとおりです。

- SQLチューニング・セットからの計画のロード

- 共有SQL領域からの計画のロード

- ステージング表からの計画のロード

SQLチューニング・セットからの計画のロード

SQLチューニング・セットは、1つ以上のSQL文、実行統計および実行コンテキストを含むデータベース・オブジェクトです。このトピックでは、STSから計画をロードする方法について説明します。

計画は、DBMS_SPM.LOAD_PLANS_FROM_SQLSETファンクションまたはCloud Controlを使用してロードできます。次の表では、ファンクション・パラメータの一部を説明します。

表23-3 LOAD_PLANS_FROM_SQLSETのパラメータ

ファンクション・パラメータ

説明

sqlset_name

そこからSQL計画ベースラインに計画をロードするSTSの名前。

basic_filter

条件を満たす計画のみをロード対象として選択するためにSTSに適用されるフィルタ。このフィルタは、DBA_SQLSET_STATEMENTSビューに対して指定可能なWHERE句条件の形式にすることができます。例は、basic_filter => 'sql_text like ''select /*LOAD_STS*/%'''です。

fixed

デフォルトのNOにすると、ロードされた計画が、固定されていない計画として使用されます。YESにすると、ロードされた計画は固定計画になります。「計画の選択」では、オプティマイザが計画ベースライン内で固定されていない計画よりも固定計画を優先させることについて説明しています。

この項では、コマンドラインから計画をロードする方法について説明します。Cloud Controlでは、「SQL計画ベースライン」サブページ(図23-7を参照)に移動し、「ロード」をクリックして、SQLチューニング・セットから計画ベースラインをロードします。

このチュートリアルでは、次のことが前提となっています。

- ロードした計画は固定にしない。

- 次の問合せを実行済である。

SELECT /*LOAD_STS*/ *
FROM   sh.sales
WHERE  quantity_sold > 40
ORDER BY prod_id;

- 共有SQL領域から、ユーザーSPMにより所有され、SPM_STSという名前のSQLチューニング・セットに計画をロード済である。

SQLチューニング・セットから計画をロードする手順は次のとおりです。

1. SQL*Plusを適切な権限でデータベースに接続し、SQLチューニング・セットに含まれる計画を確認します。
たとえば、DBA_SQLSET_STATEMENTSでSTS名を問い合せます(出力例も示します)。

SELECT SQL_TEXT
FROM   DBA_SQLSET_STATEMENTS
WHERE  SQLSET_NAME = 'SPM_STS';

SQL_TEXT
--------------------
SELECT /*LOAD_STS*/
*
FROM sh.sales
WHERE quantity_sold
> 40
ORDER BY prod_id

出力は、select /*LOAD_STS*/文に対する計画がSTS内にあることを示しています。

2. STSからSQL計画ベースラインに計画をロードします。
たとえば、SQL*Plusで次のようにファンクションを実行します。

VARIABLE v_plan_cnt NUMBER
EXECUTE :v_plan_cnt := DBMS_SPM.LOAD_PLANS_FROM_SQLSET( -
sqlset_name  => 'SPM_STS', -
basic_filter => 'sql_text like ''SELECT /*LOAD_STS*/%''' );

basic_filterパラメータは、関心のある問合せに対する計画のみをロードするWHERE句を指定します。変数v_plan_cntには、STSからロードされた計画の数が含まれます。

3. データ・ディクショナリを問い合せて、文に対するベースラインに計画がロードされたことを確認します。
次の文では、DBA_SQL_PLAN_BASELINESビューを問い合せます(出力例も示します)。

SQL> SELECT SQL_HANDLE, SQL_TEXT, PLAN_NAME,
2         ORIGIN, ENABLED, ACCEPTED
3  FROM   DBA_SQL_PLAN_BASELINES;

SQL_HANDLE            SQL_TEXT        PLAN_NAME        ORIGIN      ENA ACC
--------------------- --------------- ---------------- ----------- --- ---
SQL_a8632bd857a4a25e  SELECT          SQL_PLAN_ahstb   MANUAL-LOAD YES YES
/*LOAD_STS*/*   v1bu98ky1694fc6b
FROM sh.sales
WHERE
quantity_sold
> 40 ORDER BY
prod_id

出力は、計画が承認済であること、つまり計画ベースラインに含まれることを示しています。また、ロード元はMANUAL-LOADであり、これは計画は自動的に取得されたのではなく、エンド・ユーザーによりロードされたことを意味します。

4. オプションで、STSを削除します。
たとえば、DBMS_SQLTUNE.DROP_SQLSETを次のように実行して、SPM_STSチューニング・セットを削除します。

EXEC SYS.DBMS_SQLTUNE.DROP_SQLSET( sqlset_name=>'SPM_STS', sqlset_owner=>'SPM' );

関連項目:

- DBA_SQL_PLAN_BASELINESビューの詳細は、『Oracle Databaseリファレンス』を参照してください

- DBMS_SPM.LOAD_PLANS_FROM_SQLSETファンクションの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください

共有SQL領域からの計画のロード

このトピックでは、PL/SQLを使用してカーソル・キャッシュとも呼ばれる共有SQL領域から計画をロードする方法について説明します。

DBMS_SPMパッケージのLOAD_PLANS_FROM_CURSOR_CACHEファンクションを使用して計画をロードします。次の表では、ファンクション・パラメータの一部を説明します。

表23-4 LOAD_PLANS_FROM_CURSOR_CACHEのパラメータ

ファンクション・パラメータ

説明

sql_id

SQL文の識別子。共有SQL領域内のSQL文を識別します。

fixed

デフォルトのNOにすると、ロードされた計画が、固定されていない計画として使用されます。YESにすると、ロードされた計画は固定計画になります(「固定計画」を参照)。「計画の選択」では、オプティマイザが計画ベースライン内で固定されていない計画よりも固定計画を優先させることについて説明しています。

この項では、コマンドラインを使用して計画をロードする方法について説明します。Cloud Controlでは、「SQL計画ベースライン」サブページ(図23-7を参照)に移動し、「ロード」をクリックして、共有SQL領域から計画ベースラインをロードします。

このチュートリアルでは、次のことが前提となっています。

- 次の問合せを実行済である。

SELECT /*LOAD_CC*/ *
FROM   sh.sales
WHERE  quantity_sold > 40
ORDER BY prod_id;

- ロードした計画は固定にしない。

共有SQL領域から計画をロードする手順は次のとおりです。

1. SQL*Plusを適切な権限でデータベースに接続し、共有SQL領域内の関連する文のSQL IDを確認します。
たとえば、V$SQLでsh.sales問合せのSQL IDを問い合せます(出力例も示します)。

SELECT   SQL_ID, CHILD_NUMBER AS "Child Num",
PLAN_HASH_VALUE AS "Plan Hash",
OPTIMIZER_ENV_HASH_VALUE AS "Opt Env Hash"
FROM     V$SQL
WHERE    SQL_TEXT LIKE 'SELECT /*LOAD_CC*/%';

SQL_ID         Child Num  Plan Hash Opt Env Hash
------------- ---------- ---------- ------------
27m0sdw9snw59          0 1421641795   3160571937

前述の出力は、文のSQL IDが27m0sdw9snw59であることを示しています。

2. 指定した文に対する計画をSQL計画ベースラインにロードします。
たとえば、SQL*PlusでLOAD_PLANS_FROM_CURSOR_CACHEファンクションを実行して、SQL IDが27m0sdw9snw59の文に対する計画をロードします。

VARIABLE cnt NUMBER
EXECUTE :cnt := DBMS_SPM.LOAD_PLANS_FROM_CURSOR_CACHE( -
sql_id => '27m0sdw9snw59');

前述の例では、変数cntにはロードされた計画の数が含まれます。

3. データ・ディクショナリを問い合せて、文に対するベースラインに計画がロードされたことを確認します。
次の文では、DBA_SQL_PLAN_BASELINESを問い合せます(出力例も示します)。

SELECT SQL_HANDLE, SQL_TEXT, PLAN_NAME,
ORIGIN, ENABLED, ACCEPTED
FROM   DBA_SQL_PLAN_BASELINES;

SQL_HANDLE            SQL_TEXT             PLAN_NAME             ORIGIN      ENA ACC
--------------------- -------------------- --------------------- ----------- --- ---
SQL_a8632bd857a4a25e  SELECT /*LOAD_CC*/   SQL_PLAN_gdkvzfhrgkda MANUAL-LOAD YES YES
*                    71694fc6b
FROM sh.sales
WHERE quantity_sold
> 40
ORDER BY prod_id

出力は、計画が承認済であること、つまり文に対する計画ベースラインに含まれることを示しています。また、ロード元はMANUAL-LOADであり、これは文は自動的に取得されたのではなく、手動でロードされたことを意味します。

関連項目:

- DBMS_SPM.LOAD_PLANS_FROM_CURSOR_CACHEファンクションの使用方法の詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

- DBA_SQL_PLAN_BASELINESビューの詳細は、『Oracle Databaseリファレンス』を参照してください

ステージング表からの計画のロード

最適な計画をソース・データベースから別の宛先データベースに転送することが必要になる場合があります。

たとえば、テスト・データベース上で一連の計画を調査し、高いパフォーマンスを発揮することを確認したとします。その後、これらの計画を本番データベースにロードすることを決定します。

ステージング表とは、計画がアンパック中に表から消えないように、その表が存在する間、計画を保存する表です。ステージング表を作成するには、DBMS.CREATE_STGTAB_BASELINEプロシージャを使用します。ステージング表のパック(行の挿入)およびアンパック(行の抽出)には、DBMS_SPMパッケージのPACK_STGTAB_BASELINEとUNPACK_STGTAB_BASELINEファンクションを使用します。Oracle Data Pump ImportとExportを使用すると、ステージング表を別のデータベースにコピーできます。

次の図は、基本的な手順を示しています。

図23-8 ステージング表からの計画のロード

前提条件

このチュートリアルでは、次のことが前提となっています。

- ソース・データベース内にstage1という名前のステージング表を作成する。

- ユーザーspmが所有するすべての計画をステージング表にロードする。

- ステージング表を宛先データベースに転送する。

- stage1内の計画を固定計画としてロードする。

あるデータベースから別のデータベースへとSQL計画ベースラインのセットを転送する手順は次のとおりです。

1. SQL*Plusを使用して適切な権限でソース・データベースにログインし、CREATE_STGTAB_BASELINEプロシージャを使用してステージング表を作成します。
次の例では、stage1というステージング表が作成されます。

BEGIN
DBMS_SPM.CREATE_STGTAB_BASELINE (
table_name => 'stage1');
END;
/

2. ソース・データベースで、SQL管理ベースからステージング表にエクスポートするSQL計画ベースラインをパックします。
次の例では、ユーザーspmが作成した有効な計画ベースラインをステージング表stage1にパックします。計画名(plan_name)、SQLハンドル(sql_handle)またはその他の計画基準を使用して、SQL計画ベースラインを選択します。table_nameパラメータは必須です。

DECLARE
v_plan_cnt NUMBER;
BEGIN
v_plan_cnt := DBMS_SPM.PACK_STGTAB_BASELINE (
table_name => 'stage1'
,   enabled    => 'yes'
,   creator    => 'spm'
);
END;
/

3. Oracle Data Pump Exportを使用して、ステージング表stage1をダンプ・ファイルにエクスポートします。

4. ダンプ・ファイルを宛先データベースのホストに転送します。

5. 宛先データベースで、Oracle Data Pump Importユーティリティを使用して、ステージング表stage1をダンプ・ファイルからインポートします。

6. 宛先データベースで、SQL計画ベースラインをステージング表からSQL管理ベースにアンパックします。
次の例では、ステージング表stage1に格納された固定計画ベースラインがすべて解凍されます。

DECLARE
v_plan_cnt NUMBER;
BEGIN
v_plan_cnt := DBMS_SPM.UNPACK_STGTAB_BASELINE (
table_name => 'stage1'
,   fixed      => 'yes'
);
END;
/

関連項目:

- DBMS_SPMパッケージの使用方法の詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

- データ・ポンプ・エクスポートおよびインポート・ユーティリティの使用方法の詳細は、『Oracle Databaseユーティリティ』を参照してください。

SQL計画ベースラインの手動での展開

SQL計画管理の展開タスクが自動的に実行されるように構成することをお薦めします。またPL/SQLまたはCloud Controlを使用して、承認されていない計画を手動で展開することにより、計画ベースライン内の現在のいずれの計画よりもパフォーマンスが優れているかどうかを判断することもできます。

この項の内容は次のとおりです。

- DBMS_SPM展開ファンクションについて

- 展開タスクの管理

関連項目:

「SPM展開アドバイザのタスクの管理」

DBMS_SPM展開ファンクションについて

このトピックでは、計画の展開を管理するための主なDBMS_SPMファンクションについて説明します。展開タスクは手動で実行するか、自動的に実行されるようにスケジュールします。

表23-5 計画の展開タスクを管理するためのDBMS_SPMファンクションとプロシージャ

プロシージャまたはファンクション

説明

ACCEPT_SQL_PLAN_BASELINE

このファンクションは、1つの計画をSQL計画ベースラインに展開するという1つの推奨事項を承認します。

CREATE_EVOLVE_TASK

このファンクションは、指定されたSQL文に対する1つ以上の計画の展開を準備するためのアドバイザ・タスクを作成します。入力パラメータは、SQLハンドル、計画名または計画名のリスト、時間制限、タスク名および説明になります。

EXECUTE_EVOLVE_TASK

このファンクションは展開タスクを実行します。入力パラメータは、タスク名、実行名および実行の説明になります。指定しない場合は、アドバイザによって名前が生成され、ファンクションによって戻されます。

IMPLEMENT_EVOLVE_TASK

このファンクションは展開タスクに対するすべての推奨事項を実装します。基本的にはこのファンクションは、推奨されるすべての計画に対してACCEPT_SQL_PLAN_BASELINEを使用することと同じです。入力パラメータは、タスク名、計画名、所有者名および実行名などです。

REPORT_EVOLVE_TASK

このファンクションは、展開タスクの結果をCLOBとして表示します。入力パラメータは、タスク名およびレポートに含めるセクションです。

SET_EVOLVE_TASK_PARAMETER

このファンクションは展開タスク・パラメータの値を更新します。このリリースでは、有効なパラメータはTIME_LIMITのみです。

SPM展開アドバイザを構成して自動的に実行することをお薦めします。SQL計画ベースラインを手動で展開することもできます。次の図は、SQL計画管理タスクを管理する基本ワークフローを示しています。

図23-9 SQL計画ベースラインの展開

通常、SQL計画の展開タスクを管理する順序は次のとおりです。

1. 展開タスクを作成します。

2. オプションで、展開タスクのパラメータを設定します。

3. 展開タスクを実行します。

4. タスク内の推奨事項を実装します。

5. タスクの結果をレポートします。

関連項目:

- 「SPM展開アドバイザの自動タスクの構成」

- DBMS_SPMパッケージの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください

展開タスクの管理

このトピックでは、タスクを作成して実行し、その後その推奨事項を実装する典型的なユースケースについて説明します。

次の表では、CREATE_EVOLVE_TASKファンクションのパラメータの一部を説明します。

表23-6 DBMS_SPM.CREATE_EVOLVE_TASKのパラメータ

ファンクション・パラメータ

説明

sql_handle

文のSQLハンドル。デフォルトのNULLでは、承認されていない計画のあるすべてのSQL文を考慮します。

plan_name

計画の識別子。デフォルトのNULLは、指定されたSQLハンドルのすべての承認されていない計画、またはSQLハンドルがNULLの場合はすべてのSQL文のすべての承認されていない計画を考慮することを意味します。

time_limit

時間制限(分)。最初の承認されていない計画に対する時間制限は、入力値と等しくなります。2つ目の承認されていない計画に対する時間制限は、入力値から最初の計画の検証にかかった時間を引いた時間になります。以下同様です。デフォルトのDBMS_SPM.AUTO_LIMITは、計画に対して実行する必要がある検証の数に基づいて適切な時間制限が選択されることを意味します。

task_name

展開タスクのユーザー指定名。

この項では、コマンドラインから計画ベースラインを展開する方法について説明します。Cloud Controlでは、「SQL計画ベースライン」サブページで、計画を選択してから「展開」をクリックします。

このチュートリアルでは、次のことが前提となっています。

- 自動展開タスクを有効にしていない(「SPM展開アドバイザのタスクの管理」を参照)。

- 次の問合せに対するSQL計画ベースラインを作成する。

SELECT /* q1_group_by */ prod_name, sum(quantity_sold)
FROM   products p, sales s
WHERE  p.prod_id = s.prod_id
AND    p.prod_category_id =203
GROUP BY prod_name;

- 問合せのパフォーマンスを向上させるための索引を2つ作成し、これらの索引を使用する計画のパフォーマンスが計画ベースライン内に現在含まれる計画よりも優れている場合は、その計画を展開する。

指定した計画を展開する手順は次のとおりです。

1. 次の手順で初期設定を実行します。

a. SQL*Plusを管理者権限でデータベースに接続し、共有プールとバッファ・キャッシュをフラッシュすることによりチュートリアルの準備を行います。

ALTER SYSTEM FLUSH SHARED_POOL;
ALTER SYSTEM FLUSH BUFFER_CACHE;

b. SQL計画ベースラインの自動取得を有効にします。
たとえば、次の文を入力します。

ALTER SYSTEM SET OPTIMIZER_CAPTURE_SQL_PLAN_BASELINES=true;

c. ユーザーshとしてデータベースに接続し、SQL*Plusの表示パラメータを設定します。

CONNECT sh
-- enter password
SET PAGES 10000 LINES 140
SET SERVEROUTPUT ON
COL SQL_TEXT FORMAT A20
COL SQL_HANDLE FORMAT A20
COL PLAN_NAME FORMAT A30
COL ORIGIN FORMAT A12
SET LONGC 60535
SET LONG 60535
SET ECHO ON

2. SQL計画管理により取得されるように、SELECT文を実行します。

a. SELECT /* q1_group_by */文を実行します(1回目)。
データベースは繰返し可能な文に対する計画のみを取得するため、この文に対する計画ベースラインは空になります。

b. データ・ディクショナリを問い合せて、計画ベースライン内に計画がないことを確認します。
たとえば、次の問合せを実行します(出力例も示します)。

SELECT SQL_HANDLE, SQL_TEXT, PLAN_NAME, ORIGIN, ENABLED,
ACCEPTED, FIXED, AUTOPURGE
FROM   DBA_SQL_PLAN_BASELINES
WHERE  SQL_TEXT LIKE '%q1_group%';

no rows selected

SQL計画管理は繰返し可能な文に対する計画のみを取得するため、この結果は予想どおりです。

c. SELECT /* q1_group_by */文を実行します(2回目)。

3. データ・ディクショナリを問い合せて、文に対する計画ベースラインに計画がロードされたことを確認します。
次の文では、DBA_SQL_PLAN_BASELINESを問い合せます(出力例も示します)。

SELECT SQL_HANDLE, SQL_TEXT, PLAN_NAME,
ORIGIN, ENABLED, ACCEPTED, FIXED
FROM   DBA_SQL_PLAN_BASELINES
WHERE  SQL_TEXT LIKE '%q1_group%';

SQL_HANDLE           SQL_TEXT         PLAN_NAME                      ORIGIN       ENA ACC FIX
-------------------- ---------------- ------------------------------ ------------ --- --- ---
SQL_07f16c76ff893342 SELECT /* q1_gro SQL_PLAN_0gwbcfvzskcu242949306 AUTO-CAPTURE YES YES NO
up_by */ prod_na
me, sum(quantity
_sold) FROM
products p,
sales s WHERE
p.prod_id =
s.prod_id AND
p.prod_category
_id =203 GROUP
BY prod_name

出力は、計画が承認済であること、つまり文に対する計画ベースラインに含まれることを示しています。また、ロード元はAUTO-CAPTUREであり、これは文は手動でロードされたのではなく、自動的に取得されたことを意味します。

4. 文に対する計画をEXPLAINし、オプティマイザによりこの計画が使用されていることを確認します。
たとえば、次のように計画をEXPLAINしてから表示します。

EXPLAIN PLAN FOR
SELECT /* q1_group_by */ prod_name, sum(quantity_sold)
FROM   products p, sales s
WHERE  p.prod_id = s.prod_id
AND    p.prod_category_id =203
GROUP BY prod_name;

SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY(null, null, 'basic +note'));

出力例は次のように表示されます。

Plan hash value: 1117033222

------------------------------------------
| Id  | Operation             | Name     |
------------------------------------------
|   0 | SELECT STATEMENT      |          |
|   1 |  HASH GROUP BY        |          |
|   2 |   HASH JOIN           |          |
|   3 |    TABLE ACCESS FULL  | PRODUCTS |
|   4 |    PARTITION RANGE ALL|          |
|   5 |     TABLE ACCESS FULL | SALES    |
------------------------------------------

Note
-----
- SQL plan baseline "SQL_PLAN_0gwbcfvzskcu242949306" used for this statement

注意事項は、オプティマイザが前の手順でリストされていた計画名で示されている計画を使用していることを示しています。

5. SELECT /* q1_group_by */文のパフォーマンスを向上させるために2つの索引を作成します。
たとえば、次の文を使用します。

CREATE INDEX ind_prod_cat_name
ON products(prod_category_id, prod_name, prod_id);
CREATE INDEX ind_sales_prod_qty_sold
ON sales(prod_id, quantity_sold);

6. SELECT /* q1_group_by */文を再度実行します。
自動取得が有効になっているため、この文に対する新しい計画が計画ベースラインに移入されます。

7. データ・ディクショナリを問い合せて、文に対するSQL計画ベースラインに計画がロードされたことを確認します。
次の文では、DBA_SQL_PLAN_BASELINESを問い合せます(出力例も示します)。

SELECT SQL_HANDLE, SQL_TEXT, PLAN_NAME, ORIGIN, ENABLED, ACCEPTED
FROM   DBA_SQL_PLAN_BASELINES
WHERE  SQL_HANDLE IN ('SQL_07f16c76ff893342')
ORDER BY SQL_HANDLE, ACCEPTED;

SQL_HANDLE           SQL_TEXT             PLAN_NAME                      ORIGIN       ENA ACC
-------------------- -------------------- ------------------------------ ------------ --- ---
SQL_07f16c76ff893342 SELECT /* q1_group_b SQL_PLAN_0gwbcfvzskcu20135fd6c AUTO-CAPTURE YES NO
y */ prod_name, sum(
quantity_sold)
FROM   products p, s
ales s
WHERE  p.prod_id = s
.prod_id
AND    p.prod_catego
ry_id =203
GROUP BY prod_name

SQL_07f16c76ff893342 SELECT /* q1_group_b SQL_PLAN_0gwbcfvzskcu242949306 AUTO-CAPTURE YES YES
y */ prod_name, sum(
quantity_sold)
FROM   products p, s
ales s
WHERE  p.prod_id = s
.prod_id
AND    p.prod_catego
ry_id =203
GROUP BY prod_name

出力は、新しい計画が承認されていないこと、つまり文の履歴には含まれているが、SQL計画ベースラインに含まれていないことを示しています。

8. 文に対する計画をEXPLAINし、オプティマイザにより元の索引なしの計画が使用されていることを確認します。
たとえば、次のように計画をEXPLAINしてから表示します。

EXPLAIN PLAN FOR
SELECT /* q1_group_by */ prod_name, sum(quantity_sold)
FROM   products p, sales s
WHERE  p.prod_id = s.prod_id
AND    p.prod_category_id =203
GROUP BY prod_name;
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY(null, null, 'basic +note'));

出力例は次のように表示されます。

Plan hash value: 1117033222

------------------------------------------
| Id  | Operation             | Name     |
------------------------------------------
|   0 | SELECT STATEMENT      |          |
|   1 |  HASH GROUP BY        |          |
|   2 |   HASH JOIN           |          |
|   3 |    TABLE ACCESS FULL  | PRODUCTS |
|   4 |    PARTITION RANGE ALL|          |
|   5 |     TABLE ACCESS FULL | SALES    |
------------------------------------------

Note
-----
- SQL plan baseline "SQL_PLAN_0gwbcfvzskcu242949306" used for this statement

注意事項は、オプティマイザが手順3でリストされていた計画名で示されている計画を使用していることを示しています。

9. 管理者として接続し、承認されていない計画を持つすべてのSQL文を考慮する展開タスクを作成します。
たとえば、DBMS_SPM.CREATE_EVOLVE_TASKファンクションを実行し、その後タスクの名前を取得します。

CONNECT / AS SYSDBA
VARIABLE cnt NUMBER
VARIABLE tk_name VARCHAR2(50)
VARIABLE exe_name VARCHAR2(50)
VARIABLE evol_out CLOB

EXECUTE :tk_name := DBMS_SPM.CREATE_EVOLVE_TASK(
sql_handle => 'SQL_07f16c76ff893342',
plan_name  => 'SQL_PLAN_0gwbcfvzskcu20135fd6c');

SELECT :tk_name FROM DUAL;

次の出力例は、タスクの名前を示しています。

:EVOL_OUT
--------------------------------------------------------------------------
TASK_11

これでタスクが作成され、一意の名前が付けられたので、タスクを実行できます。

10. タスクを実行します。
たとえば、DBMS_SPM.EXECUTE_EVOLVE_TASKファンクションを実行します(出力例も示します)。

EXECUTE :exe_name :=DBMS_SPM.EXECUTE_EVOLVE_TASK(task_name=>:tk_name);
SELECT :exe_name FROM DUAL;

:EXE_NAME
---------------------------------------------------------------------------
EXEC_1

11. レポートを表示します。
たとえば、DBMS_SPM.REPORT_EVOLVE_TASKファンクションを実行します(出力例も示します)。

EXECUTE :evol_out := DBMS_SPM.REPORT_EVOLVE_TASK( task_name=>:tk_name, execution_name=>:exe_name );
SELECT :evol_out FROM DUAL;

GENERAL INFORMATION SECTION
--------------------------------------------------------------------------

Task Information:
---------------------------------------------
Task Name            : TASK_11
Task Owner           : SYS
Execution Name       : EXEC_1
Execution Type       : SPM EVOLVE
Scope                : COMPREHENSIVE
Status               : COMPLETED
Started              : 01/09/2012 12:21:27
Finished             : 01/09/2012 12:21:29
Last Updated         : 01/09/2012 12:21:29
Global Time Limit    : 2147483646
Per-Plan Time Limit  : UNUSED
Number of Errors     : 0
---------------------------------------------------------------------------

SUMMARY SECTION
---------------------------------------------------------------------------
Number of plans processed  : 1
Number of findings         : 1
Number of recommendations  : 1
Number of errors           : 0
---------------------------------------------------------------------------

DETAILS SECTION
---------------------------------------------------------------------------
Object ID         : 2
Test Plan Name    : SQL_PLAN_0gwbcfvzskcu20135fd6c
Base Plan Name    : SQL_PLAN_0gwbcfvzskcu242949306
SQL Handle        : SQL_07f16c76ff893342
Parsing Schema    : SH
Test Plan Creator : SH
SQL Text          : SELECT /*q1_group_by*/ prod_name,
sum(quantity_sold)
FROM products p, sales s
WHERE p.prod_id=s.prod_id AND p.prod_category_id=203
GROUP BY prod_name

Execution Statistics:
-----------------------------
Base Plan                     Test Plan
----------------------------  ------------------------
Elapsed Time (s):  .044336                       .012649
CPU Time (s):      .044003                       .012445
Buffer Gets:       360                           99
Optimizer Cost:    924                           891
Disk Reads:        341                           82
Direct Writes:     0                             0
Rows Processed:    4                             2
Executions:        5                             9

FINDINGS SECTION
---------------------------------------------------------------------------

Findings (1):
-----------------------------
1. The plan was verified in 2.18 seconds. It passed the benefit criterion
because its verified performance was 2.01 times better than that of the
baseline plan.

Recommendation:
-----------------------------
Consider accepting the plan. Execute
dbms_spm.accept_sql_plan_baseline(task_name => 'TASK_11', object_id => 2,
task_owner => 'SYS');

EXPLAIN PLANS SECTION
---------------------------------------------------------------------------

Baseline Plan
-----------------------------
Plan Id          : 1
Plan Hash Value  : 1117033222

---------------------------------------------------------------------------
| Id| Operation               | Name     | Rows | Bytes   |Cost | Time    |
---------------------------------------------------------------------------
| 0 | SELECT STATEMENT        |          |   21 |     861 | 924 | 00:00:12|
| 1 |   HASH GROUP BY         |          |   21 |     861 | 924 | 00:00:12|
| *2|    HASH JOIN            |          |267996|10987836 | 742 | 00:00:09|
| *3|     TABLE ACCESS FULL   | PRODUCTS |   21 |     714 |   2 | 00:00:01|
| 4 |     PARTITION RANGE ALL |          |918843| 6431901 | 662 | 00:00:08|
| 5 |      TABLE ACCESS FULL  | SALES    |918843| 6431901 | 662 | 00:00:08|
---------------------------------------------------------------------------

Predicate Information (identified by operation id):
------------------------------------------
* 2 - access("P"."PROD_ID"="S"."PROD_ID")
* 3 - filter("P"."PROD_CATEGORY_ID"=203)

Test Plan
-----------------------------
Plan Id          : 2
Plan Hash Value  : 20315500

---------------------------------------------------------------------------
|Id| Operation            | Name             | Rows | Bytes  | Cost| Time |
---------------------------------------------------------------------------
| 0|SELECT STATEMENT      |                  |    21|     861|891|00:00:11|
| 1|  SORT GROUP BY NOSORT|                  |    21|     861|891|00:00:11|
| 2|   NESTED LOOPS       |                  |267996|10987836|891|00:00:11|
|*3|    INDEX RANGE SCAN  |IND_PROD_CAT_NAME |    21|     714|  1|00:00:01|
|*4|    INDEX RANGE SCAN  |IND_SALES_PROD_QTY| 12762|   89334| 42|00:00:01|
---------------------------------------------------------------------------

Predicate Information (identified by operation id):
------------------------------------------
* 3 - access("P"."PROD_CATEGORY_ID"=203)
* 4 - access("P"."PROD_ID"="S"."PROD_ID")

このレポートは、2つの新しい索引を使用する新しい実行計画のパフォーマンスが元の計画よりも優れていることを示しています。

12. 展開タスクの推奨事項を実装します。
たとえば、IMPLEMENT_EVOLVE_TASKファンクションを実行します。

EXECUTE :cnt := DBMS_SPM.IMPLEMENT_EVOLVE_TASK( task_name=>:tk_name, execution_name=>:exe_name );

13. データ・ディクショナリを問い合せて、新しい計画が承認されたことを確認します。
問合せにより、次のサンプル出力が提供されます。

SELECT SQL_HANDLE, SQL_TEXT, PLAN_NAME, ORIGIN, ENABLED, ACCEPTED
FROM   DBA_SQL_PLAN_BASELINES
WHERE  SQL_HANDLE IN ('SQL_07f16c76ff893342')
ORDER BY SQL_HANDLE, ACCEPTED;

SQL_HANDLE           SQL_TEXT             PLAN_NAME                      ORIGIN       ENA ACC
-------------------- -------------------- ------------------------------ ------------ --- ---
SQL_07f16c76ff893342 SELECT /* q1_group_b SQL_PLAN_0gwbcfvzskcu20135fd6c AUTO-CAPTURE YES YES
y */ prod_name, sum(
quantity_sold)
FROM   products p, s
ales s
WHERE  p.prod_id = s
.prod_id
AND    p.prod_catego
ry_id =203
GROUP BY prod_name

SQL_07f16c76ff893342 SELECT /* q1_group_b SQL_PLAN_0gwbcfvzskcu242949306 AUTO-CAPTURE YES YES
y */ prod_name, sum(
quantity_sold)
FROM   products p, s
ales s
WHERE  p.prod_id = s
.prod_id
AND    p.prod_catego
ry_id =203
GROUP BY prod_name

出力は、新しい計画が承認されたことを示しています。

14. 例の後のクリーンアップを実行します。
たとえば、次の文を入力します。

EXEC :cnt := DBMS_SPM.DROP_SQL_PLAN_BASELINE('SQL_07f16c76ff893342');
EXEC :cnt := DBMS_SPM.DROP_SQL_PLAN_BASELINE('SQL_9049245213a986b3');
EXEC :cnt := DBMS_SPM.DROP_SQL_PLAN_BASELINE('SQL_bb77077f5f90a36b');
EXEC :cnt := DBMS_SPM.DROP_SQL_PLAN_BASELINE('SQL_02a86218930bbb20');
DELETE FROM SQLLOG$;
CONNECT sh
-- enter password
DROP INDEX IND_SALES_PROD_QTY_SOLD;
DROP INDEX IND_PROD_CAT_NAME;

関連項目:

DBMS_SPM展開ファンクションの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください

SQL計画ベースラインの削除

SQL計画ベースラインから一部またはすべての計画を削除できます。この方法は、SQL計画管理のテスト時に役立つことがあります。

計画を削除するには、DBMS_SPM.DROP_SQL_PLAN_BASELINEファンクションを使用します。このファンクションは、削除された計画の数を戻します。次の表では、入力パラメータを説明します。

表23-7 DROP_SQL_PLAN_BASELINEのパラメータ

ファンクション・パラメータ

説明

sql_handle

SQL文の識別子。

plan_name

特定の計画の名前。デフォルトのNULLにすると、sql_handleで識別されるSQL文に関連付けられているすべての計画が削除されます。

この項では、コマンドラインからベースラインを削除する方法について説明します。Cloud Controlでは、「SQL計画ベースライン」サブページで、計画を選択してから「削除」をクリックします。

このチュートリアルでは、次のSQL文に対するすべての計画を削除することにより、実質的にSQL計画ベースラインを削除するものとします。

SELECT /* repeatable_sql */ COUNT(*) FROM hr.jobs;

SQL計画ベースラインを削除する手順は次のとおりです。

1. SQL*Plusを適切な権限でデータベースに接続し、データ・ディクショナリで計画ベースラインを問い合せます。
次の文では、DBA_SQL_PLAN_BASELINESを問い合せます(出力例も示します)。

SQL> SELECT SQL_HANDLE, SQL_TEXT, PLAN_NAME, ORIGIN,
2         ENABLED, ACCEPTED
3  FROM   DBA_SQL_PLAN_BASELINES
4  WHERE  SQL_TEXT LIKE 'SELECT /* repeatable_sql%';

SQL_HANDLE           SQL_TEXT             PLAN_NAME                      ORIGIN         ENA ACC
-------------------- -------------------- ------------------------------ -------------- --- ---
SQL_b6b0d1c71cd1807b SELECT /* repeatable SQL_PLAN_bdc6jswfd303v2f1e9c20 AUTO-CAPTURE   YES YES
_sql */ count(*) fro
m hr.jobs

2. 文に対するSQL計画ベースラインを削除します。
次の例は、SQLハンドルがSQL_b6b0d1c71cd1807bの計画ベースラインを削除し、削除された計画の数を戻します。計画名(plan_name)、SQLハンドル(sql_handle)またはその他の計画基準を使用して、計画ベースラインを指定します。table_nameパラメータは必須です。

DECLARE
v_dropped_plans number;
BEGIN
v_dropped_plans := DBMS_SPM.DROP_SQL_PLAN_BASELINE (
sql_handle => 'SQL_b6b0d1c71cd1807b'
);
DBMS_OUTPUT.PUT_LINE('dropped ' || v_dropped_plans || ' plans');
END;
/

3. 計画が削除されたことを確認します。
たとえば、次の問合せを実行します。

SELECT SQL_HANDLE, SQL_TEXT, PLAN_NAME, ORIGIN,
ENABLED, ACCEPTED
FROM   DBA_SQL_PLAN_BASELINES
WHERE  SQL_TEXT LIKE 'SELECT /* repeatable_sql%';

no rows selected

関連項目:

DROP_SQL_PLAN_BASELINEファンクションの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

SQL管理ベースの管理

SQL管理ベース(SMB)は、SYSAUX表領域にあるデータ・ディクショナリの一部です。SMBには、文のログ、計画履歴、SQL計画ベースラインおよびSQLプロファイルが格納されます。

この項では、SMB用のディスク領域使用量パラメータの変更方法およびSMBでの計画の保存時間の変更方法について説明します。

DBA_SQL_MANAGEMENT_CONFIGビューには、SMBの現在の構成設定が表示されます。表23-8に、PARAMETER_NAME列のパラメータを示します。

表23-8 DBA_SQL_MANAGEMENT_CONFIG.PARAMETER_NAMEのパラメータ

パラメータ

説明

SPACE_BUDGET_PERCENT

SQL管理ベースが使用可能なSYSAUX領域の最大の割合。デフォルトは10です。この制限の許容範囲は1から50%です。

PLAN_RETENTION_WEEKS

消去するまで未使用の計画を保持する週の数。デフォルトは53です。

SMBのディスク領域制限の変更

週に1回のバックグラウンド・プロセスによって、SMBが使用する総領域が測定されます。定義した制限を超過すると、アラート・ログに警告が書き込まれます。SMB領域の制限が引き上げられるか、SYSAUX表領域のサイズが引き上げられるか、またはSQL管理オブジェクト(SQL計画ベースラインまたはSQLプロファイル)の消去によりSMBによって使用されている領域が減るまで、データベースは週に1回アラートを生成し続けます。このタスクでは、DBMS_SPM.CONFIGUREプロシージャを使用して制限を変更する方法について説明します。

前提条件

このチュートリアルでは、次のことが前提となっています。

- 現在のSMB領域制限がデフォルトの10%である。

- 制限の比率を30%に変更する。

SMBの制限の比率を変更する手順は次のとおりです。

1. SQL*Plusを適切な権限でデータベースに接続し、データ・ディクショナリを問い合せて、現在の領域配分の比率を確認します。
たとえば、次の問合せを実行します(出力例も示します)。

SELECT PARAMETER_NAME, PARAMETER_VALUE AS "%_LIMIT",
( SELECT sum(bytes/1024/1024) FROM DBA_DATA_FILES
WHERE TABLESPACE_NAME = 'SYSAUX' ) AS SYSAUX_SIZE_IN_MB,
PARAMETER_VALUE/100 *
( SELECT sum(bytes/1024/1024) FROM DBA_DATA_FILES
WHERE TABLESPACE_NAME = 'SYSAUX' ) AS "CURRENT_LIMIT_IN_MB"
FROM DBA_SQL_MANAGEMENT_CONFIG
WHERE PARAMETER_NAME = 'SPACE_BUDGET_PERCENT';

PARAMETER_NAME          %_LIMIT SYSAUX_SIZE_IN_MB CURRENT_LIMIT_IN_MB
-------------------- ---------- ----------------- -------------------
SPACE_BUDGET_PERCENT         10          211.4375            21.14375

2. 比率設定を変更します。
たとえば、設定を30%に変更するには次のコマンドを実行します。

EXECUTE DBMS_SPM.CONFIGURE('space_budget_percent',30);

3. データ・ディクショナリを問い合せて、変更を確認します。
たとえば、次の結合を実行します(出力例も示します)。

SELECT PARAMETER_NAME, PARAMETER_VALUE AS "%_LIMIT",
( SELECT sum(bytes/1024/1024) FROM DBA_DATA_FILES
WHERE TABLESPACE_NAME = 'SYSAUX' ) AS SYSAUX_SIZE_IN_MB,
PARAMETER_VALUE/100 *
( SELECT sum(bytes/1024/1024) FROM DBA_DATA_FILES
WHERE TABLESPACE_NAME = 'SYSAUX' ) AS "CURRENT_LIMIT_IN_MB"
FROM   DBA_SQL_MANAGEMENT_CONFIG
WHERE  PARAMETER_NAME = 'SPACE_BUDGET_PERCENT';

PARAMETER_NAME          %_LIMIT SYSAUX_SIZE_IN_MB CURRENT_LIMIT_IN_MB
-------------------- ---------- ----------------- -------------------
SPACE_BUDGET_PERCENT         30          211.4375            63.43125

関連項目:

CONFIGUREプロシージャの詳細は、『Oracle Database PL/SQLパッケージ・プロシージャおよびタイプ・リファレンス』を参照してください

SMBでの計画保存ポリシーの変更

週次にスケジュールされた消去タスクにより、SQL計画の管理で使用されるディスク領域が管理されます。このタスクは、メンテナンス期間に自動化タスクとして実行されます。データベースは、計画保存期間を超える間使用されていない計画を消去します。消去対象は、SMBに保存されたその計画のLAST_EXECUTEDタイムスタンプで識別されます。デフォルトの保存期間は53週です。指定できる期間の範囲は5から523週です。

このタスクでは、DBMS_SPM.CONFIGUREプロシージャを使用して計画保存期間を変更する方法について説明します。Cloud Controlでは、「SQL計画ベースライン」サブページ(図23-7を参照)で計画保存ポリシーを設定します。

SMBの計画保存期間を変更する手順は次のとおりです。

1. SQL*Plusを適切な権限でデータベースに接続し、データ・ディクショナリを問い合せて、現在の計画保存期間を確認します。
たとえば、次の問合せを実行します(出力例も示します)。

SQL> SELECT PARAMETER_NAME, PARAMETER_VALUE
2  FROM   DBA_SQL_MANAGEMENT_CONFIG
3  WHERE  PARAMETER_NAME = 'PLAN_RETENTION_WEEKS';

PARAMETER_NAME                 PARAMETER_VALUE
------------------------------ ---------------
PLAN_RETENTION_WEEKS                        53

2. 保存期間を変更します。
たとえば、CONFIGUREプロシージャを実行して期間を105週に変更します。

EXECUTE DBMS_SPM.CONFIGURE('plan_retention_weeks',105);

3. データ・ディクショナリを問い合せて、変更を確認します。
たとえば、次の問合せを実行します。

SQL> SELECT PARAMETER_NAME, PARAMETER_VALUE
2  FROM   DBA_SQL_MANAGEMENT_CONFIG
3  WHERE  PARAMETER_NAME = 'PLAN_RETENTION_WEEKS';

PARAMETER_NAME                 PARAMETER_VALUE
------------------------------ ---------------
PLAN_RETENTION_WEEKS                       105

関連項目:

CONFIGUREプロシージャの詳細は、『Oracle Database PL/SQLパッケージ・プロシージャおよびタイプ・リファレンス』を参照してください

24 ストアド・アウトラインのSQL計画ベースラインへの移行

ストアド・アウトラインの移行は、保存されたアウトラインをSQL計画ベースラインに変換するためにユーザーが開始するプロセスです。SQL計画ベースラインは、最適なパフォーマンスを提供することが立証された計画のセットです。

この章では、ストアド・アウトラインの移行の概要およびタスクについて説明します。この章の内容は次のとおりです。

- ストアド・アウトラインの移行について

- ストアド・アウトラインの移行の準備

- アウトラインの移行によるSQL計画管理機能の使用

- アウトラインの移行でのストアド・アウトライン動作の保存

- ストアド・アウトラインの移行後のフォーローアップ・タスクの実行

注意:

Oracle Database 12cで開始する場合は、ストアド・アウトラインは非推奨となっています。代替方法は、「ストアド・アウトラインのSQL計画ベースラインへの移行」を参照してください。

ストアド・アウトラインの移行について

ストアド・アウトラインは、SQL文のヒントのセットです。ヒントは、文に対する特定の計画を選択するようオプティマイザに指示します。ストアド・アウトラインは、計画の安定性を提供するためのレガシー・テクニックです。

この項の内容は次のとおりです。

- ストアド・アウトラインの移行の目的

- ストアド・アウトラインの移行方法

- ストアド・アウトラインの移行のためのユーザー・インタフェース

- ストアド・アウトラインの移行の基本ステップ

ストアド・アウトラインの移行の目的

計画の安定性を維持し、パフォーマンスの低下を防止するためにストアド・アウトラインに依存している場合は、ストアド・アウトラインからSQL計画ベースラインに安全に移行できます。移行した後、同じ計画の安定性を維持し、SQL計画管理フレームワークで提供された機能を利用できます。

ストアド・アウトラインには、次のデメリットがあります。

- ストアド・アウトラインは、時間の経過とともに自動的に進化しません。したがって、ストアド・アウトラインは、作成した時点では最適であっても、データベースの変更後に最適ではない計画となってパフォーマンスの低下をもたらす場合があります。

- ストアド・アウトラインのヒントは、削除された索引に対する索引ヒントと同様に無効になる場合があります。この場合、データベースでは、無効なヒントを除外してアウトラインを使用し続け、多くの場合、元の計画またはオプティマイザによって生成される現在の最適なコスト計画より劣悪な計画が生じます。

- SQL文では、現在指定されているカテゴリでストアド・アウトラインに定義された計画のみを選択できます。パフォーマンスが向上する場合でも、異なるカテゴリのストアド・アウトラインからの選択、または現在のコストベースの計画は選択できません。

- ストアド・アウトラインは、事後対応型のチューニング・テクニックです。したがって、パフォーマンス問題が発生した後にのみストアド・アウトラインを使用して問題に対処します。たとえば、高負荷になったSQL文の計画を修正するストアド・アウトラインを実装できます。この場合、高負荷になる前に予防的に文をチューニングせずに、ストアド・アウトラインを使用します。

ストアド・アウトライン移行PL/SQL APIは、次のように前述の問題を解決するのに役立ちます。

- SQL計画ベースラインにより、オプティマイザが同じ最適な計画を使用し、時間の経過とともに計画を進化させることができます。
指定したSQL文の新しい計画は、パフォーマンスの低下が生じないことを検証した後にSQL計画ベースラインとして追加できます。

- SQL計画ベースラインは、無効なヒントのために計画が再生できなくなることを防止します。
計画ベースラインに格納されたヒントが無効になった場合、その計画は再生可能な計画ではありません。この場合は、代替の再生可能な計画ベースラインまたはオプティマイザによって生成された現在の最適なコスト計画が選択されます。

- 特定のSQL文に対する複数の計画ベースラインを管理できます。
オプティマイザは、特定のSQL文の計画を最適な計画のセットから選択できるため、ストアド・アウトラインでのカテゴリごとに1つの計画といった要件に制限されることはありません。

ストアド・アウトラインの移行方法

この項では、ストアド・アウトラインをSQL計画ベースラインに移行する方法について説明します。この情報は、ストアド・アウトラインの移行タスクの実行に関する重要な情報です。

ストアド・アウトラインの移行ステージ

ストアド・アウトラインを移行するには、ストアド・アウトラインを指定します。SQL計画ベースラインが作成され、更新されます。

図24-1 ストアド・アウトラインの移行ステージ

移行プロセスには、次のステージがあります。

1. ユーザーが、移行するアウトラインを指定するファンクションを起動します。

2. データベースでアウトラインが次のように処理されます。

a. データベースが計画ベースラインに必要なアウトラインの情報をコピーします。
データベースでは、情報を直接コピーするか、アウトラインの情報に基づいて計算します。たとえば、SQL文のテキストは両方のスキーマに存在するので、テキストをアウトラインからベースラインにコピーできます。

b. データベースでは、ヒントを再解析してアウトラインにない情報を取得します。
計画のハッシュ値および計画のコストは、アウトラインの既存情報から得られないため、ヒントの再解析が必要です。

c. データベースがベースラインを作成します。

3. データベースでは、初めてSQL計画ベースラインを選択してSQL文を実行する際に、不足している情報を取得します。
コンパイル環境および実行統計は、実行する際に、計画ベースラインを解析およびコンパイルするときにのみ取得できます。

これらのフェーズが完了した後、移行が完了します。

アウトラインのカテゴリとベースライン・モジュール

アウトラインはヒントのセットであり、SQL計画ベースラインは計画のセットです。

これらは異なる技術であるため、アウトラインの一部の機能は、ベースラインの機能に正確にマップされません。たとえば、1つのSQL文に、カテゴリの異なる複数のアウトラインが存在する可能性がありますが、現在ベースラインに存在するカテゴリはDEFAULTのみです。

アウトラインのカテゴリは、SQL計画ベースラインのモジュールに相当します。表24-1に、アウトラインのカテゴリがどのようにモジュールにマップするかを説明します。

表24-1 アウトラインのカテゴリ

概念

説明

デフォルト値

アウトライン・カテゴリ

ユーザーにより定義されたストアド・アウトライン・セットの分類。

カテゴリを使用して、ストアド・アウトラインの異なるSQL文を管理できます。たとえば、1つの文が、OLTPカテゴリとDWカテゴリのアウトラインを持つことができます。

各SQL文には、1つ以上のストアド・アウトラインがあります。各ストアド・アウトラインは、1つのカテゴリにのみ分類されます。1つの文にはカテゴリの異なる複数のストアド・アウトラインがありますが、各文には1つのカテゴリにつき1つのストアド・アウトラインのみ存在します。

移行の際に、各アウトライン・カテゴリは、SQL計画ベースライン・モジュールにマップされます。

DEFAULT

ベースライン・モジュール

実行されている高度な機能。

SQL計画ベースラインは、1つのモジュールにのみ所属できます。

アウトラインのSQL計画ベースラインへの移行後、デフォルトのモジュール名はアウトライン・カテゴリ名です。

ベースライン・カテゴリ

SQL計画ベースラインには、カテゴリが1つのみ存在します。それはDEFAULTという名前のカテゴリです。ストアド・アウトラインを移行する際に、SQL計画ベースラインのモジュール名は、ストアド・アウトラインのカテゴリ名に設定されます。

1つの文は、DEFAULTカテゴリに複数のSQL計画ベースラインを持つことができます。

DEFAULT

Oracle Databaseでは、ストアド・アウトラインをSQL計画ベースラインに移行する際に、すべてのアウトライン・カテゴリを同名のSQL計画ベースライン・モジュールにマップします。次の図に示すように、アウトラインのOLTPカテゴリは、ベースラインのOLTPモジュールにマップされます。移行後、DEFAULTは、すべてのSQL計画ベースラインを含むスーパー・カテゴリです。

図24-2 DEFAULTカテゴリ

ストアド・アウトラインの移行のためのユーザー・インタフェース

DBMS_SPMパッケージを使用してストアド・アウトラインを移行できます。

表24-2 ストアド・アウトラインの移行に関連するDBMS_SPMファンクション

DBMS_SPMファンクション

説明

MIGRATE_STORED_OUTLINE

既存のストアド・アウトラインを計画ベースラインに移行します。

次のいずれかの形式を使用します。

- アウトライン名、SQLテキスト、アウトライン・カテゴリまたはすべてのストアド・アウトラインを指定します。

- アウトライン名のリストを指定します。

ALTER_SQL_PLAN_BASELINE

SQL文に関連付けられた1つの計画またはすべての計画の属性を変更します。

DROP_MIGRATED_STORED_OUTLINE

SQL計画ベースラインに移行されたストアド・アウトラインを削除します。

DBA_OUTLINESビューでMIGRATEDとマークされたストアド・アウトラインを検出して、データベースから削除します。

ストアド・アウトラインおよび計画ベースラインの動作は、初期化パラメータおよびセッション・パラメータで制御できます。表24-3に、関連パラメータを示します。これらのパラメータ設定の相互作用の説明は、表24-5および表24-6を参照してください。

表24-3 ストアド・アウトラインの移行に関連するパラメータ

初期化またはセッション・パラメータ

説明

パラメータ・タイプ

CREATE_STORED_OUTLINES

セッション中に発行された各問合せのアウトラインを自動的に作成して保存するかどうかを決定します。

初期化パラメータ

OPTIMIZER_CAPTURE_SQL_PLAN_BASELINES

繰返し可能なSQL文の自動認識およびそれらの文のSQL計画ベースラインの生成を有効または無効にします。

初期化パラメータ

OPTIMIZER_USE_SQL_PLAN_BASELINES

SQL管理ベースに格納されたSQL計画ベースラインの使用を有効または無効にします。

初期化パラメータ

USE_STORED_OUTLINES

オプティマイザが実行計画の生成にストアド・アウトラインを使用するかどうかを決定します。

注意: これは初期化パラメータではなく、セッション・パラメータです。

セッション

データベース・ビューを使用して、ストアド・アウトラインの移行に関連する情報にアクセスできます。表24-4に、主なビューを示します。

表24-4 ストアド・アウトラインの移行に関連するビュー

ビュー

説明

DBA_OUTLINES

データベースのすべてのストアド・アウトラインについて説明します。

MIGRATED列は、アウトラインの移行に関する重要な情報を示します。値は、NOT-MIGRATEDおよびMIGRATEDです。MIGRATEDの場合、ストアド・アウトラインは計画ベースラインに移行されており、使用できません。

DBA_SQL_PLAN_BASELINES

特定のSQL文に関して現在作成されているSQL計画ベースラインの情報を表示します。

ORIGIN列は、計画ベースラインがどのように作成されたかを示します。値がSTORED-OUTLINEの場合、アウトラインの移行によってベースラインが作成されたことを示します。

関連項目:

- DBMS_SPMパッケージの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

- CREATE_STORED_OUTLINES初期化パラメータの詳細は、Oracle Databaseリファレンスを参照してください

ストアド・アウトラインの移行の基本ステップ

この項では、PL/SQL APIを使用してストアド・アウトラインを移行する場合の基本ステップを示します。基本手順は次のとおりです。

1. ストアド・アウトラインの移行の準備をします。
移行の前提条件を確認し、移行後の計画ベースラインの動作を決定します。

「ストアド・アウトラインの移行の準備」を参照してください。

2. 次のいずれかを実行します。

- ベースラインに移行して、SQL計画管理の機能を使用します。
「アウトラインの移行によるSQL計画管理機能の使用」を参照してください。

- ストアド・アウトラインの動作を正確に維持して、ベースラインに移行します。
「アウトラインの移行でのストアド・アウトライン動作の保存」を参照してください。

3. 移行後の確認およびクリーンアップを実行します。
「ストアド・アウトラインの移行後のフォーローアップ・タスクの実行」を参照してください。

ストアド・アウトラインの移行の準備

この項では、ストアド・アウトラインの移行の準備について説明します。

ストアド・アウトラインの移行の準備を行うには、次の手順を実行します。

1. SYSDBA権限またはDBMS_SPMパッケージのEXECUTE権限でSQL*Plusをデータベースに接続します。
たとえば、オペレーティング・システム認証を使用してデータベースにSYSとしてログオンするには、次のコマンドを実行します。

% sqlplus /nolog
SQL> CONNECT / AS SYSDBA

2. データベースのストアド・アウトラインの問合せを実行します。
次の例では、SQL計画ベースラインに移行されていないすべてのストアド・アウトラインを問い合せます。

SELECT NAME, CATEGORY, SQL_TEXT
FROM   DBA_OUTLINES
WHERE  MIGRATED = 'NOT-MIGRATED';

3. どのストアド・アウトラインが次の前提条件を満たして移行の対象となるかを判断します。

- 文は、ランタイムのINSERT AS SELECT文ではない。

- 文は、リモート・オブジェクトを参照していない。

- この文は、プライベート・ストアド・アウトラインではない。

4. すべてのアウトラインを移行するか、指定したストアド・アウトラインか、指定したアウトライン・カテゴリに属するアウトラインかを決定します。
一部のアウトラインを移行する場合は、移行するアウトラインまたはカテゴリを指定します。

5. SQL計画ベースラインに移行するストアド・アウトラインで固定計画を使用するか、非固定計画を使用するかを決定します。

- 固定計画
固定計画は、固定されています。固定計画が、計画ベースラインに格納されたヒントを使用して再生可能な計画である場合、オプティマイザは、固定でない計画ベースラインよりも最小コストの固定計画ベースラインを常に選択します。本質的に、固定計画ベースラインは、有効なヒントを含むストアド・アウトラインとして機能します。

計画ベースラインに格納されたヒントに基づいて文を解析し、計画ベースラインと同じ計画ハッシュ値を使用して計画を作成できる場合、固定計画は再生可能です。1つ以上のヒントが無効になった場合、同じ計画ハッシュ値を使用して計画を作成することはできません。この場合、計画は非再生可能です。

ヒントを使用して解析したとき、固定計画を再生できなかった場合、オプティマイザは別の計画を選択します。次のいずれかを選択できます。

- SQL計画ベースラインの別の計画

- オプティマイザによって作成された現在のコストベースの計画

場合によっては、計画が異なるためにパフォーマンスが低下し、SQLチューニングが必要になります。

- 非固定計画
計画ベースラインに固定計画が含まれていない場合、SQL計画管理は、SQL文の計画を選択する際に、計画を同等に検討します。

6. 実際の移行を開始する前に、Oracleデータベースが次の前提条件を満たしていることを確認します。

- データベースはEnterprise Editionである。

- データベースはオープンしている必要があり、一時停止状態であってはならない。

- データベースは、制限付きアクセス(DBA)、読取り専用または移行モードであってはならない。

- Oracle Call Interface (OCI)が使用可能である。

関連項目:

- 管理者権限の詳細は、『Oracle Database管理者ガイド』を参照してください。

- DBA_OUTLINESビューの詳細は、『Oracle Databaseリファレンス』を参照してください。

アウトラインの移行によるSQL計画管理機能の使用

このタスクの目的は、次のとおりです。

- 移行後、SQL文に対して同じ固定計画を適用するのではなく、SQL計画管理で計画ベースラインのすべての計画から選択できるようにする。

- ベースラインに新しい計画を追加して、データベースの変更があった場合にSQL計画ベースラインが進化できるようにする。

前提条件

このチュートリアルでは、次のことが前提となっています。

- すべてのアウトラインを移行する。
特定のアウトラインを移行する場合、DBMS_SPM.MIGRATE_STORED_OUTLINEファンクションの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

- ベースラインのモジュール名と移行するアウトラインのカテゴリ名を同じ名前にする。

- SQL計画を固定しない。
デフォルトでは、生成される計画は固定ではなく、SQL計画管理では、SQL文の計画を選択する際にすべての計画を同等に検討します。この状況により、計画を改良する拡張機能では、SQL文の新しい計画を取得し、パフォーマンスを検証して新しい計画を計画ベースラインに受け入れることが可能になります。

ストアド・アウトラインをSQL計画ベースラインに移行するには、次の手順を実行します。

1. 適切な権限でSQL*Plusをデータベースに接続します。

2. PL/SQLファンクションMIGRATE_STORED_OUTLINEをコールします。
次のPL/SQLブロック・サンプルは、すべてのストアド・アウトラインを固定ベースラインに移行します。

DECLARE
my_report CLOB;
BEGIN
my_outlines := DBMS_SPM.MIGRATE_STORED_OUTLINE(
attribute_name => 'all' );
END;
/

関連項目:

- DBMS_SPMパッケージの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

- ALTER SYSTEM文の詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

アウトラインの移行でのストアド・アウトライン動作の保存

ストアド・アウトラインをSQL計画ベースラインに移行し、固定計画ベースラインを作成して元のストアド・アウトラインの動作を保持できます。

固定計画は、同じSQL文に対する他の計画よりも優先順位が高くなります。計画が固定されている場合、計画ベースラインは進化できません。計画ベースラインに固定計画が含まれていると、新しい計画は追加されません。

前提条件

このチュートリアルでは、次のことが前提となっています。

- firstrowというカテゴリのストアド・アウトラインのみを移行する。

- ベースラインのモジュール名と移行するアウトラインのカテゴリ名を同じ名前にする。

ストアド・アウトラインを計画ベースラインに移行するには、次の手順を実行します。

1. 適切な権限でSQL*Plusをデータベースに接続します。

2. PL/SQLファンクションMIGRATE_STORED_OUTLINEをコールします。
次のPL/SQLブロック・サンプルは、firstrowカテゴリのストアド・アウトラインを固定ベースラインに移行します。

DECLARE
my_report CLOB;
BEGIN
my_outlines := DBMS_SPM.MIGRATE_STORED_OUTLINE(
attribute_name => 'category',
attribute_value => 'firstrow',
fixed => 'YES' );
END;
/

移行後、SQL計画ベースラインのモジュールはfirstrow、カテゴリはDEFAULTです。

関連項目:

- DBMS_SPM.MIGRATE_STORED_OUTLINEファンクションの構文およびセマンティクスは、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください

- ALTER SYSTEM文の詳細は、『Oracle Database SQL言語リファレンス』を参照してください

ストアド・アウトラインの移行後のフォーローアップ・タスクの実行

アウトラインをSQL計画ベースラインに移行した後、フォローアップ作業を実行する必要があります。

このタスクの目的は、次のとおりです。

- SQL計画ベースラインに移行されたストアド・アウトラインで、ストアド・アウトラインではなく、計画ベースラインを使用するようにデータベースを構成する。

- ストアド・アウトラインではなく、SQL計画ベースラインを作成して、今後のSQL文で使用する。

- SQL計画ベースラインに移行されたストアド・アウトラインを削除する。

この項では、ストアド・アウトラインおよび計画ベースラインに関連する初期化パラメータの設定について説明します。OPTIMIZER_CAPTURE_SQL_PLAN_BASELINESおよびCREATE_STORED_OUTLINES初期化パラメータは、ストアド・アウトラインおよびSQL計画ベースラインを作成する方法および時期を指定します。表24-5に、これらのパラメータ間の相互作用を示します。

表 24-5 アウトラインおよびベースラインの作成

CREATE_STORED_OUTLINES初期化パラメータ

OPTIMIZER_CAPTURE_SQL_PLAN_BASELINES初期化パラメータ

データベースの動作

false

false

SQL文を実行する際に、ストアド・アウトラインもSQL計画ベースラインも作成されません。

false

true

繰返し可能なSQL文の自動認識およびこれらの文のSQL計画ベースラインの生成は有効です。SQL文を実行する際に、その文に対してDEFAULTというカテゴリ名の新規SQL計画ベースラインのみが作成されます(存在しない場合)。

true

false

セッション中に発行された各問合せのアウトラインが自動的に作成され、保存されます。SQL文を実行する際に、その文に対してDEFAULTというカテゴリ名の新規ストアド・アウトラインのみが作成されます(存在しない場合)。

category

false

SQL文を実行する際に、その文に対して指定されたカテゴリ名の新規ストアド・アウトラインのみが作成されます(存在しない場合)。

true

true

セッション中に発行された各問合せのアウトラインが自動的に作成され、保存されます。繰返し可能なSQL文の自動認識およびこれらの文のSQL計画ベースラインの生成も有効です。

SQL文を実行する際に、DEFAULTというカテゴリ名のストアド・アウトラインおよびSQL計画ベースラインが作成されます。

category

true

セッション中に発行された各問合せのアウトラインが自動的に作成され、保存されます。繰返し可能なSQL文の自動認識およびこれらの文のSQL計画ベースラインの生成も有効です。

SQL文を実行する際に、指定されたカテゴリ名のストアド・アウトラインが作成され、DEFAULTというカテゴリ名のSQL計画ベースラインが作成されます。

USE_STORED_OUTLINESセッション・パラメータ(これは初期化パラメータではない)およびOPTIMIZER_USE_SQL_PLAN_BASELINES初期化パラメータは、ストアド・アウトラインおよび計画ベースラインの使用方法を指定します。表24-6に、これらのパラメータの相互作用を示します。

表24-6 ストアド・アウトラインおよびSQL計画ベースラインの使用方法

USE_STORED_OUTLINESセッション・パラメータ

OPTIMIZER_USE_SQL_PLAN_BASELINES初期化パラメータ

データベースの動作

false

false

SQL文の計画を選択する際に、ストアド・アウトラインも計画ベースラインも使用しません。

false

true

SQL文の計画を選択する際に、SQL計画ベースラインのみを使用します。

true

false

SQL文の計画を選択する際に、DEFAULTというカテゴリ名のストアド・アウトラインを使用します。

category

false

SQL文の計画を選択する際に、指定されたカテゴリ名のストアド・アウトラインを使用します。

指定されたカテゴリ名のストアド・アウトラインが存在しない場合は、DEFAULTカテゴリのストアド・アウトラインを使用します(存在する場合)。

true

true

SQL文の計画を選択する際に、計画ベースラインよりもストアド・アウトラインが優先されます。

その文にDEFAULTというカテゴリ名のストアド・アウトラインが存在し、適用可能な場合は、ストアド・アウトラインを適用します。それ以外の場合は、SQL計画ベースラインを使用します。ただし、ストアド・アウトラインのプロパティがMIGRATEDの場合は、アウトラインを使用せずに対応するSQL計画ベースラインを使用します(存在する場合)。

category

true

SQL文の計画を選択する際に、計画ベースラインよりもストアド・アウトラインが優先されます。

その文に、指定されたカテゴリ名またはDEFAULTというカテゴリ名のストアド・アウトラインが存在し、適用可能な場合は、ストアド・アウトラインを適用します。それ以外の場合は、SQL計画ベースラインを使用します。ただし、ストアド・アウトラインのプロパティがMIGRATEDの場合は、アウトラインを使用せずに対応するSQL計画ベースラインを使用します(存在する場合)。

前提条件

このチュートリアルでは、次のことが前提となっています。

- ストアド・アウトラインの移行の基本ステップが完了している。

- 一部のストアド・アウトラインは、Oracle Database 10gより前のリリースで作成されている可能性がある。
Oracle Database 10gより前のリリースでは、ローカル・ヒント形式のヒントを使用しています。移行後、計画ベースラインに格納されたヒントは、Oracle Database 10gで導入されたグローバル・ヒント形式を使用します。

移行後に、データベースを適切な状態に設定するには、次の手順を実行します。

1. 適切な権限でSQL*Plusをデータベースに接続して、移行によってSQL計画ベースラインが作成されていることを確認します。
計画が使用可能であり、承認されていることを確認します。たとえば、次の問合せを入力します(サンプル出力の一部が含まれます)。

SELECT SQL_HANDLE, PLAN_NAME, ORIGIN, ENABLED, ACCEPTED, FIXED, MODULE
FROM   DBA_SQL_PLAN_BASELINES;

SQL_HANDLE                PLAN_NAME  ORIGIN         ENA ACC FIX MODULE
------------------------- ---------- -------------- --- --- --- ------
SYS_SQL_f44779f7089c8fab  STMT01     STORED-OUTLINE YES YES NO  DEFAULT
.
.
.

2. オプションとして、SQL計画ベースラインの属性を変更します。
たとえば、次の文を使用して、指定したSQL文のベースラインのステータスをfixedに変更します。

DECLARE
v_cnt PLS_INTEGER;
BEGIN
v_cnt := DBMS_SPM.ALTER_SQL_PLAN_BASELINE(
sql_handle=>'SYS_SQL_f44779f7089c8fab',
attribute_name=>'FIXED',
attribute_value=>'NO');
DBMS_OUTPUT.PUT_LINE('Plans altered: ' || v_cnt);
END;
/

3. 元のストアド・アウトラインのステータスを確認します。
たとえば、次の問合せを入力します(サンプル出力の一部が含まれます)。

SELECT NAME, OWNER, CATEGORY, USED, MIGRATED
FROM   DBA_OUTLINES
ORDER BY NAME;

NAME       OWNER      CATEGORY   USED   MIGRATED
---------- ---------- ---------- ------ ------------
STMT01     SYS        DEFAULT    USED   MIGRATED
STMT02     SYS        DEFAULT    USED   MIGRATED
.
.
.

4. SQL計画ベースラインに移行されたすべてのストアド・アウトラインを削除します。
たとえば、次の文を使用して、DBA_OUTLINESのMIGRATEDステータスのすべてのストアド・アウトラインを削除します。

DECLARE
v_cnt PLS_INTEGER;
BEGIN
v_cnt := DBMS_SPM.DROP_MIGRATED_STORED_OUTLINE();
DBMS_OUTPUT.PUT_LINE('Migrated stored outlines dropped: ' || v_cnt);
END;
/

5. 初期化パラメータを次のように設定します。

- SQL文を実行する際に、計画ベースラインを作成し、ストアド・アウトラインを作成しないように設定します。

- 同等のSQL計画ベースラインが存在しない場合、ストアド・アウトラインのみを使用するように設定します。

たとえば、次のSQL文は、SQL文を実行する際に、ストアド・アウトラインではなくSQL計画ベースラインを作成するようデータベースに指示します。また、allrowsまたはDEFAULTカテゴリのストアド・アウトラインは、それが存在し、SQL計画ベースラインに移行されていない場合にのみ適用するようデータベースに指示しています。それ以外の場合は、かわりにSQL計画ベースラインを適用します。

ALTER SYSTEM
SET CREATE_STORED_OUTLINE = false SCOPE = BOTH;

ALTER SYSTEM
SET OPTIMIZER_CAPTURE_SQL_PLAN_BASELINES = true SCOPE = BOTH;

ALTER SYSTEM
SET OPTIMIZER_USE_SQL_PLAN_BASELINES = true SCOPE = BOTH;

ALTER SESSION
SET USE_STORED_OUTLINES = allrows SCOPE = BOTH;

関連項目:

- ストアド・アウトラインの移行の基本ステップ

- DBMS_SPMパッケージの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

- CREATE_STORED_OUTLINES初期化パラメータの詳細は、Oracle Databaseリファレンスを参照してください

A 索引および表クラスタに関するガイドライン

この付録では、索引およびクラスタを使用してパフォーマンスを強化できる、または低下させるデータ・アクセス方法の概要を説明します。

この付録の内容は次のとおりです。

- 索引パフォーマンスのチューニングに関するガイドライン

- パフォーマンスを考慮したファンクション索引の使用方法に関するガイドライン

- パフォーマンスを考慮したパーティション索引の使用方法に関するガイドライン

- パフォーマンスを考慮した索引構成表の使用方法に関するガイドライン

- パフォーマンスを考慮したビットマップ索引の使用方法に関するガイドライン

- パフォーマンスを考慮したビットマップ結合索引の使用方法に関するガイドライン

- パフォーマンスを考慮したドメイン索引の使用方法に関するガイドライン

- 表クラスタの使用に関するガイドライン

- パフォーマンスを考慮したハッシュ・クラスタの使用方法に関するガイドライン

索引パフォーマンスのチューニングに関するガイドライン

ここでは、以下の項目について説明します。

- 論理構造のチューニングに関するガイドライン

- SQLアクセス・アドバイザの使用方法に関するガイドライン

- 索引を付ける列と式の選択に関するガイドライン

- コンポジット索引の選択に関するガイドライン

- 索引を使用するSQL文の記述に関するガイドライン

- 索引を使用しないSQL文の記述に関するガイドライン

- 索引の再作成に関するガイドライン

- 索引の縮小に関するガイドライン

- 一意でない索引による一意性の規定の使用方法に関するガイドライン

論理構造のチューニングに関するガイドライン

書込み集中型アプリケーションでは、索引のメンテナンスにCPUとI/Oリソースが大量に必要となる場合があります。

問合せの最適化により、問合せの実行における非選択的索引の使用を回避できますが、SQLエンジンは、索引が問合せで使用されるかどうかにかかわらず、表に対して定義されたすべての索引を継続的にメンテナンスする必要があります。したがって、必要がないかぎり索引を作成しないでください。

最適なパフォーマンスを保つために、アプリケーションで使用していない索引を削除してください。使用されていない索引は、典型的なワークロードのかかる期間にわたってALTER INDEX MONITORING USAGE機能を使用することで検出できます。この監視機能は、索引が使用されたかどうかを記録します。サンプリングした負荷以外の負荷で使用されている索引を削除しないように、典型的な負荷を監視していることを確認してください。

また、アプリケーション内では、文の実行計画の調査ですぐには明らかにならない索引の使用方法もあります。その例が、共有ロックが子表上に取り出されないようにする親表上の外部キー索引です。

新しい索引を作成して文のチューニングを行うかどうかを決定する場合、EXPLAIN PLAN文を使用して、アプリケーションの実行時にオプティマイザがこれらの索引を使用するかどうかを調べることもできます。新しい索引を作成して現在解析中の文をチューニングする場合、Oracle Databaseはその文を無効にします。

その文が次に解析されるとき、オプティマイザは、新しい索引を使用する可能性のある新しい実行計画を自動的に選択します。新しい索引をリモート・データベース上に作成して分散型の文をチューニングする場合は、その文が次に解析されるとき、オプティマイザがこれらの索引について検討します。

索引を作成して、ある文をチューニングした場合、他の文の実行計画に対するオプティマイザの選択に影響を及ぼす場合があります。たとえば、ある文によって使用される索引を作成した場合、オプティマイザは、アプリケーションの他の文に対しても、その索引の使用を選択する場合があります。このため、最初にチューニング対象と判断した文をチューニングした後、アプリケーションのパフォーマンスおよび実行計画を再検査し、SQLトレース機能を利用します。

関連項目:

- ALTER INDEX MONITORING USAGE文の構文およびセマンティクスの詳細は、Oracle Database SQL言語リファレンスを参照してください

- 外部キーの詳細は、Oracle Database開発者ガイドを参照してください

SQLアクセス・アドバイザの使用方法に関するガイドライン

SQLアクセス・アドバイザは、どの索引が必要であるかを手動で判別する作業に対する代替機能です。このアドバイザを、Oracle Enterprise Manager Cloud Control (Cloud Control)から起動するか、DBMS_ADVISORパッケージAPIで実行すると、索引セットが推奨されます。SQLアクセス・アドバイザはワークロードの使用を推奨するか、または指定のスキーマに関する仮定的なワークロードを生成します。

ワークロードのソースには、SQLキャッシュの現在の内容、ユーザー定義のSQL文のセットまたはSQLチューニング・セットなどを使用できます。ワークロードを指定すると、SQLアクセス・アドバイザにより推奨事項のセットが生成され、実装する索引を選択できます。SQLアクセス・アドバイザは、手動で実行またはCloud Controlを介して自動的に実行できる実装のためのスクリプトを提供します。

関連項目:

「SQLアクセス・アドバイザについて」

索引を付ける列と式の選択に関するガイドライン

キーは、索引を付ける列または式です。

次のガイドラインに従って、索引を付けるキーを選択します。

- WHERE句に頻出するキーの索引付けを検討します。

- SQL文で表の結合に頻繁に使用されるキーの索引付けを検討します。

- 選択性の高い索引キーを選択します。索引の選択性は、索引付けするキー値と同じ値を持つ行が表に含まれる割合です。同じ値を持つ行がほとんどない場合、索引の選択性は最適です。

注意:

整合性制約で定義されたキーおよび一意キーと主キーの式では、Oracle Databaseが自動的に索引を作成するか、既存の索引が使用されます。

データ配分に偏りがあるため、他の値と比較して1つまたは2つの値の発生が非常に少ない場合、選択性の低い列の索引付けが役立つ場合もあります。

- 個別値をほとんど持たないキーまたは式には、標準のBツリー索引を使用しません。通常、そのようなキーや式は非選択性であるため、頻繁に選択されるキー値がその他のキー値に比べてそれほど多くない場合を除くと、パフォーマンスは最適化されません。このような場合には、ビットマップ索引を使用すると効果的です。ただし、同時実行性の高いOLTPアプリケーションのように、索引が頻繁に変更される場合には向きません。

- 変更が頻繁に行われる列は、索引付けしないでください。索引付きの列を修正するUPDATE文および索引付きの表を修正するINSERT文とDELETE文では、索引がない場合よりも、処理に長い時間が必要となります。このようなSQL文では、索引のデータおよび表のデータの変更が必要です。また、追加のUNDOおよびREDOも作成されます。

- ファンクションや演算子を含むWHERE句のみに指定されるキーには索引を付けません。索引付きのキーにMINやMAX以外のファンクションや演算子を使用するWHERE句は、ファンクション索引を除く索引を使用するアクセス・パスを選択しません。

- 同時実行の数多くのINSERT文およびUPDATE文、DELETE文が親表と子表にアクセスする場合、参照整合性制約の外部キーに索引を付けることを検討します。このような索引を使用すると、子表を共有ロックせずに親表でUPDATEおよびDELETEを実行できます。

- 索引を付けるキーを選択するとき、問合せのパフォーマンス向上が、INSERT、UPDATE、DELETE文のパフォーマンス損失および索引を格納するために必要となる領域の使用に見合う価値があるかどうか検討してください。SQL文の処理時間を索引の有無によって実際に比較することをお薦めします。SQLトレース機能で処理時間を測定できます。

関連項目:

ロックへの外部キーの影響の詳細は、Oracle Database概要を参照してください

コンポジット索引の選択に関するガイドライン

コンポジット索引には複数のキー列が含まれます。

コンポジット索引には、次のような単一列索引を上回る利点があります。

- 選択性の向上
選択性の低い複数の列または式を組み合せることで、選択性の高いコンポジット索引を作成できる場合があります。

- I/Oの削減
Oracle Databaseでは、問合せで選択されるすべての列がコンポジット索引に含まれている場合、表にアクセスすることなく、索引でこれらの値を戻すことができます。

SQL文の構成メンバーが索引の先頭部分を使用する場合、その文はコンポジット索引を含むアクセス・パスを使用できます。

注意:

このことは、索引スキップ・スキャンには現在、該当しなくなっています。

索引の先頭部分とは、その索引を作成したCREATE INDEX文で列リストの先頭から連続的に指定された1つ以上の列の組合せのことです。次のCREATE INDEX文について考えてみます。

CREATE INDEX comp_ind
ON table1(x, y, z);

- x、xy、xyzの各列の組合せは、索引の先頭部分です。

- yz、y、zの各列の組合せは、索引の先頭部分ではありません。

関連項目:

「索引スキップ・スキャン」

コンポジット索引のキーの選択に関するガイドライン

コンポジット索引を構成するキーを選択するために、次のガイドラインに従ってください。

- AND演算子で結合してWHERE句の条件で頻繁に使用されるキー、特に、各キーの個別の選択性と比較して、キーを組み合せることで選択性が高くなる場合、コンポジット索引の作成を検討します。

- 複数の問合せが1つ以上のキー値に基づいて同じキー・セットを選択する場合、これらのキーのすべてを含むコンポジット索引を作成することを検討します。

また、索引を作成する際の一般的なパフォーマンスの利点およびトレードオフに関する前述のガイドラインも検討してください。

コンポジット索引のキーの順序付けに関するガイドライン

コンポジット索引内でのキーの順序を指定するために次のガイドラインに従ってください。

- WHERE句で使用されるキーが先頭部分を構成するように、索引を作成してください。

- 一部のキーがWHERE句で頻繁に使用される場合は、これらのキーのみを使用する文が索引を使用できるように、頻繁に選択されるキーが先頭部分を構成するように索引を作成します。

- すべてのキーがWHERE句で均等に使用され、そのキーの1つでデータが物理的に順序付けられている場合には、そのキーをコンポジット索引の先頭にしてください。

索引を使用するSQL文の記述に関するガイドライン

索引を作成しても、単に索引が存在するのみでは、オプティマイザはその索引を使用するアクセス・パスを選択できません。オプティマイザは、SQL文にアクセス・パスを使用可能にする構造が含まれている場合にかぎり、そのようなアクセス・パスを選択できます。索引アクセス・パスを使用するというオプションを問合せオプティマイザで可能にするには、文が索引アクセス・パスを使用可能にする構文になっていることを確認してください。

索引を使用しないSQL文の記述に関するガイドライン

場合によって、SQL文が索引アクセス・パスを使用しないようにできます。たとえば、索引の選択性が高くなく、全表スキャンのほうが効率的であるとわかっています。

そのような索引アクセス・パスを使用可能にする条件が文に含まれている場合は、次に示す方法の1つを使用して、オプティマイザに全表スキャンを使用するように強制できます。

- NO_INDEXヒントを使用して特定索引の使用を禁止にし、問合せオプティマイザに最大限の柔軟性を持たせることができます。

- FULLヒントを使用し、オプティマイザに対して索引スキャンのかわりに全表スキャンを選択するように指示します。

- INDEXヒントまたはINDEX_COMBINEヒントを使用し、オプティマイザに、ある索引(またはリストされている索引セット)を別の索引(または索引セット)のかわりに使用するように指示します。

パラレル実行は、索引を効果的に利用します。このオプションは、パラレル索引レンジ・スキャンを実行しませんが、ネステッド・ループ・ジョインをパラレル実行するためにパラレル索引参照を実行します。索引の選択性が高い(各索引エントリの行数が少ない)場合は、パラレル表スキャンよりも順次索引参照をお薦めします。

関連項目:

NO_INDEX、FULL、INDEX、INDEX_COMBINEおよびヒントの詳細は、「オプティマイザへの影響」を参照してください

索引の再作成に関するガイドライン

索引を縮小し分断化された領域を最小化するため、または索引の記憶特性を変更するために索引を再作成する場合があります。既存の索引のサブセットとなる新しい索引を作成する場合、または新しい記憶特性を使用して既存の索引を再構築する場合、Oracle Databaseでは、実表ではなく既存の索引を使用することで索引作成のパフォーマンスが向上する場合があります。

ただし、既存の索引ではなく、実表を使用することが有効な場合もあります。多くのDMLが実行された表の索引を考えてみてください。DMLのために索引のサイズが大きくなり、各ブロックが50%以下しか満たされなくなる場合があります。索引が表のほとんどの列を参照している場合、索引が表よりも大きくなりかねません。その場合は、索引よりも実表を使用した方が、索引の再作成が速くできます。

既存の索引を再編成または縮小するため、または既存の索引の記憶特性を変更するには、ALTER INDEX . . . REBUILD文を使用します。REBUILD文は、新しい索引の基礎として既存の索引を使用します。STORAGE(エクステントの割当て用)、TABLESPACE(索引を新しい表領域に移動する)およびINITRANS(エントリの最初の数を変更する)などのすべての索引記憶用の文がサポートされています。

ALTER INDEX . . . REBUILDは、高速全体スキャン機能を使用するので、通常は索引を削除して再作成するよりも高速です。この文は、マルチブロックI/Oを使用して索引ブロックをすべて読み取ってから、ブランチ・ブロックを廃棄します。さらに、このアプローチには、再作成の実行中の問合せには、旧索引を利用できるという利点があります。

関連項目:

CREATE INDEX文とALTER INDEX文、および索引の再作成に関する制限の詳細は、『Oracle Database SQL言語リファレンス』を参照してください

索引の縮小に関するガイドライン

COALESCEオプションを持つALTER INDEX文を使用して索引のリーフ・ブロックを結合できます。

このオプションでは、索引のリーフ・レベルを結合して空きブロックにし、再利用できます。また、索引をオンラインで再作成することもできます。

関連項目:

この文の構文の詳細は、『Oracle Database SQL言語リファレンス』および『Oracle Database管理者ガイド』を参照してください

一意でない索引による一意性の規定の使用方法に関するガイドライン

UNIQUE制約、またはPRIMARY KEY制約の一意性の側面に関して、一意性を規定するために、表の既存の一意でない索引を使用できます。このアプローチの利点は、制約が使用禁止にされているときでも索引が使用可能であり、妥当であるということです。したがって、使用禁止にされているUNIQUE制約またはPRIMARY KEY制約を使用可能にするために、その制約に対応付けられている一意索引を再作成する必要はありません。これにより、大規模表で操作を使用可能にする際に時間を大幅に節約できます。

さらに、一意でない索引を使用して一意性を規定すると、索引の重複を排除できます。主キー列がコンポジット索引の接頭辞として組み込まれている場合、その列に対する一意索引は不要です。制約を使用可能または規定するときに、既存の索引を使用できます。また、索引を複製しないので、領域を大幅に節約できます。ただし、既存の索引がパーティション化されている場合は、索引のパーティション・キーもUNIQUEキーのサブセットである必要があります。サブセットでない場合、Oracle Databaseでは、一意索引が追加作成され、制約を規定します。

ENABLE NOVALIDATE制約の使用方法に関するガイドライン

ENABLE NOVALIDATE制約は、新しいデータのENABLE VALIDATE制約と同じように動作します。制約をENABLE NOVALIDATE状態にすることは、表に入力された新規データが制約に準拠する必要があることを意味します。既存のデータはチェックされません。制約をENABLE NOVALIDATE状態にすることにより、表をロックしないで制約を使用可能にできます。

制約を使用禁止から使用可能に変更する場合、表をロックする必要があります。使用可能にする際に、表に対する操作が制約に準拠していることを確認できないため、新しいDML、問合せまたはDDLは実行できません。ENABLE NOVALIDATE状態では、制約に違反する操作を表に対して実行できません。

表のパラレル一貫読取り問合せにより、ENABLE NOVALIDATE制約を検証して、制約に違反するデータがあるかどうかを判断できます。ロックされないため、表の読取りも書込みも使用可能化操作によってブロックされません。さらに、ENABLE NOVALIDATE制約はパラレルで検査できます。複数の制約を同時に検査し、パラレル問合せを使用して各制約の妥当性をチェックできます。

制約と索引を持つ表を作成する手順は次のとおりです。

1. 制約を持つ表を作成します。
NOT NULL制約には名前を付けなくても構いませんが、使用可能かつ検証済で作成してください。他のすべての制約(CHECK、UNIQUE、PRIMARY KEYおよびFOREIGN KEY)に名前を付け、使用禁止で作成します。

注意:

デフォルトでは、制約はENABLED状態で作成されます。

2. 旧データを表にロードします。

3. 制約に必要な索引を含め、すべての索引を作成します。

4. 未検査の制約をすべて使用可能にします。これは、外部キーの前に主キーに対して行ってください。

5. ユーザーがデータを問合せおよび変更できるようにします。

6. 制約ごとに別個のALTER TABLE文を使用して、すべての制約を検証します。これは、外部キーの前に主キーに対して行ってください。次に例を示します。

CREATE TABLE t (a NUMBER CONSTRAINT apk PRIMARY KEY DISABLE,
b NUMBER NOT NULL);
CREATE TABLE x (c NUMBER CONSTRAINT afk REFERENCES t DISABLE);

ここで、表tにデータをロードします。

CREATE UNIQUE INDEX tai ON t (a);
CREATE INDEX tci ON x (c);
ALTER TABLE t MODIFY CONSTRAINT apk ENABLE NOVALIDATE;
ALTER TABLE x MODIFY CONSTRAINT afk ENABLE NOVALIDATE;

この時点で、ユーザーは、表tでINSERT、UPDATE、DELETEおよびSELECTの各操作を実行できます。

ALTER TABLE t ENABLE CONSTRAINT apk;
ALTER TABLE x ENABLE CONSTRAINT afk;

これで、制約はENABLE VALIDATEになりました。

関連項目:

整合性制約の詳細は、『Oracle Database概要』を参照してください。

パフォーマンスを考慮したファンクション索引の使用方法に関するガイドライン

ファンクション索引には、ファンクション(たとえば、UPPERファンクション)で変換される列、または式(たとえば、col1 + col2)に含まれている列があります。

ファンクション索引は、頻繁に実行されるSQL文のWHERE句やORDER BY句の中に変換列(または式の中の列)が含まれている場合に有益です。変換された列または式でファンクション索引を定義すると、データベースは、そのファンクションまたは式をWHERE句またはORDER BY句で使用するときに、その索引を使用できます。このようにして、SELECT文およびDELETE文を処理する際に式の計算を回避できます。

Oracle Databaseでは、降順の索引は、ファンクション索引として処理されます。DESCのマークのある列は、降順でソートされます。

たとえば、UPPER(column_name)キーワードまたはLOWER(column_name)キーワードで定義されたファンクション索引を使用すると、大/小文字を区別しない検索ができます。次の文で索引を発行したとします。

CREATE INDEX uppercase_idx ON employees (UPPER(last_name));

前述の索引を使用すると、次のような問合せの処理が容易になります。

SELECT *
FROM   employees
WHERE  UPPER(last_name) = 'MARKSON';

関連項目:

- ファンクション索引の使用の詳細は、『Oracle Database開発ガイド』および『Oracle Database管理者ガイド』を参照してください

- CREATE INDEX文の詳細は、Oracle Database SQL言語リファレンスを参照してください

パフォーマンスを考慮したパーティション索引の使用方法に関するガイドライン

パーティション表と同様に、パーティション索引を使用すると、管理性、可用性、パフォーマンスおよびスケーラビリティが向上します。個別にパーティション化(グローバル索引)することも、表のパーティション化メソッド(ローカル索引)に自動的にリンクすることも可能です。

Oracle Databaseでは、レンジ・パーティション化およびハッシュ・パーティション化されたグローバル索引をサポートします。レンジ・パーティション化されたグローバル索引では、各索引パーティションに、パーティション・バウンドで定義された値が含まれます。ハッシュ・パーティション化されたグローバル索引では、各パーティションに、Oracle Databaseハッシュ関数により決定された値が含まれます。

マルチユーザーのOLTP環境で、索引内の少数のリーフ・ブロックに競合が多い場合、ハッシュ・メソッドにより索引のパフォーマンスが向上します。OLTPアプリケーションによっては、索引の右端にのみ索引が挿入される場合があります。この状況は、単調に増える列に対して索引を定義した場合に起こります。この状況では、索引ページ、バッファ、更新のラッチおよび追加索引メンテナンス・アクティビティの競合により、索引の右端がホット・スポットとなり、パフォーマンスが低下します。

ハッシュ・パーティション化されたグローバル索引では、索引エントリはパーティション・キーおよびパーティション数に基づいて異なるパーティションにハッシュされます。これにより、定義済のパーティション数全体に競合が拡散され、スループットが向上します。ハッシュ・パーティション化されたグローバル索引を使用すると、バッファ・ラッチの競合が複数のパーティションにわたって拡散されるため、大規模PDMLとして大きなファクト表に実行されるTPC-Hリフレッシュ関数には有効です。

ハッシュ・パーティション化では、索引エントリはOracle Databaseで生成されたハッシュ値に基づいて特定の索引パーティションにマップされます。ハッシュ・パーティション化されたグローバル索引を作成するための構文は、ハッシュ・パーティション表と非常によく似ています。索引パーティション・キーについての等価述語およびIN述語を伴う問合せでは、グローバル・ハッシュ・パーティション索引を効率的に使用して問合せにすばやく回答できます。

関連項目:

グローバル索引表の詳細は、『Oracle Database概要』および『Oracle Database管理者ガイド』を参照してください。

パフォーマンスを考慮した索引構成表の使用方法に関するガイドライン

索引構成表は、表のデータが、対応付けられた索引に保持されるという点で普通の表とは異なります。新しい行の追加、行の更新、行の削除など、表データを変更すると、索引のみが更新されます。データ行は索引に格納されるため、索引構成表では完全一致、範囲検索またはその両方を含む問合せの表データに対するさらに高速なキー・ベースのアクセスが可能になります。

親/子関係は、索引構成表を保証する状況の一例です。たとえば、メンバー表に電話番号を含む子表があるとします。メンバーの電話番号は、時間の経過とともに変更および追加されます。ヒープ構成表では、行は適合するデータ・ブロックに挿入されます。ただし、メンバー表を問い合せる場合、電話番号は常に子表から取得されます。取得の効率性を高めるために、指定のメンバーの電話レコードが互いにデータ・ブロック内の近くに挿入されるように、索引構成表に電話番号を格納できます。

特定の状況では、索引構成表の方がヒープ構成表よりもパフォーマンスの面で利点があります。たとえば、問合せに必要なキャッシュ内のブロック数が比較的少ない場合、データベースではバッファ・キャッシュがより効率的に使用されます。問合せに必要な個別のブロック数が比較的少ない場合は、1回の物理I/Oによって必要なデータがすべて取得されるため、各問合せに必要なI/Oの量はわずかで済みます。

グローバル・ハッシュ・パーティション索引は索引構成表でサポートされており、マルチユーザーのOLTP環境でパフォーマンスが向上します。索引構成表は、関連するデータをまとめて格納する場合、またはデータを特定の順序で物理的に格納する場合に役立ちます。

関連項目:

索引構成表の詳細は、『Oracle Database概要』および『Oracle Database管理者ガイド』を参照してください。

パフォーマンスを考慮したビットマップ索引の使用方法に関するガイドライン

ビットマップ索引は、次のすべての特性を持つ問合せのパフォーマンスを大幅に向上できます。

- カーディナリティが低いか中位である列に関する述語がWHERE句に複数含まれています。

- カーディナリティが低いか中位である列に関する個々の述語が多数の行を選択しています。

- カーディナリティが低いか中位である列の一部または全部に対して、問合せで使用されるビットマップ索引が作成されています。

- 問合せの表に多数の行が含まれています。

複数のビットマップ索引を使用して、単独の表に対する条件を評価できます。このため、ビットマップ索引は、長いWHERE句を含む複合非定型問合せにとって非常に有効です。ビットマップ索引は、集合問合せでもスター・スキーマでの結合の最適化でも最適なパフォーマンスを提供します。

関連項目:

ビットマップ索引の詳細は、『Oracle Database概要』および『Oracle Databaseデータ・ウェアハウス・ガイド』を参照してください

パフォーマンスを考慮したビットマップ結合索引の使用方法に関するガイドライン

単一表のビットマップ索引の他に、ビットマップ結合索引を作成できます。この索引は、複数の表を結合するためのビットマップ索引です。ビットマップ結合索引では、事前に制限事項を実行することで、結合する必要のあるデータ量を削減して領域を節約できます。ビットマップ結合索引は、表の列の値ごとに、別の表の対応する行のROWIDを格納します。データ・ウェアハウス環境では、結合条件は、ディメンション表の主キー列、およびファクト表の外部キー列との間の等価内部結合です。

ビットマップ結合索引は、マテリアライズド結合ビューより格納の効率がはるかによく、事前に結合をマテリアライズする方法の代替手段です。マテリアライズド結合ビューは、ファクト表のROWIDを圧縮しません。

関連項目:

ビットマップ結合索引の例および制限については、『Oracle Databaseデータ・ウェアハウス・ガイド』を参照してください。

パフォーマンスを考慮したドメイン索引の使用方法に関するガイドライン

ドメイン索引は、ユーザー定義の索引タイプで指定された索引作成論理で作成されます。索引タイプは、ドメインの(アプリケーション固有の)索引を管理するルーチンを指定するオブジェクトです。

索引タイプを使用すると、特定の演算子の述部に合うデータに効率よくアクセスできます。通常、ユーザー定義の索引タイプは、Oracle Spatial and Graphオプションのように、Oracle Databaseオプションの一部です。

ドメイン索引の作成と保守で指定できるパラメータは、カートリッジによって異なります。同様に、ドメイン索引のパフォーマンスと記憶域の特性は、カートリッジ固有のマニュアルを参照してください。

次の情報は、適切なカートリッジ・マニュアルを参照してください。

- 索引付けの可能なデータ型

- 使用できる索引タイプ

- 索引タイプで使用できる演算子

- ドメイン索引を作成およびメンテナンスする方法

- 問合せで演算子を最も効率よく使用する方法

- パフォーマンス特性の内容

注意:

索引タイプはCREATE INDEXTYPE文でも作成できます。

関連項目:

spatialデータの索引付けの詳細は、Oracle Spatial and Graph開発者ガイドを参照してください

表クラスタの使用に関するガイドライン

表クラスタは、共通の列を共有し、通常はSQL文で同時に使用されるため、物理的にまとめて格納される1つ以上の表のグループです。

データベースでは、関連する行が物理的にまとめて格納されるため、ディスク・アクセス時間が向上します。表クラスタを作成するには、CREATE CLUSTER文を使用します。
次の場合は、表のクラスタ化を検討します。

- 結合処理で、アプリケーションが表に頻繁にアクセスする場合。

- マスター/ディテール表において、アプリケーションがマスター・レコードを選択してから対応するディテール・レコードを選択することがよくある場合。
ディテール・レコードはマスター・レコードと同じデータ・ブロックに格納されるため、選択する際にそれらがメモリー内に存在している可能性があります。これにより、Oracle Databaseでは、必要なI/O処理が減少します。

- アプリケーションが、同じマスターについて多数のディテール・レコードを選択することがよくある場合。
この場合、ディテール表のみをクラスタに格納します。このようにすれば、同じマスターについて多くの詳細レコードを選択する問合せのパフォーマンスが改善され、マスター表に対する全表スキャンのパフォーマンスも低下させずに済みます。別の方法として、索引構成表を使用する方法があります。

次の場合は、表をクラスタ化しません。

- アプリケーションが表の結合を頻繁には行わない場合、または共通の列の値を頻繁に変更する場合。
Oracle Databaseでは、行のクラスタ・キー値を変更すると、クラスタを維持するために変更された行を別のブロックに移行することが必要になる場合があるため、非クラスタ化表の値を変更する場合よりも時間がかかります。

- アプリケーションが複数の表の1つについてのみ頻繁に全表スキャンを行う場合。
クラスタ化表の全表スキャンに要する処理時間は、非クラスタ化表の全表スキャンよりも長くなる可能性があります。表がまとめて格納されているため、より多くのブロックの読取りが必要になる可能性があります。

- 同じクラスタ・キー値を持つすべての表のデータのブロック数が、1つや2つではない場合。
Oracle Databaseでは、クラスタ化表の行にアクセスする際に、その値を持つ行を含むすべてのブロックを読み取ります。これらの行が複数のブロックを使用している場合、単一行にアクセスすることによって、非クラスタ化表で同じ行にアクセスする場合よりも多くの読取り処理が必要になる場合があります。

- 各クラスタ・キー値の行数が大きく異なっている場合。
カーディナリティの低いキー値の場合には領域が無駄になります。カーディナリティの高いキー値の場合には衝突が発生します。衝突が発生するとパフォーマンスが下がります。

アプリケーションでのクラスタの長所と短所を検討してください。たとえば、結合文のパフォーマンス向上が、クラスタ・キー値を修正する文のパフォーマンス低下を上回る場合もあります。表をクラスタ化した場合と別々に格納した場合について実験して、処理時間を比較してください。

関連項目:

- 表クラスタの詳細は、Oracle Database概要を参照してください

- 表クラスタの作成の詳細は、Oracle Database管理者ガイドを参照してください

パフォーマンスを考慮したハッシュ・クラスタの使用方法に関するガイドライン

ハッシュ・クラスタは、ハッシュ関数をそれぞれの行のクラスタ・キー値に適用することによって、表データをグループ分けします。

同じクラスタ・キー値を持つすべての行が、ディスク上にまとめて格納されます。アプリケーションでのハッシュ・クラスタの長所と短所を検討してください。特定の表について、ハッシュ・クラスタの場合と、索引付きで単独の場合とで実験を行って処理時間を比較してください。

ハッシュ・クラスタを使用する場合を判断するために、次のガイドラインに従ってください。

- 同じ列または列の組合せを使用する等価条件がWHERE句に含まれる場合、WHERE句を持つSQL文により頻繁にアクセスされる表を格納するために、ハッシュ・クラスタが使用されます。この列または列の組合せをクラスタ・キーとして指定します。

- 即時および将来において挿入する行を含め、特定のクラスタ・キー値を持つすべての行を保持するのに必要な領域を判断できる場合は、ハッシュ・クラスタに表を格納します。

- ハッシュ関数の各値に対応する行が特定の列において昇順でソートされる場合、ソートされたクラスタ・データで操作のレスポンス時間が改善される場合は、ソートされたハッシュ・クラスタを使用します。

- 次の場合には、ハッシュ・クラスタに表を格納しません。

- アプリケーションが頻繁に全表スキャンを実行する場合。

- 表が拡大することを見越してハッシュ・クラスタに大きな領域を割り当てる必要がある場合。

全表スキャンでは、いくつかのブロックにはほとんど行が含まれていなくても、ハッシュ・クラスタに割り当てられているブロックをすべて読み取る必要があります。表を単独で格納することによって、全表スキャンにより読み取られるブロック数が減少します。

- アプリケーションがクラスタ・キー値を頻繁に修正する場合、ハッシュ・クラスタに表は格納しません。Oracle Databaseでは、行のクラスタ・キー値を変更すると、クラスタを維持するために変更された行を別のブロックに移行することが必要になる場合があるため、非クラスタ化表の値を変更する場合よりも時間がかかる可能性があります。

このリストの検討事項に基づいた表のハッシングが適切な場合、単一の表をハッシュ・クラスタに格納することは有益です。表が他の表と頻繁に結合されるかどうかにかかわらず同じことが言えます。

関連項目:

- ハッシュ・クラスタの管理方法の詳細は、Oracle Database管理者ガイドを参照してください

- CREATE CLUSTER文の詳細は、Oracle Database SQL言語リファレンスを参照してください

用語集

承認済の計画

SQL計画管理のコンテキストにおいて、SQL文のSQL計画ベースラインに存在する計画であり、オプティマイザで使用できます。承認済の計画には、ヒント・セット、計画のハッシュ値、計画に関連するその他の情報が含まれます。

アクセス・パス

データベースからデータを取得する方法。たとえば、索引を利用した問合せと全表スキャンを利用した問合せでは、使用されるアクセス・パスが異なります。

適応カーソル共有

バインド変数を含む1つの文で複数の実行計画を使用可能にする機能。カーソル共有には「適応」機能があります。つまり、データベースが各実行または各バインド変数値に常に同じ計画を使用することがないように、カーソルがその動作を適応させます。

適応オプティマイザ

実行時の統計に基づいて計画を適応させることを可能にするオプティマイザの機能。

適応問合せ計画

ランタイム条件でオプティマイザ統計が不正確であると示されたため、最適化後に変更される実行計画。適応問合せ計画には様々な組込み計画のオプションがあります。最初の実行時、特定のサブプランがアクティブになる前に、オプティマイザは、どのオプションを使用するかについて最終的な決定を行います。オプティマイザの選択は、この時点までの実行中に行われた監視に基づいています。したがって、適応問合せ計画によって、文の最終計画がデフォルトの計画から変更できるようになります。

適応問合せ最適化

適応オプティマイザが、実行計画に対する実行時の調整を行い、より優れた統計を導くための追加情報を検出できるようにするための一連の機能。適応最適化は、最適な計画を生成するために既存の統計が十分でない場合に役に立ちます。

ADDM

自動データベース診断モニター(ADDM)を参照してください。

アンチ結合

右側の副問合せに一致しない行を戻す結合。たとえば、アンチ結合は従業員のいない部門をリストできます。アンチ結合は、NOT EXISTSまたはNOT INの構成を使用します。

自動データベース診断モニター(ADDM)

ADDMはOracle Databaseに組み込まれている自己診断エンジンです。ADDMで自動ワークロード・リポジトリ(AWR)に取得されたデータが調査および分析され、発生する可能性のあるデータベース・パフォーマンスの問題を判別します。

自動オプティマイザ統計収集

統計がないか失効しているすべてのスキーマ・オブジェクトのオプティマイザ統計を収集するDBMS_STATSパッケージの自動実行。

初期計画の自動取得

データベースで実行される繰返し可能なSQL文のSQL計画ベースラインを自動的に作成するメカニズム。OPTIMIZER_CAPTURE_SQL_PLAN_BASELINES初期化パラメータをtrueに設定することで(デフォルトはfalse)、初期計画の自動取得を有効にします。

繰返し可能なSQL文を参照してください。

自動再最適化

SQL文のその後の実行時に計画を自動的に変更するオプティマイザの機能。自動再最適化は、最適ではない分散メソッドから並列度の不正確な選択まで、オプティマイザの見積りが不正確であるために選択されたすべての最適でない計画を修正できます。

自動SQLチューニング

自動SQLチューニング・アドバイザで実行される動作であり、システム・メンテナンス・ウィンドウで自動化タスクとして実行されます。

自動SQLチューニング・アドバイザ

自動化メンテナンス・タスクとして実行するSQLチューニング・アドバイザ。自動SQLチューニングは自動化メンテナンス・タスクとしてシステムのメンテナンス時に実行され、高負荷SQL文の実行計画を改善する方法を検索します。

SQLチューニング・アドバイザを参照してください。

自動チューニング・オプティマイザ

SQLチューニング・アドバイザで起動されるオプティマイザ。SQLチューニング・モードにおいて、オプティマイザは、追加の分析を実行して、標準モードで生成された計画をさらに改善できるかどうかをチェックします。オプティマイザの出力は、実行計画ではなく、さらに優れた計画を生成するための一連のアクションと、その理論的根拠および予測されるメリットを示します。

自動ワークロード・リポジトリ(AWR)

問題の検出および自己チューニングを目的として、Oracle Databaseのコンポーネントに、統計の収集、保持および使用のためのサービスを提供するインフラストラクチャ。

AWR

自動ワークロード・リポジトリ(AWR)を参照してください。

AWRスナップショット

パフォーマンスの比較に使用される特定の期間についてのデータのセット。スナップショットで取得したデルタ値は、時間ごとの各統計に対する変更を示します。収集した統計はメモリーから問い合せます。収集したデータは、レポートおよびビューで表示できます。

ベースライン

AWRのコンテキストにおいて、最適なレベルで動作するデータベースを示すAWRのスナップショット間の間隔。

バインド対応カーソル

バインド値ごとに異なる計画を使用するのに適したバインド依存カーソル。カーソルをバインド対応にした後で、オプティマイザは、バインド値とそのカーディナリティの見積りを基に、今後の実行のための計画を選択します。

バインド依存カーソル

最適な計画がバインド変数の値に依存するカーソルです。データベースは、別の計画が有効であるかどうかを判断するために、別のバインド値を使用するバインド依存カーソルの動作を監視します。

バインド変数

SQL文の中のプレースホルダで、SQL文を正常に実行するために、有効な値または値のアドレスと置換される必要があります。バインド変数を使用すると、実行時に入力データまたはパラメータを受け取るSQL文を作成できます。次の問合せでは、バインド変数としてv_empidを使用します。

SELECT * FROM employees WHERE employee_id = :v_empid;

バインド変数の照合

ハード解析の間にバインド変数の値を参照するオプティマイザの機能。バインド値を照合することにより、まるでリテラルが使用されたかのようにWHERE句条件の選択性を判断することができ、これによって計画が改善されます。

ビットマップ結合索引

2つ以上の表を結合するためのビットマップ索引。

ビットマップ・ピース

ビットマップ索引エントリのサブコンポーネントです。索引付けられた列の値には1つ以上のビットマップ・ピースが含まれる場合があります。データベースはビットマップ・ピースを使用して、ブロックのサイズに比べて大きい索引エントリを分割します。

Bツリー索引

ツリーを上下反転させたような形状の索引。Bツリー索引には、検索用のブランチ・ブロックと、値を格納するリーフ・ブロックの2種類のブロックがあります。リーフ・ブロックには、すべての索引付きデータ値と、実際の行を検索するための対応するROWIDが含まれています。Bはbalanced(バランスが取れた)の略で、これは、すべてのリーフ・ブロックが自動的に同じ深さになるためです。

一括ロード

CREATE TABLE AS SELECTまたはINSERT INTO ... SELECTの操作。

ブッシュ型結合ツリー

内部ノードの右または左の子を結合ノードにできる結合ツリー。ブッシュ型結合ツリーのノードは、両方の子孫が再帰構造を持つことがあります。

カーディナリティ

実行計画で操作によって戻される予想行数または実際の行数。行の総数に対して列の個別値の数が少ない場合は、データのカーディナリティは低くなります。

デカルト結合

1つ以上の表が文中に他の表への結合条件を持たない結合。オプティマイザは、データ・ソースにあるすべての行を、2つのセットのデカルト積を作成しながら、別のデータ・ソースにあるすべての行と結合します。

子カーソル

親カーソルにテキストが格納されている文の計画、コンパイル環境およびその他の情報が含まれるカーソル。親カーソルの番号は0、最初の子の番号は1、のようになります。子カーソルは親カーソルと同じSQLテキストを参照しますが、異なります。たとえば、テキストSELECT * FROM tでの2つの問合せは、tという名前の2つの異なる表を参照する場合に、別のカーソルを使用します。

クラスタ・スキャン

表クラスタへのアクセス・パス。索引クラスタでは、最初に、クラスタ索引をスキャンして、選択された行の1つのROWIDを取得します。次に、このROWIDに基づいて行の位置を特定します。

列グループ

1つの単位として扱われる一連の列。

列グループの統計

1単位として扱われる列グループに収集された拡張統計。

列統計

最適な実行計画を判断するためにオプティマイザが使用する列に関する統計。列統計には、列の個別値の数、下限値、上限値およびNULLの数が含まれます。

複合ビューのマージ

GROUP BYおよびDISTINCTキーワードを含むビューのマージ。

複合データベース操作

データベース操作において、各セクションが独自の開始点および終了点を定義する、データベース・セッションの2つの時点間でのアクティビティです。1つのセッションは、一度に1つの複合データベース操作にのみ関与できます。

同時実行性

多数のユーザーによる同一のデータへの同時アクセス。マルチユーザー・データベース管理システムには、データが正しく更新または変更され、データ整合性が維持されるように、適切な同時実行性制御が必要です。

同時統計収集モード

スキーマ内の複数の表、表内の複数のパーティションまたはサブパーティションに対して、複数の表のオプティマイザ統計をデータベースで同時に収集可能なモード。データベースで複数のCPUをすべて使用可能にすることで、同時性により、統計の収集に必要な全体の時間を減らすことができます。

条件

1つ以上の式と論理演算子の組合せで指定し、TRUE、FALSEまたはUNKNOWNのいずれかの値を戻します。

コスト

実行計画のリソース使用の見積りを示す数字による内部尺度。コストが低いほど計画はより効率的です。

コストベース・オプティマイザ(CBO)

オプティマイザのレガシー名。以前のリリースでは、コストベース・オプティマイザがルールベース・オプティマイザ(RBO)の代替でした。

コスト・モデル

問合せで使用が予測されるI/O、CPUおよびネットワーク・リソースのコストから構成される内部のオプティマイザ・モデル。

累積統計

ブロック読取り数などのカウント。Oracle Databaseはシステム、セッションおよび個別のSQL文の累積統計のタイプを生成します。

カーソル

PGAのプライベートSQL領域のハンドルまたは名前。カーソルはプライベートSQL領域と密接に関連しているため、これらの用語は同じ意味で使用されることがあります。

カーソル・キャッシュ

共有SQL領域を参照してください。

カーソルのマージ

共有SQL領域を節約するためのカーソルの結合。オプティマイザがバインド対応カーソルの計画を作成し、この計画が既存のカーソルと同じである場合、オプティマイザはカーソルのマージを実行できます。

データ・フロー演算子(DFO)

パラレル問合せのデータ再分散ステージ間の作業単位。

データの偏り

列内の値の重複数の多数のバリエーション。

データベース操作

エンド・ユーザーまたはアプリケーション・コードによって定義されるデータベース・タスクのセット。たとえば、バッチ・ジョブまたはETL処理などです。

デフォルトの計画

適応計画において、データ・ディクショナリの統計を使用してオプティマイザが最初に選択する実行計画。デフォルトの計画は、最終計画とは異なる場合があります。

無効化された計画

データベース管理者が手動で、オプティマイザの使用対象外とマークした計画。

並列度(DOP)

単一の処理に関連付けられているパラレル実行サーバーの数。パラレル実行は複数のCPUを効率よく使用するためのものです。Oracle Databaseのパラレル実行フレームワークでは、特定の並列度をユーザーが明示的に選択することも、Oracle Databaseによって自動的に並列度を制御することもできます。

稠密キー

ネイティブ整数として格納され、値の範囲を持つ数値キー。

稠密グループ化キー

グループ化列が特定のファクト表またはディメンションから取得されるすべてのグループ化キーを表すキー。

稠密結合キー

結合列が特定のファクト表またはディメンションから取得されるすべての結合キーを表すキー。

密度

列の選択性を測定する0と1の間の小数。1に近い値は、この列の非選択性が高いことを示すのに対して、0に近い値は、この列の選択性が高いことを示します。

ダイレクト・パス読取り

PGAへのシングルまたはマルチブロックでの読込み(SGAを回避)。

駆動表

その他の表が結合された表。プログラミングに例えると、別のFOR LOOPを含むFOR LOOPです。外側のFOR LOOPは、駆動表と類似していて、外部表とも呼ばれます。

動的パフォーマンス・ビュー

動的パフォーマンス表で作成されたビュー。現在のデータベース・アクティビティを記録する仮想表です。動的パフォーマンス・ビューは、データベース管理者が変更または削除できないため、固定ビューと呼ばれます。文字列V$ (Oracle RACのGV$)で始まるため、V$ビューとも呼ばれます。

動的統計

述語の選択性を見積もるために、データベースが再帰的SQL文を実行して表ブロックの小さいランダム・サンプルをスキャンする最適化手法。

動的統計レベル

データベースで動的統計を収集するタイミングと、統計の収集にオプティマイザが使用するサンプル・サイズの両方を制御するレベル。動的統計レベルを設定するには、OPTIMIZER_DYNAMIC_SAMPLING初期化パラメータまたは文ヒントのいずれかを使用します。

有効化された計画

SQL計画管理において、オプティマイザの使用対象である計画。

エンドポイント数

ヒストグラム内のバケットを一意に識別する番号。頻度ヒストグラムおよびハイブリッド・ヒストグラムでは、エンドポイント数はエンドポイントの頻度の累積です。高さ調整済ヒストグラムでは、エンドポイント数はバケット数です。

エンドポイント繰返しカウント

ハイブリッド・ヒストグラムでは、ヒストグラム内の各エンドポイント(バケット)について、エンドポイント値が繰り返された回数。繰返しカウントを使用することで、オプティマイザは、ほぼポピュラーな値についての正確な見積りを得ることができます。

エンドポイント値

エンドポイント値は、ヒストグラム内の値の範囲で最も高い値。

等価結合

結合条件に等価演算子が含まれている結合。

エスティメータ

指定された実行計画の全体コストを判断する、オプティマイザのコンポーネント。

実行計画

SQL文を実行するためにデータベースによって使用されるステップの組合せ。各処理では、データベースからデータ行を物理的に検索するか、文を発行したセッションのためにデータ行を準備します。ヒントを使用すると実行計画を上書きできます。

実行ツリー

実行計画の各手順間の行ソースのフローを示すツリー・ダイアグラム。

式

結果が値となる、1つ以上の値、演算子およびSQL関数の組合せ。たとえば、2*2という式の結果は4になります。一般に、式ではその構成要素のデータ型が想定されます。

式の統計

WHERE句に式を使用する述語がある場合にオプティマイザの見積りを改善する拡張統計の一種。

拡張統計

複数の述語が存在する場合または述語に式が含まれる場合に、カーディナリティの見積りを改善するオプティマイザ統計のタイプ。

拡張可能オプティマイザ

ユーザー定義関数およびユーザー定義索引の作成者が、実行計画選択時にオプティマイザで使用する統計収集、選択性およびコスト・ファンクションを作成できるオプティマイザ機能。オプティマイザのコスト・モデルは、CPUおよびI/Oのコストにアクセスするユーザーから提供される情報を統合するように拡張されています。

拡張機能

列グループまたは式。列グループおよび式に対して収集された統計は、拡張統計と呼ばれます。

外部表

メタデータがデータベースに格納されている一方、データがデータベース外部のファイルに格納されている読取り専用の表。データベースは外部表を記述したメタデータを使用して、外部表をリレーショナル表とみなし、外部表のデータを公開します。

フィルタ条件

SQL文で参照する1つのオブジェクトから行を削除するWHERE句コンポーネント。

最終計画

適応計画において、最後に実行される計画。デフォルトの計画は最終計画とは異なる場合があります。

固定オブジェクト

動的パフォーマンス表またはその索引。固定オブジェクトはSYSによって所有されています。固定オブジェクト表は名前がX$で始まる、V$ビューの実表です。

固定計画

優先としてマークされた承認済の計画。これにより、オプティマイザはSQL計画ベースラインの固定計画のみを検討します。固定計画を使用して、オプティマイザの計画選択プロセスを決定できます。

頻度ヒストグラム

列の各個別値が1つのバケットに対応するヒストグラムのタイプ。コインの分類に例えて考えてみましょう。バケット1にはすべての1セント硬貨を入れ、バケット2にはすべての5セント硬貨を入れるなどのように分類します。

完全外部結合

左と右の外部結合の組合せ。内部結合に加えて、内部結合の結果で戻されなかった両方の表からの行がNULLを使用して維持されます。つまり、完全外部結合を使用すると、表をまとめて結合できますが、結合される表内に対応する行を持たない行も示すことができます。

全表スキャン

データベースによって表のすべての行が順に読み取られ、選択基準を満たさない行が除外される表データのスキャン。最高水位標を下回るすべてのデータ・ブロックがスキャンされます。

グローバル一時表

特定の期間、セッション固有の中間データを格納する特殊な一時表。

ハード解析

新しい実行可能なバージョンのアプリケーション・コードを構築するためにデータベースによって実行されるステップ。実行を依頼された文の解析済の表現が共有SQL領域内に存在しない場合、データベースはソフト解析ではなくハード解析を行います。

ハッシュ・クラスタ

索引キーがハッシュ関数に置き換わることを除いて、索引付きクラスタと似ている表クラスタの一種。別個のクラスタ索引は存在しません。ハッシュ・クラスタでは、データが索引になります。

ハッシュ衝突

複数の入力値を同じ出力値にハッシュすること。

ハッシュ関数

任意の長さの入力値に対して作用し、固定長のハッシュ値を戻す関数。

ハッシュ結合

大規模なデータ・セットを結合する方法。データベースは、2つのデータ・セットの小さい方を使用して、メモリーに結合キーについてのハッシュ表を作成します。次に、大きい方のデータ・セットをスキャンし、ハッシュ表を調べて結合された行を見つけます。

ハッシュ・スキャン

表クラスタへのアクセス・パス。ハッシュ・スキャンでは、ハッシュ値に基づいてハッシュ・クラスタ内の行の位置を特定します。ハッシュ・クラスタ内においては、同一のハッシュ値を持つすべての行が同じデータ・ブロックに格納されています。ハッシュ・スキャンを実行するには、最初に、文で指定されたクラスタ・キー値にハッシュ関数を適用することによって、ハッシュ値を取得し、次に、そのハッシュ値を持つ行が含まれているデータ・ブロックをスキャンします。

ハッシュ表

ハッシュ結合で結合キーを行と関連付けるインメモリー・データ構造。たとえば、employees表とdepartments表の結合では、部門IDが結合キーになる場合があります。ハッシュ関数は結合キーを使用してハッシュ値を生成します。このハッシュ値は、ハッシュ表である配列内の索引です。

ハッシュ値

ハッシュ・クラスタで、バケットを識別する一意の数値ID。Oracle Databaseでは、無数にあるハッシュ・キー値を入力として受け付け、限定された数のバケットに選別するハッシュ関数が使用されます。各ハッシュ値は、ハッシュ・キー値(部門10、20、30など)に対応する行の格納ブロックのデータベース・ブロック・アドレスにマップされます。

ハッシング

入力値の無限集合をハッシュ値と呼ばれる出力値の有限集合に対応付ける数学的技法。ハッシングはハッシュ表内のデータの迅速な検索に役立ちます。

ヒープ構成表

データ行が特定の順序によらずディスク上に格納される表。デフォルトでは、CREATE TABLEでヒープ構成表が作成されます。

高さ調整済ヒストグラム

列値がバケットに分割され、各バケットにほぼ同数の行が存在するヒストグラム。

ヒント

SQL文の中のコメントを介してオプティマイザに渡される命令。オプティマイザはヒントを使用して文の実行計画を選択します。

ヒストグラム

表の列でのデータ配分に関する詳細情報を提供する特殊な種類の列統計。

ハイブリッド・ハッシュ配分技法

実行時まで、最終的なデータ配分方法を決定しない、適応パラレル・データ配分。

ハイブリッド・ヒストグラム

サンプル内の各エンドポイントの正確な頻度を格納し、値が複数のバケットに格納されることはない、拡張された高さベースのヒストグラム。

暗黙的問合せ

副問合せなしでデータを取得するDML文の構成要素。明示的にSELECT文が含まれていないUPDATE、DELETEまたはMERGE文では、変更対象の行が暗黙的問合せを使用して取得されます。

インメモリー・スキャン

インメモリー列ストアから行を取得する表スキャン。

増分統計のメンテナンス

パーティション・レベルの統計を集計することによりパーティション表のグローバル統計を生成するデータベースの機能。

索引

クラスタ化されていない表、表パーティションまたは表クラスタに関連付けられた、オプションのスキーマ・オブジェクト。索引によってデータ・アクセスが高速化される場合があります。

索引クラスタ

索引を使用してデータを検索する表クラスタ。クラスタ索引とは、クラスタ・キーのBツリー索引のことです。

索引クラスタ化係数

従業員の名字などの索引値に関連する行順序の尺度。データ・ブロック間の行が分散されるほどクラスタ化係数は小さくなります。

高速全索引スキャン

ディスク上に存在しているままのソートされていない索引ブロックのスキャン。このスキャンでは、表のかわりに索引が読み取られます。

全索引スキャン

全索引のキー順のスキャン。

索引構成表

プライマリBツリー索引から記憶域の編成が改変された表。ヒープ構成表とは異なり、データは主キーの順に格納されます。

索引レンジ・スキャン

索引レンジ・スキャンは、索引の順序付きスキャンであり、次の特性があります。

- 索引の1つ以上の先頭列を条件に指定します。

- 0個、1個、または複数の値を索引キーにできます。

索引レンジ・スキャン降順

データベースが降順で列を返す索引レンジ・スキャン。

索引スキップ・スキャン

索引スキャンは、コンポジット索引の初期列が問合せでスキップされる(指定されない)場合に行われます。たとえば、コンポジット索引キーが(cust_gender,cust_email)である場合、問合せ述語はcust_gender列を参照しません。

索引統計

全表スキャンまたは索引スキャンを実行するかどうかの判断をするためにオプティマイザが使用する索引に関する統計。索引統計には、Bツリー・レベル、リーフ・ブロック数、索引クラスタ化係数、個別キーおよび索引内の行数が含まれます。

索引の一意スキャン

0か1のどちらかのROWIDを返す索引のスキャン。

索引タイプ

ドメインの(アプリケーション固有の)索引を管理するルーチンを指定するオブジェクト。

内部結合

結合条件を満たす行のみを戻す2つ以上の表の結合。

内部表

ネステッド・ループ結合における、外部表(駆動表)ではない表。外部表の行ごとに、内部表のすべての行がアクセスされます。外部ループは外部表にあるすべての行に対するものであり、内部ループは内部表の中にあるすべての行に対するものです。

結合

SQL文のFROM句に指定された複数の表からデータを取得する文。結合のタイプには、内部結合、外部結合およびデカルト結合があります。

結合条件

式を使用して2つの行ソースを比較する条件。データベースでは1対の行を組み合せ、それぞれの対には、結合条件がtrueになる各行ソースの行を1行ずつ含みます。

結合削除

問合せからの重複した表の削除。列が結合述語でのみ参照され、これらの結合が結果行のフィルタおよび拡張をしないことが保証されている場合、表は重複しています。

結合の因数分解

UNION ALL問合せのブランチの共通の計算を因数分解する、コストベースの変換。結合の因数分解を使用しない場合、オプティマイザは、UNION ALL問合せの各ブランチを単独で評価します。そのため、データ・アクセスや結合などの処理が繰り返し実行されることになります。大きな実表を追加でスキャンすることを回避できるため、パフォーマンスが大幅に向上します。

結合方法

行ソースのペアを結合する方法。有効な結合方法には、ネステッド・ループ結合、ソート/マージ結合およびハッシュ結合があります。デカルト結合には、前の結合方法のいずれかが必要です。

結合順序

複数の表を一緒に結合する順序。たとえば、employees表の行ごとに、departments表の各行を読み取ることができます。別の結合順序では、departments表の行ごとに、employees表の各行を読み取ります。

Oracle Databaseでは、3つ以上の表を結合する文を実行する場合、2つの表を結合し、その結果作成された行ソースを次の表に結合します。このプロセスは、すべての表が結合されて結果が生成されるまで続きます。

結合述語

結合で2つの表の列を組み合せるWHERE句またはJOIN句の述語です。

キー・ベクター

稠密結合キーと稠密グループ化キー間をマップするデータ構造。

ラッチ

SGA内の共有データ構造を同時アクセスから保護するために使用される、低レベルのシリアライズ制御メカニズム。

左側の深い結合ツリー

各結合の左入力が、以前の結合の結果である結合ツリー。

左表

外部結合において、(ANSI SQL構文の)OUTER JOINキーワードの左側で指定される表。

ライブラリ・キャッシュ

共有プール内のメモリー領域。このキャッシュには、共有SQL領域、プライベートSQL領域(共有サーバー構成の場合)、PL/SQLプロシージャおよびパッケージ、ロックやライブラリ・キャッシュ・ハンドルなどの制御構造が含まれています。

ライブラリ・キャッシュ・ヒット

ライブラリ・キャッシュ内で検出されたSQL文のコードの再利用。

ライブラリ・キャッシュ・ミス

SQLの処理中にライブラリ・キャッシュ内で使用可能な計画を検索して検出できない行動。

メンテナンス・ウィンドウ

自動化されたメンテナンス・タスクが実行される連続的な時間間隔。メンテナンス・ウィンドウは、MAINTENANCE_WINDOW_GROUPというウィンドウ・グループに属するOracle Schedulerのウィンドウです。

計画の手動取得

SQL計画ベースラインへの既存の計画の、ユーザー開始の一括ロード。

マテリアライズド・ビュー

問合せの結果を格納するスキーマ・オブジェクト。マテリアライズド・ビューのすべては、読取り専用または更新可能です。

マルチブロック読取り

複数のデータベース・ブロックを読み込むI/Oコール。マルチブロック読取りでは、高速で全表スキャンを実行できます。たとえば、データ・ブロックが8 KBの場合がありますが、オペレーティング・システムでは1回のI/Oで1024 KBを読み取れます。問合せによっては、オプティマイザが、1回のI/Oで128個のデータ・ブロックを読み取るほうが128回の順次I/Oよりもコスト効率が高いと判断する場合があります。

NDV

個別値の数。NDVは、カーディナリティの見積りの生成に重要です。

ネステッド・ループ結合

結合方法の一種。ネステッド・ループ結合は、結合を駆動する外部表を判定し、外部表の各行について内部表の各行を調べます。外部ループは外部表にある各行に対するものであり、内部ループは内部表の中にある各行に対するものです。プログラミングに例えると、別のforループを含むforです。

非等価結合

結合条件に等価演算子を含まない結合。

非結合列

1つの表のみを参照するWHERE句の述語です。

非ポピュラー値

ヒストグラムにおいて、2つ以上のエンドポイントにまたがらない値。非ポピュラー値以外の値は、すべてポピュラー値です。

非作業負荷統計

データベースで作業負荷をシミュレートする際に収集されたオプティマイザ・システム統計。

オンデマンドSQLチューニング

SQLチューニング・アドバイザの手動起動。自動SQLチューニング・タスクの結果として行われるのではないSQLチューニング・アドバイザの起動は、すべてオンデマンド・チューニングです。

最適化

SQL文を実行する最も効率的な方法を選択するプロセス全体。

オプティマイザ

SQL文で参照されているオブジェクトと指定された条件に関連する要因を考慮して、SQL文を実行する最も効率的な方法を決定する組込みのデータベース・ソフトウェア。

オプティマイザのコスト・モデル

オプティマイザが実行計画を選択するために使用するモデル。オプティマイザはコストが最も少ない実行計画を選択します。コストは、その計画のリソース使用量の見積りを表します。オプティマイザ・コスト・モデルでは、問合せで使用されるI/O、CPUおよびネットワーク・リソースが考慮されます。

オプティマイザ環境

作業領域サイズやオプティマイザの設定(たとえば、オプティマイザ・モード)など、実行計画の生成に影響する可能性があるすべてのセッション設定。

オプティマイザの目標

オプティマイザによるリソース使用の優先順位付け。OPTIMIZER_MODE初期化パラメータの使用により、オプティマイザの目標を最短のスループットや最短のレスポンス時間に設定できます。

オプティマイザ統計

各SQL文に対して最適な実行計画を選択するためにオプティマイザによって使用されるデータベースおよびデータベース・オブジェクトに関する詳細。カテゴリには、行数などの表統計、Bツリー・レベルなどの索引統計、CPUとI/Oのパフォーマンスなどのシステム統計およびNULL数などの列統計が含まれます。

オプティマイザ統計の収集

データベース・オブジェクトのオプティマイザ統計を収集すること。データベースではこの統計を自動的に収集するか、またはシステムによって提供されるDBMS_STATSパッケージを使用して手動で収集できます。

オプティマイザ統計コレクタ

適応計画で使用する実行時統計を収集するために、キー・ポイントで実行計画に挿入される行ソース。

オプティマイザ統計プリファレンス

自動統計収集およびDBMS_STATS統計収集プロシージャで使用するパラメータのデフォルト値。

外部結合

表のどれか1つの1つ以上の列で外部結合演算子(+)を使用する結合条件。データベースは、結合条件に一致する行をすべて戻します。また、外部結合演算子を指定した表で一致する行がない場合、外部結合演算子を使用せずに表からすべての行を戻します。

外部表

駆動表を参照してください

パラレル実行

複数のCPUおよびI/Oリソースを1つのデータベース操作の実行に適用すること。

パラレル問合せ

1つのSQL問合せを実行するために、複数のプロセスが同時に連携して動作する問合せ。複数プロセス内で作業を分割すると、Oracle Databaseでは、より迅速に文を実行できます。たとえば、1つのプロセスで4つの四半期分をすべて処理するのではなく、4つのプロセスで1年のそれぞれの四半期に対する行を取得します。

親カーソル

SQLテキストおよびSQL文のその他の最小情報が格納されているカーソル。子カーソルには、計画、コンパイル環境、その他の情報が含まれます。文が最初に実行されると、データベースによって共有プールに親カーソルと子カーソルが作成されます。

解析コール

SQL文実行の準備のためにOracleに行われるコール。このコールには、SQL文の構文チェック、SQL文の最適化、SQL文の実行可能形式の作成または指定が含まれています。

解析

SQL文の各部分を他のルーチンで処理できるデータ構造へ分解するSQL処理の段階。

ハード解析は、実行されるSQL文が、共有プール内にないか、共有プール内にあっても共有できない場合に行われます。ソフト解析は、セッションでSQL文を実行する際に、その文がすでに共有プール内にあり、その文を使用できる場合に行われます。

パーティション・メンテナンス操作

表パーティションの追加、交換、マージ、分割などのパーティションに関連する操作。

パーティション・ワイズ結合

2つの表の大規模な結合を分割する結合最適化(一方の表が、結合キーで複数の小規模な結合にパーティション化されている必要がある)。

保留中の統計情報

公開されていないオプティマイザ統計。デフォルトでは、オプティマイザは公開された統計を使用しますが、保留中の統計情報は使用しません。

パフォーマンス・フィードバック

この自動再最適化の形式ではPARALLEL_DEGREE_POLICYがADAPTIVEに設定された場合に、繰り返しSQL文に対して自動的に選択される並列度を改善できます。

パイプライン・テーブル・ファンクション

入力として行のコレクションを受け入れるPL/SQLファンクション。SELECT文のFROMリストで表演算子のオペランドとしてテーブル・ファンクションを起動します。

計画の展開

SQL計画履歴の中の未承認の計画をSQL計画ベースラインの承認済の計画へ手動で変更することです。

プラン・ジェネレータ

特定の問合せブロックに対して、最小コストの計画を検出するために、様々なアクセス・パス、結合方法および結合順序を試行するオプティマイザの要素。

計画の選択

ハード解析実行後、文のSQL計画ベースラインの中で一致する計画を検出しようとするオプティマイザの試み。

計画検証

未承認の計画のパフォーマンスとSQL計画ベースラインの中の計画のパフォーマンスを比較し、未承認の計画のほうが良好であることを確認することです。

ポピュラー値

ヒストグラムにおいて、2つ以上のエンドポイントにまたがる値。ポピュラー値以外の値は、すべて非ポピュラー値です。

述語のプッシュ

オプティマイザが関連する述語を、それを含む問合せブロックからビューの問合せブロックにプッシュする変換技法。マージされていないビューでは、プッシュされた述語は、索引へのアクセスまたはフィルタとして使用できるので、この方法を使用するとマージされていないビューのサブプランが改善されます。

プライベートSQL領域

解析済の文と処理に使用するその他の情報が保持されるメモリー内の領域。プライベートSQL領域には、バインド変数値、問合せ実行状況の情報、問合せ実行作業領域などのデータが格納されます。

SQLの事前チューニング

SQLチューニング・ツールを使用して、ユーザーがパフォーマンスの問題に不満を持つ前にチューニングの候補となるSQL文を識別することです。

SQLの事後チューニング、SQLチューニングを参照してください。

予測ビュー

オプティマイザによって生成されるビュー。DISTINCTビューがマージされた問合せに表示されるか、またはGROUP BYビューが、GROUP BY、HAVINGまたは集計も含まれている外側の問合せブロックにマージされる問合せに表示されます。

単純ビューのマージ、複合ビューのマージを参照してください。

問合せ

表またはビューからデータを取り出す操作。たとえば、SELECT * FROM employeesは問合せです。

問合せブロック

トップレベルのSELECT文、副問合せまたはマージされていないビュー。

問合せオプティマイザ

オプティマイザを参照してください。

SQLの事後チューニング

ユーザーが不満を持った場合に、SQLに関連するパフォーマンスの問題を診断して修正します。

SQLの事前チューニング、SQLチューニングを参照してください。

再帰的SQL

ユーザーが発行したSQL文を実行するために、データベースで発行が必要になるSQLの追加文。再帰的SQLの生成は、再帰的コールと呼ばれます。たとえば、データ・ディクショナリの情報がメモリーにないため、ディスクから取り出す必要がある場合に、データベースで再帰的コールが生成されます。

再最適化

自動再最適化を参照してください。

繰返し可能なSQL文

SQL文のログでの追跡を確認後、データベースで解析または実行される文。

レスポンス時間

作業単位の完了に必要な時間。

スループットを参照してください。

結果セット

問合せにおいて、カーソルの実行によって生成される行セット。

右側の深い結合ツリー

各結合の右入力が以前の結合の結果であり、結合ツリーの各内部ノードの左の子が表である結合ツリー。

右表

外部結合において、(ANSI SQL構文の)OUTER JOINキーワードの右側で指定される表。

ROWID

表内の行に対するグローバルな一意のアドレス。

行セット

実行計画の手順によって戻される行セット。

行ソース

1組の行を反復方式で処理し、行セットを生成する反復制御構造。

行ソース・ジェネレータ

オプティマイザから最適な計画を受け取り、SQL文の実行計画を出力するソフトウェア。

行ソース・ツリー

行ソース・ジェネレータによって生成される行ソースのコレクション。SQL文の行ソース・ツリーでは、表の順序、アクセス方法、結合方法、フィルタやソートなどのデータ操作といった情報を示します。

サンプル表スキャン

単純な表、または結合およびビューを含む文などの複合SELECT文からデータのランダムなサンプルを取り出すスキャン。

サンプリング

表の行のランダムに取得されたサブセットから統計を収集すること。

選択性

述語または述語の組合せによって取り出される行セットの割合を示す値。たとえば、WHERE last_name = 'Smith'などです。0を選択すると述語テストに合格する行がないことを意味し、値1を選択するとすべての行がテストに合格することを意味します。

選択性という語句は、大まかに「選ぶ」ことを意味します。選択性の高い問合せでは、戻される行の割合が低く(選択性が0に近い)、非選択性の高い問合せでは、戻される行の割合は高くなります(選択性が1に近い)。

セミ結合

第2の表に少なくとも1つの一致がある場合に、第1の表から行を戻す結合。たとえば、少なくとも1人従業員がいる部門をリストします。セミ結合と従来の結合の違いは、第1の表の行が1回しか戻されないことです。セミ結合は、EXISTSまたはINの構成を使用します。

共有カーソル

複数のSQL文で使用される共有SQL領域。

共有プール

共有SQL領域などの共有メモリー構成メンバーを含むSGAの一部。

共有SQL領域

SQL文の解析ツリーと実行計画を含む共有プール内の領域。一意の文に対して、共有SQL領域は1つのみ存在します。共有SQL領域は、カーソル・キャッシュと呼ばれることもあります。

単純データベース操作

1つのSQL文またはPL/SQLのプロシージャまたはファンクションで構成されたデータベース操作。

単純ビューのマージ

選択表示結合ビューのマージ。たとえば、問合せがdepartmentsとlocations表を結合する副問合せにemployees表を結合する場合などです。

SMB

SQL管理ベース(SMB)を参照してください。

スノーフレーク・スキーマ

ディメンション表が他の表を参照するスター・スキーマ。

スノーストーム・スキーマ

複数のスノーフレーク・スキーマの組合せ。

ソフト解析

ハード解析以外のすべての解析。発行されるSQL文が共有プール内の再利用可能なSQL文と同じ場合、Oracle Databaseは既存のコードを再利用します。コードの再利用は、ライブラリ・キャッシュ・ヒットとも呼ばれます。

ソート/マージ結合

結合方法の一種。両方の入力が結合キーでソートされるソート結合と、それに続いてソートされたリストがマージされるマージ結合で構成された結合。

SQLアクセス・アドバイザ

SQLアクセス・アドバイザは、どのマテリアライズド・ビュー、索引およびマテリアライズド・ビュー・ログを作成、削除または保持するのが適切かを提示する内部診断ソフトウェアです。

SQLのコンパイル

Oracle SQL処理のコンテキストにおいて、この用語は、解析、最適化、計画生成の段階を総称しています。

SQL計画ディレクティブ

オプティマイザがより最適な計画を生成するために使用できる追加情報および命令。たとえば、SQL計画ディレクティブは、欠落している統計の収集または動的統計の収集をオプティマイザに命令することもあります。

SQLハンドル

SQLシグネチャの数値から導出された文字列。シグネチャと同様に、このハンドルは一意にSQL文を識別します。ユーザーAPIでSQL検索キーになります。

SQL ID

特定のSQL文に対する、ライブラリ・キャッシュ内の親カーソルの一意の識別子。SQL文のテキストに適用されたハッシュ関数によってSQL IDが生成されます。V$SQL.SQL_ID列で、SQL IDが表示されます。

SQLインシデント

Oracle Databaseの障害診断インフラストラクチャでは、SQL関連の問題の1回の発生を表します。問題(クリティカル・エラー)が複数回発生したとき、それぞれの発生に対してインシデントが作成されます。インシデントには日時が記録され、自動診断リポジトリ(ADR)で追跡されます。

SQL管理ベース(SMB)

文のログ、計画履歴、SQL計画ベースラインおよびSQLプロファイルが格納されている論理リポジトリ。SMBは、データ・ディクショナリの一部であり、SYSAUX表領域内にあります。

SQL計画ベースライン

繰返し可能なSQL文に対する1つ以上の承認済の計画のセット。各承認済の計画には、ヒント・セット、計画のハッシュ値、計画に関連するその他の情報が含まれます。SQL計画管理は、SQL計画ベースラインを使用して、一定期間SQL文の実行計画を記録し、評価します。

SQL計画の取得

一連のSQL文に対して、計画に関連する情報を取得し、SQL管理ベース(SMB)に保存する方法。計画の取得とは、SQL計画管理にこの計画を認識させることを意味します。

SQL計画ディレクティブ

オプティマイザがより最適な計画を生成するために使用する追加情報。オプティマイザは、文レベルではなく、問合せ式のSQL計画ディレクティブを収集します。このようにして、ディレクティブは、複数のSQL文で使用可能になります。

SQL計画履歴

取得された一連の実行計画。この履歴には、SQL計画ベースラインおよび未承認の計画が含まれます。

SQL計画管理

SQL計画管理は、SQL文の実行計画を時間の経過とともに記録し、評価を行う予防メカニズムです。SQL計画管理は、オプティマイザの新しいバージョン、オプティマイザ統計への変更、システム設定などの環境変化によるSQL計画の不具合を防止できます。

SQLの処理

SQL文の解析、最適化、行ソースの生成および実行の段階。

SQLプロファイル

SQL文の自動チューニング中に作成される補助的な情報セット。SQLプロファイルとSQL文の関係は、統計と表の関係と同様です。オプティマイザは、SQLプロファイルを使用して、カーディナリティおよび選択性の見積りを改善し、より適切な計画を選択できるようになります。

SQLプロファイリング

自動チューニング・アドバイザによる見積りの確認および検証。

SQLシグネチャ

大/小文字および空白が正規化されているSQL文のテキストを使用して計算されたハッシュ値。SQL文は一意に識別されます。データベースでは、このシグネチャをキーとして使用し、SQLプロファイル、SQL計画ベースライン、SQLパッチなどのSQL管理オブジェクトを管理します。

SQL文のログ

自動SQL計画キャプチャが有効になっている場合に、オプティマイザによって一定期間評価されたSQL文のSQL IDを含むログ。文がログ内に存在する場合、追跡されます。

SQLテスト・ケース

問題のあるSQL文、および別の環境でその実行計画を再現するために必要な関連情報。SQLのテスト・ケースは、Oracle Data Pumpファイルに格納されます。

SQLテスト・ケース・ビルダー

ユーザーが別のデータベースで問題を再現できるように、SQL文の関連情報を収集し、パッケージ化するデータベース機能。DBMS_SQLDIAGパッケージは、SQLテスト・ケース・ビルダーのインタフェースです。

SQLトレース・ファイル

個々のSQL文に関するパフォーマンス情報を提供するサーバー生成ファイル。たとえば、トレース・ファイルには、解析数、実行数、フェッチ数、CPUと経過時間、物理読込みと論理読込み、ライブラリ・キャッシュでのミスなどが含まれます。

SQLチューニング

測定可能な目標を達成するためにSQL文の効率を改善するプロセス。

SQLチューニング・アドバイザ

高負荷SQL文を最適化する組込みデータベース診断ソフトウェア。

自動SQLチューニング・アドバイザを参照してください。

SQLチューニング・セット(STS)

1つ以上のSQL文、実行統計および実行コンテキストを含むデータベース・オブジェクト。

スター・スキーマ

ディメンション・データ・モデルを表すように設計されたリレーショナル・スキーマです。1つ以上のファクト表と、外部キーを介して関連付けられている1つ以上のディメンション表で構成されます。

統計フィードバック

カーディナリティの見積りが誤っている繰返し問合せの計画を自動的に改善する自動再最適化の形式。オプティマイザは、統計がない、統計が不正確である、述語が複雑であるなど、多数の理由でカーディナリティを誤って見積ることがあります。

ストアド・アウトライン

SQL文のヒント・セット。ストアド・アウトラインのヒントは、文に対して特定の計画を選択するようオプティマイザに指示します。

サブプラン

オプティマイザが実行時に代替として切り替えることができる適応計画の一部。サブプランは、計画内の複数の操作で構成できます。たとえば、オプティマイザは、実行時に計画を変更するかどうか判断する際に、結合方法および対応するアクセス・パスを1単位として扱うことができます。

副問合せ

別のSQL文内にネストされた問合せ。暗黙的な問合せとは異なり、副問合せはSELECT文を使用してデータを取得します。

副問合せのネスト解除

オプティマイザはネストされた問合せを同等の結合文に変換してから、その結合を最適化する変換技法。

シノプシス

INCREMENTAL値がtrueに設定されている場合、パーティション表で収集される補助統計のセット。

システム統計

オプティマイザがCPUおよびI/Oの特性を使用できるようにする統計。索引統計には、Bツリー・レベル、リーフ・ブロック数、クラスタ化係数、個別キーおよび索引内の行数が含まれます。

表クラスタ

1つ以上の共通する列を持つ、1つ以上の表のデータを含むスキーマ・オブジェクト。表クラスタでは、データベースは同じクラスタ・キーを共有するすべての表について、すべての行をまとめて格納します。

表拡張

オプティマイザが、パーティション表のread-mostly部分では索引を使用するが、表のアクティブ部分では索引を使用しない計画を生成できるようにする変換技法。

表統計

表アクセス・コスト、結合カーディナリティ、結合順序などを判断するためにオプティマイザが使用する表に関する統計。表統計には、行数、ブロック数、空のブロック、各ブロックの平均空き領域、連鎖行数、行の平均の長さおよび表統計の失効が含まれます。

スループット

単位時間内に完了する作業量。

レスポンス時間を参照してください。

上位頻度ヒストグラム

統計的には重要でない非ポピュラー値を無視することによって、頻繁に出現する値に関するより適切なヒストグラムを作成できる頻度ヒストグラムのバリエーション。

チューニング・モード

2つのオプティマイザ・モードのうちの1つ。チューニング・モードで実行する場合、オプティマイザは自動チューニング・オプティマイザと呼ばれます。チューニング・モードにおいて、オプティマイザは、標準モードで生成された計画をさらに改善できるかどうかを判断します。オプティマイザの出力は、実行計画ではなく、さらに優れた計画を生成するための一連のアクションと、その理論的根拠および予測されるメリットを示します。

未承認の計画

SQL計画履歴内に存在するが、SQL計画管理に追加されていない、文に対する計画。

非選択性

行セットのうち比較的多数の行。選択性が1に近づくほど、問合せの非選択性は高くなります。たとえば、100万行の表から999,999行が戻される問合せは、非選択性の問合せです。1行を戻す同じ表の問合せは、選択性の問合せです。

ユーザーのレスポンス時間

ユーザーがコマンドを発行し、レスポンスを受け取る間の時間。

スループットを参照してください。

V$ビュー

動的パフォーマンス・ビューを参照してください。

ベクトルI/O

データベースにより行IDのセットが取得され、配列にバッチされてオペレーティング・システムに送信され、そこで読取りが行われるタイプのI/O。

ビューのマージ

ビューを表す問合せブロックを、それを包含する問合せブロックにマージすること。ビューのマージにより、オプティマイザが追加の結合順序、アクセス方法およびその他の変換を考慮できるようになり、計画を向上させることができます。

作業負荷統計

指定時間内のシステム・アクティビティに関するオプティマイザ統計。

索引

A  B  C  D  E  F  G  H  I  J  K  L  M  N  O  P  Q  R  S  T  U  V  W

A

- アクセス・パス

- 実行計画 1

- 全表スキャン 1

- 全表スキャン 1 , 2

- 適応計画

- カーディナリティの見積りの誤り 1

- オプティマイザ統計コレクタ 1

- レポート作成モード 1

- サブプラン 1

- 適応問合せ最適化

- 適応計画 1 , 2 , 3

- 適応問合せ計画 1 , 2

- 制御 1

- 動的統計 1

- 適応問合せ計画

- ビットマップ索引プルーニング 1

- 結合方法 1

- パラレルの配分方法 1

- 適応統計

- 自動再最適化 1

- 動的統計 1

- SQL計画ディレクティブ 1 , 2

- ADDM 1

- ALTER SESSION文

- 例 1

- アンチ結合 1

- アプリケーション

- 実装 1

- 自動再最適化

- カーディナリティの見積りの誤り 1

- パフォーマンス・フィードバック 1

- 統計フィードバック 1

- 自動統計収集 1

- 自動チューニング・オプティマイザ

- SQLプロファイル 1

- 自動ワークロード・リポジトリ(AWR) 1

B

- ビッグ・バン・ロールアウトの方法 1

- バインド対応カーソル 1

- バインド依存カーソル 1

- バインド変数の照合 1

- バインド変数

- バインド照合 1

- ビットマップ索引

- INLIST ITERATOR 1

- 結合 1

- プルーニング 1

- 使用するとき 1

- BOOLEANデータ型 1

- バルク・ロード

- ヒストグラムの作成 1

- 索引の統計の収集 1

- BYTES列

- PLAN_TABLE表 1 , 2

C

- カーディナリティ 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 12

- CARDINALITY列

- PLAN_TABLE表 1 , 2

- デカルト結合 1

- 子カーソル 1

- クラスタ

- ソートされたハッシュ 1

- クラスタ, 表 1

- 列グループ

- オプティマイザ統計 1

- 列グループの統計 1

- 列

- カーディナリティ 1

- 索引 1

- コンパイル, SQL 1 , 2 , 3

- コンポジット索引 1

- コンポジット・パーティション化

- 例 1

- 同時統計収集 1 , 2 , 3

- 一貫モード

- TKPROF 1

- 制約 1

- COST列

- PLAN_TABLE表 1 , 2

- 現行モード

- TKPROF 1

- CURSOR_NUM列

- TKPROF_TABLE表 1

- CURSOR_SHARING初期化パラメータ 1

- カーソルのマージ 1

- カーソル

- 概要 1

- バインド対応 1

- バインド依存 1

- バインド変数の照合 1

- 子 1

- 親 1 , 2

- 解析 1

- 共有 1 , 2 , 3

- カーソル共有

- 強制 1

D

- データ

- モデル化 1

- データベース操作

- コンポジット 1 , 2

- 概念 1

- 定義 1 , 2

- 単純 1 , 2

- データベース操作, 監視

- コンポジット 1

- 複合操作 1

- データベース操作の作成 1

- ヒントを使用した有効化 1

- 初期化パラメータを使用した有効化 1

- Enterprise Managerのインタフェース 1

- PL/SQLインタフェース 1

- 目的 1

- リアルタイムSQL 1

- 単純操作 1

- Cloud Controlの使用 1

- データ・ブロック 1

- データ・ディクショナリ・キャッシュ 1

- データ・フロー演算子(DFO) 1

- データ・ポンプ

- エクスポート・ユーティリティ

- システム生成の列名の統計 1

- インポート・ユーティリティ

- 統計のコピー 1

- データの偏り 1

- データ型

- BOOLEAN 1

- DATE_OF_INSERT列

- TKPROF_TABLE表 1

- DB_FILE_MULTIBLOCK_READ_COUNT初期化パラメータ 1

- DBA_OPTSTAT_OPERATION_TASKSビュー 1

- DBA_OPTSTAT_OPERATIONSビュー 1

- DBMS_ADVISORパッケージ 1

- DBMS_MONITORパッケージ

- エンドツーエンド・アプリケーションのトレース 1

- DBMS_SPMパッケージ 1

- DBMS_SQLTUNEパッケージ

- SQLチューニング・アドバイザ 1

- DBMS_XPLAN 1

- DDL(データ定義言語)

- 処理 1

- デッドロック 1

- 設計のデバッグ 1

- 専用サーバー 1

- 稠密キー

- 稠密グループ化キー 1

- 稠密結合キー 1

- 密度, ヒストグラム 1

- DEPTH列

- TKPROF_TABLE表 1

- 設計

- デバッグ 1

- テスト 1

- 検証 1

- 開発環境 1

- DIAGNOSTIC_DEST初期化パラメータ 1

- 使用禁止の制約 1

- DISTRIBUTION列

- PLAN_TABLE表 1 , 2

- ドメイン索引

- EXPLAIN PLAN 1

- 使用 1

- 動的統計

- 制御 1

- プロセス 1

- サンプリング・レベル 1

- 統計レベルの設定 1

- 使用するとき 1

E

- 使用可能な制約 1

- エンドポイント繰返しカウント, ヒストグラム 1

- エンドツーエンド・アプリケーションのトレース

- アクション名とモジュール名 1

- サービスの作成 1

- DBMS_APPLICATION_INFOパッケージ 1

- DBMS_MONITORパッケージ 1

- 概要 1

- 規定された制約 1

- 例

- ALTER SESSION文 1

- EXPLAIN PLAN出力 1

- EXECUTE_TASKプロシージャ 1

- 実行プラン

- 概要 1

- 適応 1 , 2 , 4

- 例 1

- 概要 1

- TKPROF 1 , 2

- V$ビュー 1

- utlxpls.sqlスクリプトによる表示 1

- 実行ツリー 1

- EXPLAIN PLAN文

- アクセス・パス 1 , 2

- フル・パーティション・ワイズ結合 1

- パーシャル・パーティション・ワイズ結合 1

- パーティション・オブジェクト 1

- 基本的な手順 1

- 出力の例 1

- TKPROFプログラムでの起動 1

- PLAN_TABLE表 1

- 制限事項 1

- 出力の表示 1

- 式の統計

- 作成 1

- 拡張統計 1

- 拡張機能 1

F

- 固定オブジェクト

- 統計の収集 1 , 2

- 頻度ヒストグラム 1 , 2 , 3

- 完全外部結合 1

- フル・パーティション・ワイズ結合 1

- 全表スキャン 1 , 2 , 3

- ファンクション索引 1

G

- グローバル一時表 1

H

- ハード解析 1

- ハード解析 1 , 2

- ハッシュ・クラスタ

- ソート 1

- ハッシング 1

- ハッシュ結合

- コストベースの最適化 1

- ハッシュ・パーティション

- 例 1

- 高さ調整済ヒストグラム 1 , 2

- 高負荷SQL

- チューニング 1 , 2

- ヒント, オプティマイザ

- FULL 1

- GATHER_OPTIMIZER_STATISTICS 1

- NO_GATHER_OPTIMIZER_STATISTICS 1

- NO_INDEX 1

- NO_MONITOR 1

- OPTIMIZER_FEATURES_ENABLE 1

- ヒストグラム

- カーディナリティのアルゴリズム 1

- バルク・ロード中の作成 1

- 作成の基準 1

- データの偏り 1

- 定義 1

- 密度 1

- エンドポイント数 1

- エンドポイント繰返しカウント 1

- エンドポイント値 1

- 頻度 1 , 2 , 3

- 高さ調整済 1 , 2

- ハイブリッド 1 , 2

- NDV 1

- 非ポピュラー値 1

- ポピュラー値 1

- 目的 1

- 上位頻度 1 , 2

- ハイブリッド・ヒストグラム 1 , 2

I

- I/O

- 削減 1

- ID列

- PLAN_TABLE表 1 , 2

- 増分統計

- メンテナンス 1 , 2

- 索引クラスタ化係数 1

- 索引

- 不使用 1

- ビットマップ 1 , 2

- 列の選択 1

- コンポジット 1

- ドメイン 1

- 削除 1

- 一意性の規定 1

- 使用の保証 1

- ファンクション 1

- 選択性の向上 1

- 低選択性 1

- 値の修正 1

- 非一意 1

- 再作成 1

- スキャン 1

- 選択性 1

- 索引統計

- 索引クラスタ化係数 1

- 初期化パラメータ

- DIAGNOSTIC_DEST 1

- インメモリー集計

- 制御 1

- 仕組み 1

- 目的 1

- インメモリー集計

- フェーズ 1

- シナリオ 1

- インメモリー表スキャン

- 制御 1

- 例 1

- 選択する場合 1

- 内部ループ, ネステッド・ループ結合 1

J

- 結合方法

- ネステッド・ループ 1 , 2

- 結合

- アンチ結合 1

- デカルト 1

- 完全外部 1

- ハッシュ 1

- ネステッド・ループ 1 , 2 , 3

- ネステッド・ループおよびコストベースの最適化 1

- 順序付け 1

- 外部 1

- パーティション・ワイズ

- フルの例 1

- パーシャルの例 1

- 完全 1

- セミ結合 1

- ソート/マージ 1

- ソート/マージおよびコストベースの最適化 1

K

- キー・ベクター 1

L

- ラッチ

- 解析 1

- ライブラリ・キャッシュ 1

- ライブラリ・キャッシュ・ミス 1

- ロック

- デッドロック 1

M

- 計画の手動取得 1

- マテリアライズド・ビュー

- クエリー・リライト 1

- モデル化

- データ 1

- マルチバージョン読取り一貫性 1

N

- NDV 1

- ネステッド・ループ結合

- 動作の概要 1

- ネステッド・ループ

- 駆動表 1

- ネステッド・ループ結合

- コストベースの最適化 1

- USE_NLヒント 1

- NO_INDEXヒント 1

- 非ポピュラー値, ヒストグラム 1

- NOT IN副問合せ 1

O

- OBJECT_INSTANCE列

- PLAN_TABLE表 1 , 2

- OBJECT_NAME列

- PLAN_TABLE表 1 , 2

- OBJECT_NODE列

- PLAN_TABLE表 1 , 2

- OBJECT_OWNER列

- PLAN_TABLE表 1 , 2

- OBJECT_TYPE列

- PLAN_TABLE表 1 , 2

- OPERATION列

- PLAN_TABLE表 1 , 2

- 最適化

- 適応問合せ 1

- 最適化, SQL 1

- オプティマイザ

- 適応 1

- 定義 1

- 環境 1

- エスティメータ 1

- 実行 1

- 目標 1

- 目的 1

- 行ソース 1

- 統計 1

- スループット 1

- OPTIMIZER_FEATURES_ENABLE初期化パラメータ 1

- OPTIMIZER列

- PLAN_TABLE 1 , 2

- オプティマイザ環境 1

- オプティマイザ・ヒント

- FULL 1

- MONITOR 1

- NO_INDEX 1

- OPTIMIZER_FEATURES_ENABLE 1

- オプティマイザ統計

- 適応統計 1

- 自動収集 1 , 2

- 基本的なトピック 1

- バルク・ロード 1

- カーディナリティ 1

- コレクション 1

- 列グループ 1

- 列グループ 1 , 2

- 動的 1 , 2 , 3 , 4 , 5

- 拡張 1

- 同時収集 1 , 2 , 3

- パラレル収集 1

- 取得 1

- ヒストグラム 1

- 増分 1 , 2 , 3 , 4

- 索引 1

- 手動収集 1

- 収集の監視 1

- プラガブル・データベース 1

- プリファレンス 1 , 2

- 設定 1

- SQL計画ディレクティブ 1 , 2

- システム 1

- 一時 1

- オプティマイザ統計の収集 1

- オプティマイザ統計コレクタ 1

- OPTIONS列

- PLAN_TABLE表 1 , 2

- OTHER_TAG列

- PLAN_TABLE表 1 , 2

- OTHER列

- PLAN_TABLE表 1 , 2

- 外部結合 1

- 外部ループ, ネステッド・ループ結合 1

P

- パッケージ

- DBMS_ADVISOR 1

- パラレル実行

- 統計の収集 1

- PARENT_ID列

- PLAN_TABLE表 1 , 2

- 親カーソル 1 , 2

- 解析コール 1

- 解析

- ハード 1

- 解析, SQL

- ハード 1

- ハード解析 1

- 解析ツリー 1

- ソフト 1

- ソフト解析 1

- PARTITION_ID列

- PLAN_TABLE表 1 , 2

- PARTITION_START列

- PLAN_TABLE表 1 , 2

- PARTITION_STOP列

- PLAN_TABLE表 1 , 2

- パーティション・オブジェクト

- EXPLAIN PLAN文 1

- 増分統計の収集 1 , 2

- パーティション化

- 例 1

- コンポジットの例 1

- ハッシュ 1

- 範囲 1

- 開始列と終了列 1

- パーティションのメンテナンス操作 1

- パーティション・ワイズ結合

- 完全 1

- フル, EXPLAIN PLAN出力 1

- パーシャル, EXPLAIN PLAN出力 1

- パフォーマンス

- 実行計画の表示 1

- PLAN_TABLE表

- BYTES列, 1 , 2

- CARDINALITY列, 1 , 2

- COST列 1 , 2

- 作成 1

- 表示 1

- DISTRIBUTION列 1 , 2

- ID列 1 , 2

- OBJECT_INSTANCE列 1 , 2

- OBJECT_NAME列 1 , 2

- OBJECT_NODE列 1 , 2

- OBJECT_OWNER列 1 , 2

- OBJECT_TYPE列 1 , 2

- OPERATION列 1 , 2

- OPTIMIZER列 1 , 2

- OPTIONS列 1 , 2

- OTHER_TAG列 1 , 2

- OTHER列 1 , 2

- PARENT_ID列 1 , 2

- PARTITION_ID列 1 , 2

- PARTITION_START列 1 , 2

- PARTITION_STOP列 1 , 2

- POSITION列 1 , 2

- REMARKS列 1 , 2

- SEARCH_COLUMNS列 1 , 2

- STATEMENT_ID列 1 , 2

- TIMESTAMP列 1 , 2

- 計画の展開

- 目的 1

- プラガブル・データベース

- 自動オプティマイザ統計収集 1

- 管理機能 1

- SQL管理ベース 1

- SQLチューニング・アドバイザ 1 , 2

- SQLチューニング・セット 1

- ポピュラー値, ヒストグラム 1

- POSITION列

- PLAN_TABLE表 1 , 2

- プライベートSQL領域

- 解析 1

- プロセス

- 専用サーバー 1

- プログラミング言語 1

Q

- 問合せ

- 索引不使用 1

- 索引使用の保証 1

- 問合せ変換

- インメモリー集計 1

- 表拡張の目的 1

- マテリアライズド・ビューを使用したクエリー・リライト 1

- スター型変換 1

- 表拡張 1 , 2 , 3

R

- レンジ

- パーティションの例 1

- パーティション 1

- リアルタイム・データベース操作 1

- リアルタイムSQL監視 1 , 2

- Real-World Performance

- カーソル共有 1

- recursive calls 1

- 再帰的SQL 1 , 2 , 3

- REMARKS列

- PLAN_TABLE表 1 , 2

- 再最適化, 自動

- カーディナリティの見積りの誤り 1

- パフォーマンス・フィードバック 1

- 統計フィードバック 1

- 結果セット, SQL 1 , 2

- ロールアウトの方法

- ビッグ・バン・アプローチ 1

- トリクル・アプローチ 1

- ROWID

- 表アクセス 1

- 行

- 位置特定に使用されるROWID 1

- 行セット 1

- 行ソース 1

- 行ソース生成 1

- 行ソース 1

S

- SAMPLE BLOCK句 1

- SAMPLE句 1

- サンプル表スキャン 1

- スキャン

- インメモリー 1

- サンプル表 1

- SEARCH_COLUMNS列

- PLAN_TABLE表 1 , 2

- 選択性

- 索引の作成 1

- 索引の向上 1

- 索引 1

- SELECT文

- SAMPLE句 1

- セミ結合 1

- 共有プール

- 解析チェック 1

- 共有SQL領域 1 , 2

- ソフト解析 1 , 2

- ソート/マージ結合

- コストベースの最適化 1

- 動作の概要 1

- SPM展開アドバイザのタスク

- 管理 1

- スケジューリング 1

- SQL

- 実行 1

- 最適化 1

- 解析 1

- 再帰的 1

- 結果セット 1 , 2

- 処理の段階 1 , 2

- SQL_STATEMENT列

- TKPROF_TABLE 1

- SQL, 再帰的 1 , 2

- SQLアクセス・アドバイザ

- 定数 1

- EXECUTE_TASKプロシージャ 1

- SQLのコンパイル 1 , 2 , 3

- SQL管理ベース

- プラガブル・データベース 1

- SQL演算子 1

- SQLの解析

- 解析コール 1

- SQLパフォーマンス・アナライザ 1

- SQL計画ベースライン

- 表示 1

- 削除 1

- 共有SQL領域からのロード 1

- DBMS_SPMを使用したロード 1

- SQL計画の取得 1

- SQL計画ディレクティブ

- カーディナリティの見積りの誤り 1

- 管理 1

- SQL計画の展開

- 展開タスクの管理 1

- SQL計画履歴 1

- SQL計画管理

- 計画の自動取得 1

- 利点 1

- DBMS_SPM 1

- 概要 1

- SQLチューニング・セットからの計画のロード 1

- 計画の手動取得 1

- 計画の取得 1

- 計画の展開 1 , 2 , 3

- 計画の選択 1 , 2

- 計画検証 1

- 目的 1

- SPM Evolve Advisor 1

- SQL計画ベースライン 1 , 2

- SQL計画の取得 1

- SQLの処理

- セマンティクス・チェック 1

- 共有プール・チェック 1

- ステージ 1

- 構文チェック 1

- SQLプロファイル

- SQL計画ベースライン 1

- SQL文のログ 1

- SQL文

- 索引不使用 1

- 索引使用の保証 1

- 実行計画 1

- 索引データの修正 1

- SQLテスト・ケース・ビルダー 1

- SQLテスト・ケース 1

- SQLトレース機能

- 出力 1

- 文の切捨て 1

- トレース・ファイル 1

- SQLトレース・ファイル 1

- SQLチューニング

- 定義 1

- 概要 1

- 事前 1

- 目的 1

- 事後 1

- ツールの概要 1

- SQLチューニング・アドバイザ

- 概要 1

- APIを使用した管理 1

- 分析 1

- アーキテクチャ 1

- 制御 1

- 入力ソース 1 , 2

- プラガブル・データベース 1 , 2

- 使用 1 , 2

- SQLチューニング・セット

- SQL計画ベースラインでロード 1

- プラガブル・データベース 1

- SQLチューニング・セット

- APIによる管理 1

- スター・クエリー 1

- 開始列

- パーティション化とEXPLAIN PLAN文 1

- スター型変換 1

- STATEMENT_ID列

- PLAN_TABLE表 1 , 2

- 統計, オプティマイザ

- 適応統計 1

- 自動収集 1

- バルク・ロード 1

- カーディナリティ 1

- コレクション 1

- 列グループ 1

- 列グループ 1 , 2

- 動的 1 , 2 , 3 , 4 , 5

- 動的統計 1

- エクスポートとインポート 1

- 拡張 1

- 同時収集 1

- 増分 1 , 2 , 3 , 4

- 索引 1

- 前のバージョンのリストアに関する制限 1

- 手動収集 1

- 収集の監視 1

- プリファレンス 1

- システム 1 , 2 , 3

- ユーザー定義 1

- 終了列

- パーティション化とEXPLAIN PLAN文 1

- ストアド・アウトライン

- カテゴリ 1

- 移行の目的 1

- 副問合せ

- NOT IN 1

- システム統計 1

T

- 表クラスタ 1

- 表拡張

- 概要 1

- 仕組み 1

- 目的 1

- シナリオ 1

- 表統計 1

- 一時表, グローバル 1

- 設計のテスト 1

- スループット

- オプティマイザの目標 1

- TIMESTAMP列

- PLAN_TABLE表 1 , 2

- TKPROF_TABLE 1

- TKPROFプログラム

- 出力SQLスクリプトの編集 1

- 出力の例 1

- 出力SQLスクリプトの生成 1

- 行ソースの操作 1

- EXPLAIN PLAN文の使用 1

- 待機イベント情報 1

- 上位頻度ヒストグラム 1 , 2

- トレース

- trcsessとの統合 1

- ファイルの識別 1

- 変換, 問合せ

- 表拡張の目的 1

- 表拡張 1 , 2 , 3

- trcsessユーティリティ 1

- トリクル・ロールアウトの方法 1

- チューニング

- 論理構造 1

U

- 一意性 1

- USER_ID列, TKPROF_TABLE 1

V

- V$SQL_PLAN_STATISTICS_ALLビュー

- 実行計画の情報表示に使用 1

- V$SQL_PLAN_STATISTICSビュー

- 実行計画の統計表示に使用 1

- V$SQL_PLANビュー

- 実行計画の表示に使用 1

- V$SQLAREAビュー 1

- 設計の検証 1

W

- ワークロード 1

Oracleの法律上の注意点

コピーライト

Copyright © 1994-2017, Oracle and/or its affiliates. All rights reserved.

ライセンス制約の保証と結果的に生じる損害の免責

このソフトウェアおよび関連ドキュメントの使用と開示は、ライセンス契約の制約条件に従うものとし、知的財産に関する法律により保護されています。ライセンス契約で明示的に許諾されている場合もしくは法律によって認められている場合を除き、形式、手段に関係なく、いかなる部分も使用、複写、複製、翻訳、放送、修正、ライセンス供与、送信、配布、発表、実行、公開または表示することはできません。このソフトウェアのリバース・エンジニアリング、逆アセンブル、逆コンパイルは互換性のために法律によって規定されている場合を除き、禁止されています。

保証免責

ここに記載された情報は予告なしに変更される場合があります。また、誤りが無いことの保証はいたしかねます。誤りを見つけた場合は、オラクルまでご連絡ください。

制限付権利について

このソフトウェアまたは関連ドキュメントを、米国政府機関もしくは米国政府機関に代わってこのソフトウェアまたは関連ドキュメントをライセンスされた者に提供する場合は、次の通知が適用されます。

U.S. GOVERNMENT END USERS: Oracle programs, including any operating system, integrated software, any programs installed on the hardware, and/or documentation, delivered to U.S. Government end users are "commercial computer software" pursuant to the applicable Federal Acquisition Regulation and agency-specific supplemental regulations. As such, use, duplication, disclosure, modification, and adaptation of the programs, including any operating system, integrated software, any programs installed on the hardware, and/or documentation, shall be subject to license terms and license restrictions applicable to the programs. No other rights are granted to the U.S. Government.

危険な用途への使用について

このソフトウェアまたはハードウェアは様々な情報管理アプリケーションでの一般的な使用のために開発されたものです。このソフトウェアまたはハードウェアは、危険が伴うアプリケーション(人的傷害を発生させる可能性があるアプリケーションを含む)への用途を目的として開発されていません。このソフトウェアまたはハードウェアを危険が伴うアプリケーションで使用する際、安全に使用するために、適切な安全装置、バックアップ、冗長性(redundancy)、その他の対策を講じることは使用者の責任となります。このソフトウェアまたはハードウェアを危険が伴うアプリケーションで使用したことに起因して損害が発生しても、Oracle Corporationおよびその関連会社は一切の責任を負いかねます。

商標と登録商標について

OracleおよびJavaはオラクルおよびその関連会社の登録商標です。その他の社名、商品名等は各社の商標または登録商標である場合があります。

Intel、Intel Xeonは、Intel Corporationの商標または登録商標です。すべてのSPARCの商標はライセンスをもとに使用し、SPARC International, Inc.の商標または登録商標です。AMD、Opteron、AMDロゴ、AMD Opteronロゴは、Advanced Micro Devices, Inc.の商標または登録商標です。UNIXは、The Open Groupの登録商標です。

第三者のコンテンツ、製品、サービスに対する免責事項

このソフトウェアまたはハードウェア、そしてドキュメントは、第三者のコンテンツ、製品、サービスへのアクセス、あるいはそれらに関する情報を提供することがあります。適用されるお客様とOracle Corporationとの間の契約に別段の定めがある場合を除いて、Oracle Corporationおよびその関連会社は、第三者のコンテンツ、製品、サービスに関して一切の責任を負わず、いかなる保証もいたしません。適用されるお客様とOracle Corporationとの間の契約に定めがある場合を除いて、Oracle Corporationおよびその関連会社は、第三者のコンテンツ、製品、サービスへのアクセスまたは使用によって損失、費用、あるいは損害が発生しても一切の責任を負いかねます。

Pre-General Availability (一般提供前)版のドキュメントについて

このドキュメントがPre-General Availability (一般提供前)版の場合:

このドキュメントはPre-General Availability (一般提供前)版であり、デモおよび暫定使用のみを目的としたものです。このソフトウェアを使用するハードウェアに限定するものではありません。Oracle Corporationおよびその関連会社は、このドキュメントに関して一切の責任を負わず、いかなる保証もいたしません。また、このドキュメントを使用したことによって損失、費用、あるいは損害が発生しても、一切の責任を負いかねます。

非公開のPre-General Availability (一般提供前)版のドキュメントについて

このドキュメントが非公開のPre-General Availability (一般提供前)版の場合:

このドキュメントに含まれる情報は、情報の共有のみを目的としたものであって、顧客諮問委員会(Customer Advisory Board)のメンバーとしてのお客様の立場でのみ、またはお客様のPre-General Availability Trial Agreement (Pre-GAトライアル契約)のみに従って検討されるべきものとします。マテリアル、コード、または機能の提供をお約束するものではなく、購入決定を行う際の判断材料とすべきではありません。このドキュメントに記載されている特徴または機能の開発、リリースおよび時期については、オラクルの裁量により決定されます。

このドキュメントには、ソフトウェアまたは印刷物などの形式を問わず、オラクルが独占的な権利を有する財産的情報が含まれています。この機密資料へのアクセスと使用は、お客様とオラクルとの間で締結され、お客様が遵守に同意した、Oracle Master Agreement、Oracle License and Oracle Services Agreement (オラクル・ライセンスおよびサービスに関する契約書)、Oracle Partner Network Agreement、Oracle Distribution Agreementまたはその他のライセンス契約の条件に従うものとします。このドキュメントとその内容の開示、コピー、複製および配布には、オラクルによる事前の承諾を必要とします。このドキュメントはライセンス契約の一部となるものではなく、オラクルおよびその子会社や関連会社との契約を構成するものではありません。

ドキュメントのアクセシビリティ

オラクルのアクセシビリティについての詳細情報は、Oracle Accessibility ProgramのWebサイト(http://www.oracle.com/pls/topic/lookup?ctx=acc&id=docacc)を参照してください。

Oracle Supportへのアクセス

サポートをご契約のお客様には、My Oracle Supportを通して電子支援サービスを提供しています。詳細情報は(http://www.oracle.com/pls/topic/lookup?ctx=acc&id=info)か、聴覚に障害のあるお客様は(http://www.oracle.com/pls/topic/lookup?ctx=acc&id=trs)を参照してください。