3

これは、「効率的に 7.300.000.000 行を格納する」(効率的に 7.300.000.000 行を格納する) という私の質問へのフォローアップです。

パーティショニングで MySQL を使用することにしました。予備のスキーマは次のようになります。

CREATE TABLE entity_values (
  entity_id MEDIUMINT UNSIGNED DEFAULT 0 NOT NULL, # 3 bytes = [0 .. 16.777.215]
  date_id SMALLINT UNSIGNED DEFAULT 0 NOT NULL, # 2 bytes = [0 .. 65.535]
  value_1 MEDIUMINT UNSIGNED DEFAULT 0 NOT NULL, # 3 bytes = [0 .. 16.777.215]
  value_2 MEDIUMINT UNSIGNED DEFAULT 0 NOT NULL, # 3 bytes = [0 .. 16.777.215]
  UNIQUE KEY (entity_id, date_id)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 PARTITION BY HASH(entity_id) PARTITIONS 25;

これは与える:

  • 行 = 7.300.000.000 行 (前の投稿に記載されている要件による)
  • サイズ/行 = 11 バイト (3+2+3+3)
  • 合計サイズ = 7.300.000.000 行 * 11 バイト = 80.300.000.000 バイト = 80.3 GB
  • パーティション = 25 (3.2 GB/パーティション、パーティション サイズは多少任意)

「id」列は使用されないため、元の設計から主キーを削除したことに注意してください。

さて、私の質問ですが、前回の投稿で概説した要件と上記のスキーマを考慮して、さらに最適化/調整できる提案はありますか? または、MySQL を使用することにした場合、上記のスキーマは「最適」ですか?

更新:現在のデータ セットを上記のスキーマにロードしようとしましたが、8.570.532 行で 212.000.000 バイト相当のディスク領域が必要になり、1 行あたり約 24.7 バイトになります。

更新: entity_id+date_id をカバーするインデックスは、entity_id のみをターゲットとするクエリにも使用されることに注意してください。

4

3 に答える 3

1

通常、1 つのエンティティ ID のすべて (またはほとんど) のデータを取得する場合は、データベースで一意のチェックを行う必要がない限り、インデックスを (entity_id,date_id) ではなくエンティティ ID のみにすることを検討する必要があります。

その効果は、インデックスを小さくして、より多くのメモリを取得できるようにすることです。あなたの目標は、インデックスをメモリに入れることです。SELECT..ORDER BY DATE を実行する必要がある場合でも、MySQL が 3650 の値を瞬時に (インデックスなしで) 注文できることがわかります。この問題は、ディスクから行を読み取る時間です。

ただし、主なパフォーマンスの問題は、INSERT によって 1 つのエンティティのデータがディスク全体に分散され、各 (エンティティ、日付) のディスク アクセスが必要になり、クエリが毎秒数百行で実行されることです。各エンティティが単一のパーティションにあり、行がそのディスク全体に分散しているため、パーティショニングはこれを助けません。(ディスクの RAID0 が少し役に立ちます)。

効率的に取得するには、エンティティのデータをディスク上で連続させる必要があります。つまり、INSERT 順序からデータを並べ替える必要があります。MySQL ALTER TABLE.. ORDER BY ... でこれを行うことができますが、永遠にかかります。過去 2 週間、ALTER TABLE..ORDER BY を実行している 182M 行のテーブルがありましたが、まだ完了していません。

そのため、カスタム ストレージ エンジンを作成しました。

ところで、複数のサーバー、または少なくとも複数のディスクにまたがってパーティション分割を行っていない限り、パーティション分割によって何かが得られるかどうかはわかりません。MySQL がしなければならない大変な作業は、パーティショニングによって簡単になるわけではありません。それはすべてディスクアクセス時間に関するものです。

各パーティションを別のディスクに配置すると役立つ場合があります。物理ディスクの数の 2 倍を超えるパーティションはありません。1 回ではなく 2 回にすると、キューイングのメリットがいくらか得られますが、あまり効果があるとは思えません。できるだけ多くのディスクで RAID0 を使用して、パーティション分割されていない単一のテーブルよりもはるかに優れているとは思えません。

このアプリケーションのパフォーマンスは、ディスク シークの回数によって決まるため、1 秒あたりのシーク回数を増やすことができれば役立ちます。

パーティショニングを使用すると、処理の並列処理がいくらか得られますが (複数のプロセッサがある場合)、システムはプロセッサではなく I/O バウンドになります。プロセッサの使用率が 2% に達した場合は、おそらく必要のないこと (またはアプリケーションではないこと) を実行しています。

私は、MySQL を使用して 9 年間、この種のアプリケーションを作成、最適化、および運用してきました...そして、その経験から予想されるすべての傷があります。データがメモリのサイズ (私の「巨大」の定義) よりもはるかに大きくなると、全体的なパフォーマンスの問題はディスク I/Oになります。幸運を!!

于 2009-03-21T14:05:15.413 に答える
0

entity_id前の質問で、 ;のすべての行を取得することを示しました。ただし、特定のエンティティの日付範囲を取得する予定がある場合は、サブパーティショニング (複合パーティショニングとも呼ばれます)を使用できます。使用状況に応じて、メイン パーティションを entity_id にし、サブ パーティションを年またはその他の日付範囲にすることができます。システムで意味がある場合は、逆にすることもできます。

于 2009-03-20T14:57:27.013 に答える