Oracleで次のSQLステートメントを実行しようとしていますが、実行には時間がかかります。
SELECT orderID FROM tasks WHERE orderID NOT IN
(SELECT DISTINCT orderID FROM tasks WHERE
engineer1 IS NOT NULL AND engineer2 IS NOT NULL)
IN句にあるサブパーツだけを実行すると、Oracleで非常に高速に実行されます。
SELECT DISTINCT orderID FROM tasks WHERE
engineer1 IS NOT NULL AND engineer2 IS NOT NULL
Oracleでステートメント全体にこれほど長い時間がかかるのはなぜですか? SQL Serverでは、ステートメント全体がすばやく実行されます。
あるいは、使用すべきより単純な/異なる/より良いSQLステートメントはありますか?
問題に関する詳細:
違いが生じる場合に備えて、テーブルには最大12万行あり、注文ごとに3つのタスクがあるため、最大4万の異なる注文があります。
回答への回答:
元のSQLステートメントでは、サブクエリはSQLステートメントの最初の部分の各行に対して毎回実行されると思います-静的であり、1回だけ実行する必要がありますか?
実行中
ANALYZE TABLE tasks COMPUTE STATISTICS;
元のSQLステートメントの実行がはるかに高速になりました。
なぜこれをしなければならないのか、そしていつまた実行する必要があるのか、まだ興味がありますか?
統計は、さまざまな実行プランの効率を決定するために必要なOracleのコストベースのオプティマイザー情報を提供します。たとえば、テーブル内の行数、行の平均幅、列ごとの最大値と最小値、列ごとの個別の値の数などです。 、インデックスのクラスタリング係数など。
小さなデータベースでは、毎晩統計を収集してそのままにしておくジョブを設定できます。実際、これは10g未満のデフォルトです。大規模な実装の場合、通常、実行プランの安定性とデータの変更方法を比較検討する必要がありますが、これは難しいバランスです。
Oracleには、実行時に関連する統計を決定するためにテーブルをサンプリングするために使用される「動的サンプリング」と呼ばれる機能もあります。これは、サンプリングのオーバーヘッドが、長時間実行されるクエリの潜在的なパフォーマンスの向上よりも重要であるデータウェアハウスでより頻繁に使用されます。
多くの場合、このタイプの問題は、関連するテーブルを分析すると解消されます(したがって、Oracleはデータの分散についてより良いアイデアを持っています)
ANALYZE TABLE tasks COMPUTE STATISTICS;
「IN」句は、Oracleではかなり遅いことが知られています。実際、Oracleの内部クエリオプティマイザは、「IN」を含むステートメントを適切に処理できません。 「EXISTS」を使用してみてください:
SELECT orderID FROM tasks WHERE orderID NOT EXISTS
(SELECT DISTINCT orderID FROM tasks WHERE
engineer1 IS NOT NULL AND engineer2 IS NOT NULL)`print("code sample");`
注意:クエリが同じデータ結果を作成するかどうかを確認してください。
エディスは言う:おっと、クエリはうまく形成されていませんが、一般的な考え方は正しいです。 Oracleは、2番目の(内部)クエリの全表スキャンを実行し、結果を作成してから、最初の(外部)クエリと比較する必要があるため、速度が低下します。試してみてください
SELECT orderID AS oid FROM tasks WHERE NOT EXISTS
(SELECT DISTINCT orderID AS oid2 FROM tasks WHERE
engineer1 IS NOT NULL AND engineer2 IS NOT NULL and oid=oid2)
または似たようなもの;-)
代わりに結合を使用してみます
SELECT
t.orderID
FROM
tasks t
LEFT JOIN tasks t1
ON t.orderID = t1.orderID
AND t1.engineer1 IS NOT NULL
AND t1.engineer2 IS NOT NULL
WHERE
t1.orderID IS NULL
また、元のクエリが次のように指定されていると、おそらく理解しやすくなります。
SELECT orderID FROM orders WHERE orderID NOT IN
(SELECT DISTINCT orderID FROM tasks WHERE
engineer1 IS NOT NULL AND engineer2 IS NOT NULL)
(すべての注文がリストされた注文テーブルがあると仮定します)
次に、結合を使用して次のように書き換えることができます。
SELECT
o.orderID
FROM
orders o
LEFT JOIN tasks t
ON o.orderID = t.orderID
AND t.engineer1 IS NOT NULL
AND t.engineer2 IS NOT NULL
WHERE
t.orderID IS NULL
いくつかの質問:
同じクエリを作成する別の方法は次のとおりです。
select orderid from tasks
minus
select orderid from tasks
where engineer1 IS NOT NULL AND engineer2 IS NOT NULL
ただし、クエリに「orders」テーブルが含まれることを期待します。
select orderid from ORDERS
minus
select orderid from tasks
where engineer1 IS NOT NULL AND engineer2 IS NOT NULL
または
select orderid from ORDERS
where orderid not in
( select orderid from tasks
where engineer1 IS NOT NULL AND engineer2 IS NOT NULL
)
または
select orderid from ORDERS
where not exists
( select null from tasks
where tasks.orderid = orders.orderid
and engineer1 IS NOT NULL OR engineer2 IS NOT NULL
)
私はTZQTZIOに同意します、私はあなたの質問を受け取りません。
クエリが理にかなっていると想定する場合は、いくつかの提案としてEXISTSを使用してみて、INを回避することをお勧めします。 INは必ずしも悪いわけではなく、実際にはEXISTSよりもパフォーマンスが優れていることを示す場合があります。
質問のタイトルはあまり役に立ちません。このクエリを1つのOracleデータベースに設定して、実行速度を遅くし、別のデータベースで高速に実行することができます。データベースがクエリ、オブジェクト統計、SYSスキーマ統計、パラメータをどのように解決するか、およびサーバーのパフォーマンスを決定する多くの要因があります。ここでは、SQLServerとOracleの違いは問題ではありません。
クエリの調整とパフォーマンスに関心があり、検索するGoogle用語の詳細を知りたい場合は、「OaktableOracle」と「Oraclejonathanlewis」を使用してください。
「なぜこれをしなければならないのか、そしていつまた実行する必要があるのか、私はまだ興味がありますか?」
統計は、さまざまな実行プランの効率を決定するために必要なOracleのコストベースのオプティマイザー情報を提供します。たとえば、テーブル内の行数、行の平均幅、列ごとの最大値と最小値、列ごとの個別の値の数などです。 、インデックスのクラスタリング係数など。
小さなデータベースでは、毎晩統計を収集してそのままにしておくジョブを設定できます。実際、これは10g未満のデフォルトです。大規模な実装の場合、通常、実行プランの安定性とデータの変更方法を比較検討する必要がありますが、これは難しいバランスです。
Oracleには、実行時に関連する統計を決定するためにテーブルをサンプリングするために使用される「動的サンプリング」と呼ばれる機能もあります。これは、サンプリングのオーバーヘッドが、長時間実行されるクエリの潜在的なパフォーマンスの向上よりも重要であるデータウェアハウスでより頻繁に使用されます。
何人かの人々はほぼ正しいSQLを持っていると思いますが、内部クエリと外部クエリの間の結合が欠落しています。
これを試して:
SELECT t1.orderID
FROM tasks t1
WHERE NOT EXISTS
(SELECT 1
FROM tasks t2
WHERE t2.orderID = t1.orderID
AND t2.engineer1 IS NOT NULL
AND t2.engineer2 IS NOT NULL)
テーブル内の行のどの割合が「engineer1 IS NOT NULL AND engineer2 IS NOTNULL」」の条件を満たしていますか?
これにより、(大まかに)インデックスを使用して関連するorderidを取得する価値があるかどうかがわかります。
インデックス付けされていないケースを非常にうまく処理するクエリをOracleで作成する別の方法は、次のとおりです。
select distinct orderid
from
(
select orderid,
max(case when engineer1 is null and engineer2 is null then 0 else 1)
over (partition by orderid)
as max_null_Finder
from tasks
)
where max_null_Finder = 0
Oracleオプティマイザは、MINUSステートメントを適切に処理します。 MINUSを使用してクエリを書き直すと、非常に高速に実行される可能性があります。
SELECT orderID FROM tasks
MINUS
SELECT DISTINCT orderID FROM tasks WHERE
engineer1 IS NOT NULL AND engineer2 IS NOT NULL
新しいテイク。
Iff:
および
その後これはあなたが望むことをするはずです:
SELECT orderID
FROM tasks
GROUP BY orderID
HAVING COUNT(engineer1) = 0 AND COUNT(engineer2) = 0
テストしてください。
私はΤΖΩΤΖΙΟΥとwearejimboにあなたの質問が...
SELECT DISTINCT orderID FROM Tasks
WHERE Engineer1 IS NULL OR Engineer2 IS NULL;
SQL Serverについてはわかりませんが、null行がインデックスに含まれていないため、このクエリはインデックスを利用できません。これに対する解決策は、null値の行のみを含む関数ベースのインデックスを作成できるようにクエリを書き直すことです。これはNVL2で実行できますが、SQLServerに移植できない可能性があります。
最善の答えは、あなたの基準を満たすものではなく、プラットフォームごとにそのプラットフォームに最適な異なるステートメントを書くことだと思います。
あなたのクエリはと同じではありません
SELECT orderID FROM tasks
WHERE engineer1 IS NOT NULL OR engineer2 IS NOT NULL
?
どうですか:
SELECT DISTINCT orderID FROM tasks t1 WHERE NOT EXISTS (SELECT * FROM tasks t2 WHERE t2.orderID=t1.orderID AND (engineer1 IS NOT NULL OR engineer2 IS NOT NULL));
私は最適化の第一人者ではありませんが、Oracleデータベースのいくつかのインデックスを見落としているかもしれません。
別のオプションは、マイナスを使用することです(MSSQLを除く)
SELECT orderID FROM tasks
MINUS
SELECT DISTINCT orderID FROM tasks WHERE engineer1 IS NOT NULL
AND engineer2 IS NOT NULL