web-dev-qa-db-ja.com

OracleのOrder By句のパフォーマンスを向上させる方法

OracleデータベースにUAVT_BINAというテーブルがあり、28897352行あります。私が書くとき:

select * from UAVT_BINA

dBは0.1秒で応答します。しかし、私が書くとき

select * from UAVT_BINA order by CBSBMKODU

dBは66秒で応答します。 CSBMKODUにインデックスがあります。アプリケーション標準のためにデータを並べ替える必要があります。パフォーマンスを向上させるにはどうすればよいですか?

これは、ソートされたクエリのプランの説明の結果です

enter image description here

前に、フレームワーク側で動的クエリを使用し、フィルタリングされたデータの単純な結果クエリがここにあると述べました

SELECT 
"Project2"."C1" AS "C1", 
"Project2"."CRTM" AS "CRTM", 
"Project2"."ADANO" AS "ADANO", 
"Project2"."BINADURUMSTRING" AS "BINADURUMSTRING", 
"Project2"."C2" AS "C2", 
"Project2"."BINANUMARATAJTIPISTRING" AS "BINANUMARATAJTIPISTRING", 
"Project2"."BINAYAPITIPISTRING" AS "BINAYAPITIPISTRING", 
"Project2"."BLOKADI" AS "BLOKADI", 
"Project2"."CSBMADI" AS "CSBMADI", 
"Project2"."C3" AS "C3", 
"Project2"."DISKAPINO" AS "DISKAPINO", 
"Project2"."C4" AS "C4", 
"Project2"."C5" AS "C5", 
"Project2"."C6" AS "C6", 
"Project2"."NITELIKSTRING" AS "NITELIKSTRING", 
"Project2"."C7" AS "C7", 
"Project2"."PAFTANO" AS "PAFTANO", 
"Project2"."PARSELNO" AS "PARSELNO", 
"Project2"."POSTAKODU" AS "POSTAKODU", 
"Project2"."SITEADI" AS "SITEADI", 
"Project2"."C8" AS "C8", 
"Project2"."C9" AS "C9", 
"Project2"."UPTRID" AS "UPTRID", 
"Project2"."UPTM" AS "UPTM", 
"Project2"."STATESTRING" AS "STATESTRING", 
"Project2"."STATEID" AS "STATEID", 
"Project2"."CRTRID" AS "CRTRID", 
"Project2"."MAHALLEADI" AS "MAHALLEADI", 
"Project2"."BINADURUMID" AS "BINADURUMID", 
"Project2"."BINANUMARATAJTIPIID" AS "BINANUMARATAJTIPIID", 
"Project2"."BINAYAPITIPIID" AS "BINAYAPITIPIID", 
"Project2"."MAHALLEID" AS "MAHALLEID"
FROM ( SELECT 
    "Distinct1"."DISKAPINO" AS "DISKAPINO", 
    "Distinct1"."SITEADI" AS "SITEADI", 
    "Distinct1"."BLOKADI" AS "BLOKADI", 
    "Distinct1"."POSTAKODU" AS "POSTAKODU", 
    "Distinct1"."CRTM" AS "CRTM", 
    "Distinct1"."CRTRID" AS "CRTRID", 
    "Distinct1"."UPTM" AS "UPTM", 
    "Distinct1"."UPTRID" AS "UPTRID", 
    "Distinct1"."STATEID" AS "STATEID", 
    "Distinct1"."STATESTRING" AS "STATESTRING", 
    "Distinct1"."ADANO" AS "ADANO", 
    "Distinct1"."PARSELNO" AS "PARSELNO", 
    "Distinct1"."PAFTANO" AS "PAFTANO", 
    "Distinct1"."BINADURUMSTRING" AS "BINADURUMSTRING", 
    "Distinct1"."BINADURUMID" AS "BINADURUMID", 
    "Distinct1"."BINAYAPITIPIID" AS "BINAYAPITIPIID", 
    "Distinct1"."BINAYAPITIPISTRING" AS "BINAYAPITIPISTRING", 
    "Distinct1"."BINANUMARATAJTIPIID" AS "BINANUMARATAJTIPIID", 
    "Distinct1"."BINANUMARATAJTIPISTRING" AS "BINANUMARATAJTIPISTRING", 
    "Distinct1"."NITELIKSTRING" AS "NITELIKSTRING", 
    "Distinct1"."CSBMADI" AS "CSBMADI", 
    "Distinct1"."MAHALLEID" AS "MAHALLEID", 
    "Distinct1"."MAHALLEADI" AS "MAHALLEADI", 
    1 AS "C1", 
     CAST( "Distinct1"."BINANO" AS number(19,0)) AS "C2", 
     CAST( "Distinct1"."CSBMID" AS number(19,0)) AS "C3", 
     CAST( "Distinct1"."ESKIBINAKIMLIKNO" AS number(19,0)) AS "C4", 
     CAST( "Distinct1"."ESKIBINAKODU" AS number(19,0)) AS "C5", 
     CAST( "Distinct1"."ID" AS number(19,0)) AS "C6", 
     CAST( "Distinct1"."NITELIKID" AS number(19,0)) AS "C7", 
     CAST( "Distinct1"."YOLALTIKATSAYISI" AS number(19,0)) AS "C8", 
     CAST( "Distinct1"."YOLUSTUKATSAYISI" AS number(19,0)) AS "C9"
    FROM ( SELECT DISTINCT 
        "Extent1"."ID" AS "ID", 
        "Extent1"."DISKAPINO" AS "DISKAPINO", 
        "Extent1"."SITEADI" AS "SITEADI", 
        "Extent1"."BLOKADI" AS "BLOKADI", 
        "Extent1"."POSTAKODU" AS "POSTAKODU", 
        "Extent1"."ESKIBINAKODU" AS "ESKIBINAKODU", 
        "Extent1"."CRTM" AS "CRTM", 
        "Extent1"."CRTRID" AS "CRTRID", 
        "Extent1"."UPTM" AS "UPTM", 
        "Extent1"."UPTRID" AS "UPTRID", 
        "Extent1"."STATEID" AS "STATEID", 
        "Extent1"."NITELIKID" AS "NITELIKID", 
        "Extent1"."STATESTRING" AS "STATESTRING", 
        "Extent1"."CSBMID" AS "CSBMID", 
        "Extent1"."ADANO" AS "ADANO", 
        "Extent1"."PARSELNO" AS "PARSELNO", 
        "Extent1"."PAFTANO" AS "PAFTANO", 
        "Extent1"."BINANO" AS "BINANO", 
        "Extent1"."YOLALTIKATSAYISI" AS "YOLALTIKATSAYISI", 
        "Extent1"."YOLUSTUKATSAYISI" AS "YOLUSTUKATSAYISI", 
        "Extent1"."ESKIBINAKIMLIKNO" AS "ESKIBINAKIMLIKNO", 
        "Extent1"."BINADURUMSTRING" AS "BINADURUMSTRING", 
        "Extent1"."BINADURUMID" AS "BINADURUMID", 
        "Extent1"."BINAYAPITIPIID" AS "BINAYAPITIPIID", 
        "Extent1"."BINAYAPITIPISTRING" AS "BINAYAPITIPISTRING", 
        "Extent1"."BINANUMARATAJTIPIID" AS "BINANUMARATAJTIPIID", 
        "Extent1"."BINANUMARATAJTIPISTRING" AS "BINANUMARATAJTIPISTRING", 
        "Extent1"."NITELIKSTRING" AS "NITELIKSTRING", 
        "Extent1"."CSBMADI" AS "CSBMADI", 
        "Extent1"."MAHALLEID" AS "MAHALLEID", 
        "Extent1"."MAHALLEADI" AS "MAHALLEADI"
        FROM  (SELECT 
"UAVT_BINA_EVW"."ID" AS "ID", 
"UAVT_BINA_EVW"."DISKAPINO" AS "DISKAPINO", 
"UAVT_BINA_EVW"."SITEADI" AS "SITEADI", 
"UAVT_BINA_EVW"."BLOKADI" AS "BLOKADI", 
"UAVT_BINA_EVW"."POSTAKODU" AS "POSTAKODU", 
"UAVT_BINA_EVW"."ESKIBINAKODU" AS "ESKIBINAKODU", 
"UAVT_BINA_EVW"."CRTM" AS "CRTM", 
"UAVT_BINA_EVW"."CRTRID" AS "CRTRID", 
"UAVT_BINA_EVW"."UPTM" AS "UPTM", 
"UAVT_BINA_EVW"."UPTRID" AS "UPTRID", 
"UAVT_BINA_EVW"."STATEID" AS "STATEID", 
"UAVT_BINA_EVW"."NITELIKID" AS "NITELIKID", 
"UAVT_BINA_EVW"."STATESTRING" AS "STATESTRING", 
"UAVT_BINA_EVW"."CSBMID" AS "CSBMID", 
"UAVT_BINA_EVW"."ADANO" AS "ADANO", 
"UAVT_BINA_EVW"."PARSELNO" AS "PARSELNO", 
"UAVT_BINA_EVW"."PAFTANO" AS "PAFTANO", 
"UAVT_BINA_EVW"."BINANO" AS "BINANO", 
"UAVT_BINA_EVW"."YOLALTIKATSAYISI" AS "YOLALTIKATSAYISI", 
"UAVT_BINA_EVW"."YOLUSTUKATSAYISI" AS "YOLUSTUKATSAYISI", 
"UAVT_BINA_EVW"."ESKIBINAKIMLIKNO" AS "ESKIBINAKIMLIKNO", 
"UAVT_BINA_EVW"."BINADURUMSTRING" AS "BINADURUMSTRING", 
"UAVT_BINA_EVW"."BINADURUMID" AS "BINADURUMID", 
"UAVT_BINA_EVW"."BINAYAPITIPIID" AS "BINAYAPITIPIID", 
"UAVT_BINA_EVW"."BINAYAPITIPISTRING" AS "BINAYAPITIPISTRING", 
"UAVT_BINA_EVW"."BINANUMARATAJTIPIID" AS "BINANUMARATAJTIPIID", 
"UAVT_BINA_EVW"."BINANUMARATAJTIPISTRING" AS "BINANUMARATAJTIPISTRING", 
"UAVT_BINA_EVW"."NITELIKSTRING" AS "NITELIKSTRING", 
"UAVT_BINA_EVW"."CSBMADI" AS "CSBMADI", 
"UAVT_BINA_EVW"."MAHALLEID" AS "MAHALLEID", 
"UAVT_BINA_EVW"."MAHALLEADI" AS "MAHALLEADI"
FROM "ATLAS"."UAVT_BINA_EVW" "UAVT_BINA_EVW") "Extent1"
        INNER JOIN (SELECT 
"BS_AUTHORIZEDREGION_EVW"."ID" AS "ID", 
"BS_AUTHORIZEDREGION_EVW"."MAHALLEID" AS "MAHALLEID", 
"BS_AUTHORIZEDREGION_EVW"."KOYID" AS "KOYID", 
"BS_AUTHORIZEDREGION_EVW"."BUCAKID" AS "BUCAKID", 
"BS_AUTHORIZEDREGION_EVW"."ILCEID" AS "ILCEID", 
"BS_AUTHORIZEDREGION_EVW"."ROLEID" AS "ROLEID", 
"BS_AUTHORIZEDREGION_EVW"."USERID" AS "USERID",
"BS_AUTHORIZEDREGION_EVW"."ILID" AS "ILID",
"BS_AUTHORIZEDREGION_EVW"."ATUHORIZEDREGIONTYPEID" AS "ATUHORIZEDREGIONTYPEID"
FROM "ATLAS"."BS_AUTHORIZEDREGION_EVW" "BS_AUTHORIZEDREGION_EVW") "Extent2" ON (("Extent1"."MAHALLEID" = "Extent2"."MAHALLEID") OR (("Extent1"."MAHALLEID" IS NULL) AND ("Extent2"."MAHALLEID" IS NULL))) AND ((:p__linq__0 = "Extent2"."USERID") OR ((:p__linq__0 IS NULL) AND ("Extent2"."USERID" IS NULL)))
    )  "Distinct1"
)  "Project2"
ORDER BY "Project2"."CRTM" DESC

クエリはインデックスを使用していないようです。インデックスを使用する場合は、次のことを行う必要があります。

  • インデックスの最初のエントリをフェッチします
    • rOWIDによってこの行の他のデータでテーブルを検索します
  • インデックスの次のエントリをフェッチします
    • rOWIDによってこの行の他のデータでテーブルを検索します
  • インデックスの次のエントリをフェッチします
    • テーブルからこの行に属する他のデータを検索します
  • ...

Select句に*があるため、テーブル内のデータのこのルックアップが必要です。インデックスには行のすべてのデータが含まれていないと思います。したがって、1つの

select *
from BINA
order by CBSBMKODU

ステートメントを使用すると、インデックスを避けたほうが速くなりますが、テーブルからすべてのデータをフェッチして並べ替えることができます。すべてのデータをフェッチして並べ替えるには、66秒かかります。この後、最初のレコードをクライアントに送信できます。

とにかくあなたのデータベースにインデックスを使用するように説得することができます(私はそれらがうまくいくかどうかわかりません)

セッション/システム パラメーターOPTIMIZER_MODE を使用し、FIRST_ROWSに設定します。次に、データベースは最初の行がフェッチされるまでの時間を最小限にしようとするため、インデックスを使用できます。

オプティマイザをインデックスに導くためのヒント を使用して、クエリを次のように変更します

select /*+ INDEX(BINA CBSBMKODU) */ *
from BINA
order by CBSBMKODU

または、データの構造を変更することもできます。

行のすべてのフィールドが含まれるようにインデックスCBSBMKODUを変更します。次に、データベースは行のすべての値をインデックスから取得でき、テーブルで検索する必要はありません。したがって、インデックスによるアクセスを使用する可能性があり、ダウはテーブルをスキャンしようとしません。このソリューションでは、テーブルの2つの完全なコピーを保存しています。1つはテーブル自体に、もう1つはインデックスCBSBMKODUに保存しています。

または、テーブルの構造を変更して、通常のヒープ構成テーブルの代わりに インデックス構成テーブル にすることもできます。次に、テーブルはすでにインデックスのように編成されており、データを2回保持する必要はありません。

しかし、これらすべてのソリューションはすべて、本当に満足できるものではありません。データベースに関してこれらの「アプリケーション標準」を確認する必要があります。明らかに、事前にソートされたデータの3000万行を返さない方が良いでしょう。

1
miracle173

このクエリの本質を抽出しようとすると、次のクエリが得られます。

_SELECT Project2.*
FROM 
    (SELECT Distinct1.*
    FROM 
        (SELECT DISTINCT Extent1.*
        FROM (SELECT UAVT_BINA_EVW.* FROM ATLAS.UAVT_BINA_EVW UAVT_BINA_EVW) Extent1
            INNER JOIN (SELECT BS_AUTHORIZEDREGION_EVW.* FROM ATLAS.BS_AUTHORIZEDREGION_EVW BS_AUTHORIZEDREGION_EVW) Extent2 ON 
                ((Extent1.MAHALLEID = Extent2.MAHALLEID) 
                    OR ((Extent1.MAHALLEID IS NULL) AND (Extent2.MAHALLEID IS NULL))) 
                AND ((:p__linq__0 = Extent2.USERID) OR ((:p__linq__0 IS NULL) AND (Extent2.USERID IS NULL)))
        ) Distinct1
    ) Project2
ORDER BY Project2.CRTM DESC;
_

これらすべてのサブクエリの理由はわかりません。私が間違っていなければ、これは

_SELECT DISTINCT ...
FROM ATLAS.UAVT_BINA_EVW UAVT_BINA_EVW Extent1
    INNER JOIN ATLAS.BS_AUTHORIZEDREGION_EVW Extent2 ON 
        ((Extent1.MAHALLEID = Extent2.MAHALLEID) 
            OR ((Extent1.MAHALLEID IS NULL) AND (Extent2.MAHALLEID IS NULL))) 
        AND ((:p__linq__0 = Extent2.USERID) OR ((:p__linq__0 IS NULL) AND (Extent2.USERID IS NULL)))
ORDER BY CRTM DESC;
_

INNER JOIN ... ON ((Extent1.MAHALLEID = Extent2.MAHALLEID) OR ((Extent1.MAHALLEID IS NULL) AND (Extent2.MAHALLEID IS NULL))

_FULL OUTER JOIN_のように見えるので、最後にクエリを次のように減らすことができます。

_SELECT DISTINCT ...
FROM ATLAS.UAVT_BINA_EVW UAVT_BINA_EVW Extent1
    FULL OUTER JOIN ATLAS.BS_AUTHORIZEDREGION_EVW Extent2 ON Extent1.MAHALLEID = Extent2.MAHALLEID 
WHERE :p__linq__0 = Extent2.USERID OR (:p__linq__0 IS NULL AND Extent2.USERID IS NULL)
ORDER BY CRTM DESC;
_

ご覧のとおり、唯一の述語は_:p__linq__0 = Extent2.USERID_にあります(通常、これは_Extent2.USERID = :p__linq__0_と記述します-_ATLAS.BS_AUTHORIZEDREGION_EVW.USERID_にインデックスがありますか?これはOracleが作成する唯一のインデックスですかもしれません使用。

DISTINCT句のため、CRTMのインデックスは役に立たないと思います。これにより、Oracleは結果全体を読み取ってTEMPセグメントに入れ、ソートするよう強制されますが、ここではわかりません。

1