1

次の構造のテーブルがあります

CREATE TABLE rel_score (
  user_id bigint(20) NOT NULL DEFAULT '0',
  score_date date NOT NULL,
  rel_score decimal(4,2) DEFAULT NULL,
  doc_count int(8) NOT NULL
  total_doc_count int(8) NOT NULL
  PRIMARY KEY (user_id,score_date),
  KEY SCORE_DT_IDX (score_date)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 PACK_KEYS=1

テーブルには、2000 年 1 月 1 日から日付まで毎日、アプリケーション内のすべてのユーザーの rel_score 値が格納されます。合計レコード数は 7 億を超えると見積もっています。テーブルに 6 か月分のデータ (約 3,000 万行) を入力したところ、クエリの応答時間は約 8 分でした。ここに私の質問があります、

select 
  user_id, max(rel_score) as max_rel_score
from
  rel_score
where score_date between '2012-01-01' and '2012-06-30'
group by user_id
order by max_rel_score desc;

次の手法を使用してクエリを最適化しようとしましたが、

  1. score_date 列でのパーティショニング
  2. score_date 列にインデックスを追加する

クエリの応答時間はわずかに改善され、8 分弱になりました。

応答時間を改善するにはどうすればよいですか? テーブルのデザインは適切ですか?

また、ユーザーはデータ範囲全体に対してクエリを実行できるため、古いデータをアーカイブに移動することはできません。

4

2 に答える 2

0

プライマリ インデックスは、テーブルを適切にカバーする必要があります。持っていない場合は、 にインデックスを作成することをお勧めしrel_score(user_id, score_date, rel_score)ます。クエリの場合、これは「カバリング」インデックスです。つまり、クエリ内のすべての列がインデックスに含まれているため、エンジンはデータ ページ (インデックスのみ) にアクセスする必要はありません。

次のバージョンもこのインデックスをうまく利用する可能性があります (ただし、クエリのバージョンの方がはるかに好きです)。

select u.user_id,
       (select max(rel_score)
        from rel_score r2
        where r2.user_id = r.user_id and 
              r2.score_date between '2012-01-01' and '2012-06-30'
      ) as rel_score
from (select distinct user_id
      from rel_score
      where score_date between '2012-01-01' and '2012-06-30'
     ) u
order by rel_score desc;

このクエリの背後にある考え方は、集計を単純なインデックス ルックアップに置き換えることです。MySQL での集計は低速な操作です。他のデータベースでははるかにうまく機能するため、このようなトリックは必要ありません。

于 2013-09-02T14:47:30.113 に答える