web-dev-qa-db-ja.com

MySQLインデックスのメンテナンス

MySQLでインデックスを維持して断片化を防ぎ、クエリの実行を何らかの方法で最適化する方法について、多くの調査を行いました。

テーブルで使用可能な最大スペースとデータとインデックスで使用されるスペースの比率を計算する式に精通しています。

しかし、私の主な質問はまだ答えられていません。おそらく、これはSQL Serverのインデックスメンテナンスに精通しているためであり、MySQLでもそれはある程度似ていると思う傾向があります。

SQLサーバーでは、いくつかのインデックスを設定でき、それぞれに異なるレベルの断片化を設定できます。次に、1つをピックアップして、残りに影響を与えることなく、その特定のインデックスで「REORGANIZE」または「REBUILD」操作を実行できます。

私の知る限りでは、このような「テーブルの断片化」はなく、SQL Serverは「テーブルの断片化」を修正するためのツールを提供していません。それが提供するのは、内部および外部の断片化だけでなく、インデックスの断片化(インデックスによって使用されるページ数とそのページの完全性と連続性の比率と同様に理解される)をチェックするツールです。

これらすべては、少なくとも私にとっては、非常に簡単に理解できます。

MySQLでインデックスを維持する番になると、前述のように「テーブルの断片化」という概念しか存在しません。

MySQLのテーブルには複数のインデックスを含めることができますが、その有名な式で「断片化率」を確認すると、各インデックスの断片化が表示されず、テーブル全体が表示されます。

MySQLでインデックスを最適化したい場合、操作する特定のインデックスを選択しません(SQL Serverなど)。代わりに、テーブル全体で「OPTIMIZE」操作を実行します。これは、おそらくすべてのインデックスに影響します。

MySQLでテーブルが最適化されると、データ+インデックスVS全体のスペースによって使用されるスペースの比率が減少します。これは、ハードドライブ内のある種の物理的な再編成を示唆し、物理スペースの減少につながります。ただし、インデックスの断片化は、物理的なスペースだけでなく、挿入と更新によって時間の経過とともに変更されたツリーの構造に関するものです。

最後に、InnoDB/MySQLにテーブルを取得しました。そのテーブルには、300万レコード、105列、55インデックスがあります。 2.1GBのインデックスを除くと1.5GBです。

そのテーブルは、更新、挿入のために毎日何千回もヒットしています(実際にレコードを削除するわけではありません)。

そのテーブルは何年も前に作成されており、誰もインデックスを維持していないことは確かです。

そこに巨大な断片化が見つかると予想していたのですが、断片化計算を規定通りに実行すると

free_space / (data_length + index_length)

断片化が0.2%しかないことがわかります。私見はかなり非現実的です。

だから大きな質問は:

  1. テーブル全体ではなく、MySQLの特定のインデックスの断片化をチェックするにはどうすればよいですか
  2. SQL Serverのように、OPTIMIZE TABLEは実際にインデックスの内部/外部断片化を修正しますか?
  3. MySQLでテーブルを最適化すると、実際にテーブルのすべてのインデックスが再構築されますか?
  4. (ツリー自体を再構築せずに)インデックスの物理スペースを削減すると、実際にはパフォーマンスが向上すると考えるのは現実的ですか?
12
Nicolas

インデックスの断片化は過大評価されています。それについて心配しないでください。

2つの隣接する、やや空のブロックが、自然な処理としてInnoDBによってマージされます。

BTreeでのランダムなアクションにより、BTreeは平均69%のフルに自然に引き寄せられます。確かに、これは100%ではありませんが、「修正」のオーバーヘッドは価値がありません。

_SHOW TABLE STATUS_はいくつかのメトリックを提供しますが、それらには欠陥があります-「Data_free」には特定の「空き」スペースが含まれますが、他の「空き」スペースは含まれません。

各ブロックには未使用のスペースがあります。空き16KBブロック。無料の「エクステント」(nMBチャンク)。刈り取りを待っているMVCC行。非リーフノードには独自のフラグメンテーションがあります。等.

PerconaとOracleでは、インデックスの大きさ(ブロック数)の見方が異なります。 「無料」の定義が限られているため、どちらも役に立ちません。ブロック(各16KB)はチャンク(数MB)に割り当てられているように思われるため、あらゆる種類の断片化があると思われます。実際には、通常、これらのマルチMBチャンクのほとんどの1つです。また、_OPTIMIZE TABLE_は必ずしもスペースを取り戻すわけではありません。

SQL ServerがBTreesを使用している場合、「断片化がない」と言っているのは嘘です。 「ブロック分割」で何が起こるか考えてください。または、継続的なデフラグのオーバーヘッドについて考えてみてください。どちらにしても失う。

さらに、テーブルとインデックスは基本的に同じ構造であることに注意してください。

  • インデックスに基づくB + Tree
  • 「データ」は主キーに基づいています。各セカンダリインデックスは、そのインデックスに基づくB +ツリーです。
  • 「データ」のリーフノードには、テーブルのすべての列が含まれます。
  • セカンダリインデックスのリーフノードには、そのセカンダリインデックスの列と、PRIMARY KEYの列が含まれています。

_innodb_file_per_table = ON_を使用している場合、_.ibd_ファイルのサイズを確認することで、OPTIMIZE TABLE後の縮小(ある場合)を明確に確認できます。 OFFの場合、情報は_ibdata1_に埋め込まれますが、すべての「空き」スペースがすべてのテーブルに属しているため、_SHOW TABLE STATUS_はかなり正確な場合があります。まあ、事前に割り当てられたチャンクを除いて。

新しく最適化されたfile-per-tableテーブルには、4M、5M、6M、または7MのData_freeが正確に含まれていることに気付くでしょう。繰り返しになりますが、これは事前割り当てであり、詳細を提供することができません。

私は10年以上にわたってInnoDBを使用してきました。私は、大小を問わず、何千もの異なるテーブルで作業してきました。 1000のうち1つのテーブルだけが本当に_OPTIMIZE TABLE_を必要とすると私は言います。他のテーブルで使用するのはもったいないです。

105列はたくさんありますが、多すぎないでしょう。

oneテーブルに55のインデックスがありますか?それは悪いです。つまり、INSERTあたり55回の更新です。それについてさらに議論しましょう。 INDEX(a)もある場合、INDEX(a,b)は役に立たないことに注意してください。また、カーディナリティが低いため、INDEX(flag)は役に立ちません。 (ただし、INDEX(flag, foo)が役立つ場合があります。)

Q1:データまたはセカンダリインデックスのいずれかですべての形式の断片化をチェックする良い方法はありません。

Q2、Q3:_OPTIMIZE TABLE_は、CREATEing新しいテーブルとINSERTingすべての行、そしてRENAMEingDROPpingによってテーブルを再構築します。 PK順でデータを再挿入することにより、dataが適切にデフラグされることが保証されます。インデックスは別の問題です。

Q4:couldDROPおよびreCREATE各インデックスをクリーンアップします。しかし、これは非常に遅いプロセスです。 5.6にはいくつかの高速化がありますが、最適化に役立つかどうかはわかりません。

_ALTER TABLE ... DISABLE KEYS_、次にENABLEすることもできます。このmayを使用すると、すべてのセカンダリインデックスを一度に効率的に再構築できます。

6
Rick James

テーブル全体ではなく、MySQLの特定のインデックスの断片化をチェックするにはどうすればよいですか

パス。

SQL Serverのように、OPTIMIZE TABLEは実際にインデックスの内部/外部断片化を修正しますか?

テーブルとそのインデックスを完全に再構築します。

MySQLでテーブルを最適化すると、テーブルのすべてのインデックスが実際に再構築されますか?

それは同じ質問と同じ答えです。

(ツリー自体を再構築せずに)インデックスの物理スペースを減らすと、実際にパフォーマンスが向上すると考えるのは現実的ですか?

スペースを削減できると考えるのは現実的ではありませんなしツリーを再構築します。彼らは一緒に行きます。

1
user207421