1

「log」という名前のテーブルがあるとします。その中には巨大なレコードがあります。

アプリケーションは通常、単純な SQL によってデータを取得します。

SELECT * 
FROM log 
WHERE logLevel=2 AND (creationData BETWEEN ? AND ?)

logLevelおよびcreationDataインデックスがありますが、レコードの数によってデータの取得に時間がかかります。

どうすればこれを修正できますか?

4

8 に答える 8

5

実行計画/「EXPLAIN PLAN」の結果を見てください。大量のデータを取得している場合、パフォーマンスを向上させるためにできることはほとんどありません。SELECTステートメントを変更して、関心のある列のみを含めることができますが、実行している論理読み取りの数は変更されないため、パフォーマンスへの影響はごくわずかであると思われます。

少数のレコードのみを取得する場合は、LogLevel のインデックスと CreationDate のインデックスでうまくいくはずです。

更新: SQL サーバーは、ほとんどの場合、大規模なデータベースの小さなサブセットをクエリすることを目的としています (たとえば、数百万のデータベースから単一の顧客レコードを返すなど)。本当に大規模なデータセットを返すように調整されているわけではありません。あなたが返すデータの量が本当に多い場合、あなたができることは一定量しかないので、私は尋ねる必要があります:

あなたが実際に達成しようとしていることは何ですか?

  • ユーザーにログ メッセージを表示している場合、ユーザーは一度に小さなサブセットにしか関心がないため、SQL データを効率的にページングする方法を検討することもできます。一度に記録するか、それでも非常に高速である必要があります。

  • ある種の統計分析を行おうとしている場合は、統計分析により適したデータ ストアにデータを複製することをお勧めします。(ただし、それは私の専門分野ではありません)

于 2010-08-16T14:43:52.230 に答える
4

1: 絶対に使用Select *
しないでください 2: インデックスが正しく、統計が最新であることを確認してください
3: (オプション) 特定の時間以降のログ データを見ていない場合 (私の経験では、発生した場合1 週間以上前であれば、おそらくログは必要ないでしょう) それをバックアップにアーカイブするジョブを設定し、未使用のレコードを削除します。これにより、テーブルのサイズが小さくなり、テーブルの検索にかかる時間が短縮されます。

于 2010-08-16T14:43:00.110 に答える
2

使用している SQL データベースの種類によっては、Horizaontal Partitioningを調べることができます。多くの場合、これはデータベース側で完全に実行できるため、コードを変更する必要はありません。

于 2010-08-16T14:50:25.760 に答える
1

すべての列が必要ですか? 最初のステップは、実際に取得する必要があるものだけを選択することです。

もう 1 つの側面は、データがアプリケーションに到着した後にデータをどう処理するかです (データ セットにデータを入力する/順番に読み取る/?)。

処理アプリケーション側で改善の可能性がある場合があります。

次の質問に答える必要があります。

返されたすべてのデータを一度にメモリに保持する必要がありますか? 取得側の行ごとにどのくらいのメモリを割り当てますか? 一度にどれくらいのメモリが必要ですか? メモリを再利用できますか?

于 2010-08-16T14:44:24.183 に答える
0

他の回答と同様に、本当にすべてのフィールドが必要な場合を除いて、「select*」は使用しないでください。

logLevelとcreationDataにはインデックスがあります

両方の値を持つ単一のインデックスが必要です。それらをどの順序で配置するとパフォーマンスに影響しますが、可能なログレベル値の数が少ない(そしてデータが歪んでいない)と仮定すると、creationDataを最初に配置するとパフォーマンスが向上します。

最適なインデックスは、log(N)へのクエリのコストを削減します。つまり、レコードの数が増えるにつれて、インデックスの速度は低下します。

C。

于 2010-08-16T16:01:02.963 に答える
0

あなたにできることは2つあります。

  1. 日付列に基づいてテーブルを水平に分割します

  2. 事前集計の概念を使用します。

事前集計: preagg には、「logs」テーブル、「logs_temp」テーブル、「logs_summary」テーブル、および「logs_archive」テーブルがあります。logs と logs_temp テーブルの構造は同じです。アプリケーションの流れは次のようになります。すべてのログがログ テーブルに記録され、1 時間ごとに次のことを行う cron ジョブが実行されます。

a. ログ テーブルから「logs_temp」テーブルにデータをコピーし、ログ テーブルを空にします。これは、Shadow Table トリックを使用して実行できます。

b. logs_temp テーブルからその特定の時間のログを集計します

c. 集計結果を集計表に保存する

d. レコードを logs_temp テーブルから logs_archive テーブルにコピーしてから、logs_temp テーブルを空にします。

このようにして、結果は要約表に事前に集計されます。

結果を選択したいときはいつでも、要約テーブルから選択します。

この方法では、データが 1 時間ごとに事前に集計されているため、レコード数がはるかに少ないため、選択は非常に高速です。しきい値を 1 時間から 1 日に増やすこともできます。それはすべてあなたのニーズに依存します。

ログ テーブルには過去 1 時間分のデータしか保持されないため、ログ テーブルのデータ量はそれほど多くないため、挿入も高速になります。挿入を高速にします。

シャドー テーブル トリックの詳細については、こちらをご覧ください。

wordpressで構築したニュースサイトで事前集計方式を採用しました。最近人気のある (過去 3 日間に人気のある) ニュース項目を表示するニュース Web サイト用のプラグインを開発する必要があり、1 日あたり 10 万件のヒットがあり、この事前集計機能は非常に役立ちました。クエリ時間は 2 秒以上から 1 秒未満に短縮されました。プラグインを近日中に公開する予定です。

于 2010-08-16T15:56:40.657 に答える
0

いくつかのこと

すべての列が必要ですか?SELECT *テーブルにある 15 列のうち 5 列をリストするのが面倒なので、通常はそうします。

RAM を増やしてください。RAM が多ければ多いほど、より多くのデータをキャッシュに保存できます。これは、ディスクから読み取るよりも 1000 倍高速です。

于 2010-08-16T14:42:43.090 に答える
0

creationData私はあなたが意味することを本当に願っていますcreationDate

まず、 と にインデックスを付けるだけでは十分ではありません。2 つの個別のインデックスがある場合、Oracle は 1 つしか使用できません。必要なのは、両方のフィールドの単一のインデックスです。logLevelcreationData

CREATE INDEX i_log_1 ON log (creationData, logLevel);

最初に creationData を置いていることに注意してください。このように、そのフィールドを WHERE 句に入れるだけでも、インデックスを使用できます。(日付のみでのフィルタリングは、ログ レベルのみでのシナリオの可能性が高いようです)。

次に、テーブルにデータ (本番環境で使用するのと同じ量のデータ) が入力されていることを確認し、テーブルの統計を更新します。

テーブルが大きい場合 (少なくとも数十万行)、次のコードを使用して統計を更新します。

DECLARE
  l_ownname          VARCHAR2(255) := 'owner'; -- Owner (schema) of table to analyze
  l_tabname          VARCHAR2(255) := 'log'; -- Table to analyze
  l_estimate_percent NUMBER(3) := 5;  -- Percentage of rows to estimate (NULL means compute)
BEGIN
  dbms_stats.gather_table_stats (
     ownname => l_ownname ,
      tabname => l_tabname,
      estimate_percent => l_estimate_percent,
      method_opt => 'FOR ALL INDEXED COLUMNS',
      cascade => TRUE
  );
END;

それ以外の場合、テーブルが小さい場合は使用します

ANALYZE TABLE log COMPUTE STATISTICS FOR ALL INDEXED COLUMNS;

さらに、テーブルが大きくなる場合は、creationDate 列の範囲で分割することを検討する必要があります。詳細については、次のリンクを参照してください。

于 2010-08-17T05:47:55.590 に答える