3

次のクエリに関するガイダンスをいただければ幸いです。実験とその現在の進捗状況のリストがあります(簡単にするために、ステータスを4種類に減らしましたが、データには10の異なるステータスがあります)。最終的に、すべての未完了の実験の現在のステータスのリストを返す必要があります。

テーブルexp_statusが与えられると、

Experiment | ID     | Status
----------------------------
     A     |   1    | Starting 
     A     |   2    | Working On It
     B     |   3    | Starting
     B     |   4    | Working On It
     B     |   5    | Finished Type I
     C     |   6    | Starting
     D     |   7    | Starting
     D     |   8    | Working On It
     D     |   9    | Finished Type II
     E     |   10   | Starting
     E     |   11   | Working On It
     F     |   12   | Starting 
     G     |   13   | Starting
     H     |   14   | Starting
     H     |   15   | Working On It
     H     |   16   | Finished Type II

望ましい結果セット:

  Experiment | ID   | Status
----------------------------
     A     |   2    | Working On It
     C     |   6    | Starting
     E     |   11   | Working On It
     F     |   12   | Starting 
     G     |   13   | Starting

最新のID番号は、最新のステータスに対応します。

今、私が持っている現在のコードは150秒で実行されます。

    SELECT *
    FROM 
          (SELECT Experiment, ID, Status, 
          row_number () over (partition by Experiment
          order by ID desc) as rn
          FROM exp_status)
    WHERE rn = 1
    AND status NOT LIKE ('Finished%')

問題は、このコードは時間を無駄にするということです。結果セットは、390万のテーブルから引き出された45,000行です。これは、ほとんどの実験が終了ステータスにあるためです。コードは通過し、それらすべてを注文し、最後に終了したものだけを除外します。表の実験の約95%は終了段階にあります。最初にクエリですべての実験とその実験の「終了」がないステータスを選択する方法を理解できませんでした。次のことを試しましたが、パフォーマンスが非常に遅くなりました。

SELECT *
FROM exp_status
WHERE experiment NOT IN 
(
  SELECT experiment
  FROM exp_status
  WHERE status LIKE ('Finished%')
)

どんな助けでもいただければ幸いです!

4

3 に答える 3

2

あなたの要件を考えると、with を使用した現在のクエリはrow_number()、可能な限り最も効率的なものの 1 つだと思います。このクエリに時間がかかるのは、データをソートする必要があるからではなく、そもそも読み取るデータが非常に多いためです (余分な CPU 時間は、フェッチ時間に比べて無視できます)。さらに、最初のクエリは FULL SCAN を作成します。これは、大量のデータを読み取るための最良の方法です。

パフォーマンスを向上させたい場合は、読み取る行を大幅に減らす方法を見つける必要があります。2 番目のクエリは正しい方向に進みません。

  1. 「終了した」行がテーブル全体に分散され、すべての行の大部分を占める可能性が高いため、内側のクエリはフル スキャンになる可能性があります。
  2. 外側のクエリもフル スキャンであり、45k * (実験ごとのステータス変更の数) の一意でないインデックス スキャンよりも高速な ANTI-HASH JOIN である可能性があります。

したがって、2 番目のクエリには、少なくとも 2 倍の読み取り数 (および結合) があるようです。

本当に性能を上げたいのであれば、設計変更が必要になると思います。

たとえば、アクティブな実験のテーブルを作成し、このテーブルに参加できます。このテーブルは、具体化されたビューとして維持するか、実験ステータスを挿入するコードを変更して維持します。さらに進んで、最後のステータスをこのテーブルに保存できます。この「最後の状態」を維持することはおそらく余分な負担になりますが、これはパフォーマンスの向上によって正当化される可能性があります。

于 2012-07-11T15:27:08.843 に答える
1

テーブルのパーティション分割を検討してくださいstatus

www.orafaq.com/wiki/Partitioning_FAQ

これらのタイプのクエリが頻繁に発生する場合は、マテリアライズド ビューを作成して、集計を再計算する必要がないようにすることもできます。

クエリの実行計画を提供していただけますか。それらがなければ、時間がかかる正確な理由を知ることは困難です

于 2012-07-11T15:33:22.477 に答える
0

このバリアントを使用して、最初のクエリを少し改善できます。

select experiment
     , max(id) id
     , max(status) keep (dense_rank last order by id) status
  from exp_status
 group by experiment
having max(status) keep (dense_rank last order by id) not like 'Finished%'

プランを比較すると、一歩少ないことがわかります

よろしく、
ロブ。

于 2012-07-12T10:50:55.867 に答える