インデックスを作成せずにOracleクエリのパフォーマンスを改善する
-
04-07-2019 - |
質問
インデックスを作成せずにOracleクエリのクエリパフォーマンスを改善するためにできることは何ですか?
次のクエリは、より高速に実行しようとしています:
SELECT c.ClaimNumber, a.ItemDate, c.DTN, b.FilePath
FROM items a,
itempages b,
keygroupdata c
WHERE a.ItemType IN (112,115,189,241)
AND a.ItemNum = b.ItemNum
AND b.ItemNum = c.ItemNum
ORDER BY a.DateStored DESC
これらの列にはインデックスが作成されておらず、各テーブルには何百万ものレコードが含まれています。言うまでもなく、クエリの実行には3分半以上かかります。これは実稼働環境のサードパーティデータベースであり、インデックスを作成することは許可されていないため、クエリ自体のパフォーマンスを改善する必要があります。
ありがとう!
解決
最初に、クエリをANSI標準に書き換えます:
SELECT c.ClaimNumber, a.ItemDate, c.DTN, b.FilePath
FROM items a
INNER JOIN itempages b ON b.ItemNum = a.ItemNum
INNER JOIN keygroupdata c ON c.ItemNum = b.ItemNum
WHERE a.ItemType IN (112,115,189,241)
ORDER BY a.DateStored DESC
これにより、何が起こっているかを読みやすく理解しやすくなります。また、実際に大きな問題を引き起こす可能性のある間違い(クロスジョイン)を行わないようにします。次に、Explainプランを取得して、そのクエリでDBMSが何をしているのかを確認します。いくつかのインデックスを使用しようとしていますか?テーブルを正しく結合していますか?
次に、作業中のテーブルを確認して、クエリを高速化するために使用できるインデックスが既に存在するかどうかを確認します。最後に、他のみんなが提案したように、Order By句を削除して、コードでそれを行うだけです。
他のヒント
最初に行うべきであるように、サードパーティに結合列のインデックスを作成するよう依頼してください!インデックスがなければ、Oracleはブルートフォース以外に何もすることはありません。
これらのテーブルのいずれかでマテリアライズドビューを作成してみてください。次に、マテリアライズドビューにインデックスを作成して、クエリの高速化に役立てることができます(これは、生のテーブルではなくマテリアライズドビューをクエリします)。
もちろん、基礎となるテーブルが更新された場合、ビューとインデックスを更新する必要があります。
まず、実行計画を確認します。クエリ実行の各段階で取得される行の数を正確に反映していますか?述語「a.ItemType IN(112,115,189,241)」はどの程度選択的ですか?実行計画には、結合または並べ替えのための一時ディスク領域の使用が示されていますか?
実際には、質問を修正して実行計画を含めることができます。
また、ハッシュ結合が無効になっていないことを確認してください。これは、OLTPで調整されたシステムではOracleのバルクデータを等価結合する最も効率的な方法である場合があります。彼らは実行計画に現れるべきです。
ここに示すように、テーブルを結合する前にアイテムタイプでフィルタリングを試すことができます。
9iより前のOracleで実行している場合、これは驚くべき利点をもたらすことがあります。
select
c.claimnumber,
a.itemdate,
c.dtn,
b.filepath
from
(
select itemdate
from items it
where it.itemtype in(112,115,189,241)
) a
itempages b,
keygroupdata c
where a.itemnum = b.itemnum
and b.itemnum = c.itemnum
ヒントを追加してみてください/ + RULE /または/ + ORDERED /驚くべき結果が得られます。
SELECT /*+RULE*/
c.ClaimNumber, a.ItemDate, c.DTN, b.FilePath
FROM
items a,
itempages b,
keygroupdata c
WHERE a.ItemType IN (112,115,189,241)
AND a.ItemNum = b.ItemNum
AND b.ItemNum = c.ItemNum
ORDER BY a.DateStored DESC
クエリ入力が定数または予測可能( itemType IN(...)
)の場合、代替方法はクエリを1日に1回または2回実行し、結果をローカルに保存することです必要に応じてインデックス付きのテーブル。
その後、コストのかかるクエリを「オフライン」にして、インタラクティブクエリの結果をより速く/より良くすることができます。
これは頻繁に実行するクエリですか?このクエリを高速化するために必要なインデックスを作成することは、DB所有者の利益になると思われます。クエリの実行に費やしている3.5分は、運用環境に何らかの影響を与える必要があります!
また、彼らはテーブルの統計更新を実行していますか?結合順序はテーブルの統計に基づいて計算されるため、パフォーマンスが向上する可能性があります。
ところで、あなたは何ができますか?読むだけ?一時テーブルを作成してそれらにインデックスを配置できる場合は、テーブルの一時コピーを作成し、それらにインデックスを付けてから、一時コピーとのインデックスアシスト結合を実行することを検討できます。
このスレッドは非常に古いことは知っていますが、検索エンジンについては、オラクルで動作し、データに応じてはるかに高速な代替ソリューションを提供したかったのです。
with a as (
select
*
from
items
where
ItemType IN (112,115,189,241)
)
SELECT
c.ClaimNumber
, a.ItemDate
, c.DTN, b.FilePath
FROM
a,
itempages b,
keygroupdata c
WHERE
a.ItemNum = b.ItemNum
AND b.ItemNum = c.ItemNum
ORDER BY
a.DateStored DESC
WITH
句で / * + MATERIALIZE * /
ヒントを試すこともできます。
実際には、oracleの古い結合構文はansi sqlよりも読みやすいと思います^^
インデックスを作成しないと、そのクエリはテーブルサイズが大きくなるにつれて悪化するだけです。 そうは言っても、order by句を削除して、クライアント側でソートを実行してみてください。
冗長な要素のように思われる部分をwhere句に追加することで、オプティマイザーが選択するためのパスウェイを追加することで、メリットが得られる場合があります。
たとえば、A.ItemNum = B.ItemNum AND B.ItemNum = C.ItemNumがあります。 A.ItemNum = C.ItemNumも追加してみてください。ただし、オプティマイザーはそれ自体でそれを把握できるほど十分にインテリジェントであると確信しています。試してみる価値はあります。
ItemType列のデータ型に応じて、varcharの場合、次を使用すると実行速度が速くなる場合があります。Oracleは暗黙的な変換を行います。
SELECT c.ClaimNumber, a.ItemDate, c.DTN, b.FilePath
FROM items a,
itempages b,
keygroupdata c
WHERE ((a.ItemType IN ('112','115','189','241'))
AND (a.ItemNum = b.ItemNum)
AND (b.ItemNum = c.ItemNum))
ORDER BY a.DateStored DESC
これらのテーブルで統計が収集されていますか?そうでない場合、統計の収集は実行計画を変更する可能性がありますが、必ずしも良いとは限りません。
それとは別に、実行計画を見てください。最適でない順序でテーブルを結合していることがわかります(たとえば、フィルター条件を持つaと結合する前にbとcを結合している可能性があります)。
ヒントを使用して、アクセスパス、結合順序、または結合方法に影響を与えることができます。
更新:コメントに返信すると、これに移動しましたプレゼンテーション。役に立つか、少なくとも興味深いかもしれません。
インデックスがないと言う場合、これは定義された主キーまたは外部キーがないことを意味しますか?明らかにテーブルの分析と統計の収集は重要ですが、テーブルの結合方法を定義するなどのメタデータが存在しない場合、Oracleは不適切な実行パスを選択する可能性があります。
その場合、/ * + ORDERED * /などのヒントを使用することが、オプティマイザーが適切な実行パスを確実に選択できるようにする唯一のオプションです。また、外部キーと主キーを追加する価値がありますが、それらをDISABLEおよびVALIDATEとして定義します。
このコメントの有用性は、インデックスに対する嫌悪感がどこまで進んでいるかによって決まると思います。YMPV。
まずこのクエリでビューを作成し、このビューからテーブルを生成します。また、日付にインデックスを作成し、ジョブを作成して、システムがアイドル状態の真夜中にスケジュールします。
さて、インデックスを作成できないため、統計がすべて最新であることを確認し、クエリを次のように書き換えます:
as((*、++ MATERIALIZE * / ItemType、ItemNum、DateStored、ItemDate from items Type in(112,115,189,241)))
SELECT c.ClaimNumber、a.ItemDate、c.DTN、b.FilePath
から、
itempages b、
keygroupdata c
WHERE a.ItemNum = b.ItemNum
AND b.ItemNum = c.ItemNum
ORDER BY a.DateStored DESC
ORDER BYを削除
行をアプリケーションに戻した後、ソートを実行します。