ほとんどのデータベースは、時間の経過とともにサイズが大きくなります。成長はデータベースのパフォーマンスに影響を与えるほど速いとは限りませんが、それが発生する場合は確かにあります。その場合、その影響を減らすために何ができるのか、大規模なデータを処理するときにデータベース操作をスムーズに行うにはどうすればよいのか、よく疑問に思います。
まず、「大量のデータ」とはどういう意味かを定義してみましょう。 MySQLまたはMariaDBの場合、非圧縮のInnoDBです。 InnoDBは、利用可能なメモリ(主にInnoDBバッファプール)から大きな恩恵を受けるように機能します。データがそこに収まる限り、ディスクアクセスは書き込みのみを処理するように最小限に抑えられます。読み取りはメモリから提供されます。データがメモリを超えるとどうなりますか?現在キャッシュされていない行にアクセスする必要がある場合は、ディスクからさらに多くのデータを読み取る必要があります。データ量が増えると、ワークロードはCPUバウンドからI/Oバウンドに切り替わります。これは、ボトルネックがCPUではなく(データがメモリに収まる場合の場合でした。メモリ内のデータアクセスが高速で、データの変換と集約が遅い)、I / Oサブシステムである(データに対するCPUの動作が遅い)ことを意味します。ディスクからデータにアクセスするよりも高速です。)フラッシュの採用が増えるにつれ、I / Oにバインドされたワークロードは、ドライブの回転時に使用されていたほどひどくはありません(SSDではランダムアクセスの方がはるかに高速です)が、パフォーマンスへの影響は依然としてあります。 。
通常、アクティブなデータセットのみを考慮していることを覚えておく必要があります。確かに、スキーマにはテラバイトのデータが含まれている可能性がありますが、最後の5 GBのみにアクセスする必要がある場合、これは実際には非常に良い状況です。確かに、それでも運用上の課題がありますが、パフォーマンスに関しては問題ないはずです。
このブログの目的のために仮定しましょう。これは科学的な定義ではありません。データ量が多いということは、アクティブなデータサイズがメモリのサイズを大幅に上回っている場合を意味します。 2GBのメモリがある場合は100GB、200GBのメモリがある場合は20TBになる可能性があります。転換点は、ワークロードが厳密にI/Oバウンドであるということです。 MySQLとMariaDBで利用できるいくつかのオプションについて説明する間、私たちと一緒に耐えてください。
パーティショニング
大量のデータを処理するための歴史的な(しかし完全に有効な)アプローチは、パーティショニングを実装することです。その背後にある考え方は、テーブルをパーティションに分割することです。これは、サブテーブルのようなものです。分割は、ユーザーが定義したルールに従って行われます。いくつかの例を見てみましょう(SQLの例はMySQL 8.0のドキュメントから引用しています)
MySQL 8.0には、次のタイプのパーティショニングが付属しています。
- 範囲
- リスト
- 列
- ハッシュ
- キー
サブパーティションを作成することもできます。ここではドキュメントを書き直すつもりはありませんが、パーティションがどのように機能するかについての洞察を提供したいと思います。パーティションを作成するには、パーティションキーを定義する必要があります。これは列にすることも、RANGEまたはLISTの場合は、データをパーティションに分割する方法を定義するために使用される複数の列にすることもできます。
HASHパーティショニングでは、ユーザーが列を定義する必要があります。列はハッシュされます。次に、データはそのハッシュ値に基づいてユーザー定義の数のパーティションに分割されます。
CREATE TABLE employees (
id INT NOT NULL,
fname VARCHAR(30),
lname VARCHAR(30),
hired DATE NOT NULL DEFAULT '1970-01-01',
separated DATE NOT NULL DEFAULT '9999-12-31',
job_code INT,
store_id INT
)
PARTITION BY HASH( YEAR(hired) )
PARTITIONS 4;
この場合、ハッシュは「hired」列のYEAR()関数によって生成された結果に基づいて作成されます。
KEYパーティショニングは、どの列をハッシュするかをユーザーが定義し、残りはMySQLが処理することを除いて、同様です。
HASHパーティションとKEYパーティションはデータをパーティションの数全体にランダムに分散しますが、RANGEとLISTを使用すると、ユーザーは何をするかを決定できます。 RANGEは通常、時刻または日付で使用されます:
CREATE TABLE quarterly_report_status (
report_id INT NOT NULL,
report_status VARCHAR(20) NOT NULL,
report_updated TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
)
PARTITION BY RANGE ( UNIX_TIMESTAMP(report_updated) ) (
PARTITION p0 VALUES LESS THAN ( UNIX_TIMESTAMP('2008-01-01 00:00:00') ),
PARTITION p1 VALUES LESS THAN ( UNIX_TIMESTAMP('2008-04-01 00:00:00') ),
PARTITION p2 VALUES LESS THAN ( UNIX_TIMESTAMP('2008-07-01 00:00:00') ),
PARTITION p3 VALUES LESS THAN ( UNIX_TIMESTAMP('2008-10-01 00:00:00') ),
PARTITION p4 VALUES LESS THAN ( UNIX_TIMESTAMP('2009-01-01 00:00:00') ),
PARTITION p5 VALUES LESS THAN ( UNIX_TIMESTAMP('2009-04-01 00:00:00') ),
PARTITION p6 VALUES LESS THAN ( UNIX_TIMESTAMP('2009-07-01 00:00:00') ),
PARTITION p7 VALUES LESS THAN ( UNIX_TIMESTAMP('2009-10-01 00:00:00') ),
PARTITION p8 VALUES LESS THAN ( UNIX_TIMESTAMP('2010-01-01 00:00:00') ),
PARTITION p9 VALUES LESS THAN (MAXVALUE)
);
他のタイプの列でも使用できます:
CREATE TABLE employees (
id INT NOT NULL,
fname VARCHAR(30),
lname VARCHAR(30),
hired DATE NOT NULL DEFAULT '1970-01-01',
separated DATE NOT NULL DEFAULT '9999-12-31',
job_code INT NOT NULL,
store_id INT NOT NULL
)
PARTITION BY RANGE (store_id) (
PARTITION p0 VALUES LESS THAN (6),
PARTITION p1 VALUES LESS THAN (11),
PARTITION p2 VALUES LESS THAN (16),
PARTITION p3 VALUES LESS THAN MAXVALUE
);
LISTパーティションは、複数のパーティション間で行を並べ替える値のリストに基づいて機能します。
CREATE TABLE employees (
id INT NOT NULL,
fname VARCHAR(30),
lname VARCHAR(30),
hired DATE NOT NULL DEFAULT '1970-01-01',
separated DATE NOT NULL DEFAULT '9999-12-31',
job_code INT,
store_id INT
)
PARTITION BY LIST(store_id) (
PARTITION pNorth VALUES IN (3,5,6,9,17),
PARTITION pEast VALUES IN (1,2,10,11,19,20),
PARTITION pWest VALUES IN (4,12,13,14,18),
PARTITION pCentral VALUES IN (7,8,15,16)
);
あなたが尋ねるかもしれないパーティションを使用することのポイントは何ですか?重要な点は、ルックアップはパーティション化されていないテーブルよりも大幅に高速であるということです。特定の月に作成された行を検索するとします。テーブルに数年分のデータが格納されている場合、これは課題になります。インデックスを使用する必要があります。ご存知のように、インデックスは行を見つけるのに役立ちますが、それらの行にアクセスすると、からのランダムな読み取りが大量に発生します。テーブル全体。年月ベースで作成されたパーティションがある場合、MySQLはその特定のパーティションからすべての行を読み取ることができます-インデックスにアクセスする必要はなく、ランダムな読み取りを行う必要もありません:パーティションからすべてのデータを順番に読み取るだけです。すべて設定されています。
パーティションは、データローテーションの処理にも非常に役立ちます。 MySQLが削除する行を簡単に識別して単一のパーティションにマップできる場合は、インデックスを使用して行を検索するDELETE FROM table WHERE…を実行する代わりに、パーティションを切り捨てることができます。これは、RANGEパーティショニングで非常に役立ちます。上記の例に固執すると、データを2年間だけ保持する場合は、cronジョブを簡単に作成できます。これにより、古いパーティションが削除され、次の月に新しい空のパーティションが作成されます。
InnoDB圧縮
大量のデータがある場合(必ずしもデータベースについて考える必要はありません)、最初に頭に浮かぶのはデータを圧縮することです。ファイルを圧縮してサイズを大幅に縮小するオプションを提供するツールは多数あります。 InnoDBにはそのためのオプションもあります-MySQLとMariaDBの両方がInnoDB圧縮をサポートしています。圧縮を使用する主な利点は、I/Oアクティビティが減少することです。データを圧縮すると、データが小さくなるため、読み取りと書き込みが高速になります。通常のInnoDBページのサイズは16KBです。SSDの場合、これは読み取りまたは書き込みを行う4つのI / O操作です(SSDは通常4KBページを使用します)。 16KBを4KBに圧縮できれば、I/O操作を4つ減らすことができます。データセットとメモリの比率に関しては、あまり役に立ちません。実際には、さらに悪化する可能性があります。MySQLは、データを操作するために、ページを解凍する必要があります。それでも、圧縮されたページをディスクから読み取ります。これにより、4KBの圧縮データと16KBの非圧縮データを格納するInnoDBバッファープールが作成されます。もちろん、不要なデータを削除するアルゴリズムはありますが(圧縮されていないページは可能な場合は削除され、圧縮されたページのみがメモリに保持されます)、この領域での大幅な改善は期待できません。
ストレージに関して圧縮がどのように機能するかを覚えておくことも重要です。ソリッドステートドライブは、最近のデータベースサーバーの標準であり、いくつかの特定の特性があります。それらは高速であり、トラフィックがシーケンシャルであるかランダムであるかをあまり気にしません(ランダムよりもシーケンシャルアクセスを優先しますが)。それらは大量の場合は高価です。限られた数の書き込みサイクルを処理できるため、「使い古された」という問題があります。ここでは、圧縮が非常に役立ちます。ディスク上のデータのサイズを縮小することで、データベースのストレージレイヤーのコストを削減します。ディスクに書き込むデータのサイズを小さくすることで、SSDの寿命を延ばします。
残念ながら、圧縮が役立つ場合でも、大量のデータの場合はまだ十分ではない可能性があります。もう1つのステップは、InnoDB以外のものを探すことです。
MyRocks
MyRocksは、MySQLおよびMariaDBで使用可能なストレージエンジンであり、InnoDBとは異なる概念に基づいています。私の同僚であるSebastianInsaustiは、MariaDBでのMyRocksの使用についての素晴らしいブログを持っています。要点は、その設計(Log Structured Merge、LSMを使用)により、MyRocksはInnoDB(B + Tree構造に基づく)よりも圧縮の点で大幅に優れています。 MyRocksは、大量のデータを処理し、書き込み回数を減らすように設計されています。これは、データ量が多く、データにアクセスするための要件が高いFacebookから発信されました。したがって、SSDストレージ-それでも、このような大規模では、圧縮のすべてのゲインは巨大です。 MyRocksは、InnoDBよりも最大2倍優れた圧縮を実現できます(つまり、サーバーの数を2つ減らすことができます)。また、ライトアンプリフィケーション(行の内容の変更を処理するために必要な書き込みの数)を減らすように設計されています。必要な書き込みは、InnoDBの10分の1です。これにより、明らかにI / O負荷が軽減されますが、さらに重要なことに、InnoDBを使用して同じ負荷を処理する場合と比較して、SSDの寿命が10倍長くなります。パフォーマンスの観点から、データ量が少ないほどアクセスが速くなるため、このようなストレージエンジンは、データベースからデータをより速く取り出すのにも役立ちます(MyRocksの設計では最優先事項ではありませんでしたが)。
柱状データストア
関連リソースClusterControlパフォーマンス管理高可用性MySQLおよびMariaDBソリューションの高レイテンシの影響を理解するMySQLパフォーマンスチートシートある時点で私たちにできることは、MySQLを使用してそのような量のデータを処理できないことを認めることだけです。もちろん、シャーディングすることも、さまざまなことを行うこともできますが、最終的には意味がなくなります。追加の解決策を探す時が来ました。それらの1つは、ビッグデータ分析を念頭に置いて設計された列型データストア(データベース)を使用することです。確かに、OLTPタイプのトラフィックには役立ちませんが、企業はデータ駆動型であり、ランダムデータではなく正確な数値に基づいて意思決定を行うため、分析は今日ではほとんど標準となっています。多数の列データストアがありますが、ここではそのうちの2つについて説明します。 MariaDBAXとClickHouse。 MariaDB AXとは何か、MariaDBAXの使用方法を説明するブログがいくつかあります。重要なのは、MariaDB AXをクラスターの形でスケールアップして、パフォーマンスを向上させることができるということです。 ClickHouseは、分析を実行するためのもう1つのオプションです。ブログ投稿の1つで説明したように、ClickHouseはMySQLからのデータを複製するように簡単に構成できます。高速で無料です。また、クラスターの形成やデータのシャーディングに使用して、パフォーマンスをさらに向上させることもできます。
結論
このブログ投稿が、MySQLまたはMariaDBで大量のデータを処理する方法についての洞察を提供してくれることを願っています。幸いなことに、私たちが自由に使えるオプションがいくつかあり、最終的には、それを実際に機能させることができない場合は、良い選択肢があります。