web-dev-qa-db-ja.com

データベースインデックスをフォローするためのベストプラクティス

インデックスを使用してデータベースのパフォーマンスを向上させるためのDOおよびDONTは何ですか?

DOは、インデックスを作成する必要がある場合、またはパフォーマンスを向上させるヒントに関連する別のインデックスです。

DONTは、インデックスを作成してはならない場合や、パフォーマンスを低下させる可能性のある別のインデックス関連のアクションです。

17
Click Upvote

これは、データベースの使用目的に一部依存します。一般に、インデックスは挿入と更新を遅くし、クエリを高速化するためです。データウェアハウスでは、通常、更新やバッチ挿入は行われないため、インデックスの作成が簡単になり、多数のクエリを実行することで、多数のインデックスが高速化されます。 Webセールスなどのオンラインデータベースでは、挿入や更新が多数行われるため、慎重に選択されたインデックスがいくつかあると、パフォーマンスが低下します。

特定のタイプのクエリを多数取得する場合は、クエリのインデックスを作成できますが、それはデータウェアハウスよりもオンライン処理用です。特定の列がクエリで大量に出現する場合、その列のインデックスが必要になる場合があります。これは、さまざまな方法でクエリされることが多く、予測できない方法でデータウェアハウスに特に役立ちます。

インデックスを追加または削除するときは常に、パフォーマンステストを実行して、それがどのような影響を与えるかを確認してください。それがなければ、あなたはブラインドを撃っています。

多くの場合、1つのデータベースシステムに固有で、そのRDBMSのツールを使用して、クエリとデータベースのチューニングに関する本があります。ただし、データベースを最適化する必要がある場合は、大規模な操作を実行しているため、適切な専門知識を持つDBAを雇う必要があります。

15
David Thornley

テーブルの使い方に大きく依存します。単一で単純な答えはありません。

私があなたに与えることができる最高のアドバイスは、チューニングアドバイザーを使用することです。アプリケーションの使用中にデータベースコマンドを分析し、アプリケーションに対して負荷テストを実行して、意味のあるアドバイスを提供します。

それらは SQL ServerOracle に対して存在します。他のDBMSにそれらがあるかどうかはわかりませんが、そのような基本的なツールが提供されていないのではないでしょうか。

いくつかのランダムな推奨:

  • インデックスは、WHERE句に含まれることが多い列に適用すると、パフォーマンスが向上します。
  • クエリで最も使用される列にクラスター化インデックスを使用します。
  • 列の組み合わせで複数のインデックスを作成できることを忘れないでください(クエリで使用されるため)
  • インデックスが多いと、INSERTコマンドのパフォーマンスが低下します。

最後のアドバイス:DBパフォーマンスがプロジェクトにとって本当に重要な場合は、専門家を雇ってください。それは私がやったことです。

17
user2567

@Pierre 303はすでにそれを言っていましたが、私は再びそれを言います。 [〜#〜] do [〜#〜]列の組み合わせにインデックスを使用します。 (a, b)の複合インデックスは、aのクエリの方がa単独のインデックスよりもわずかに遅く、クエリが両方の列を組み合わせる場合は非常に優れています。一部のデータベースは、テーブルにアクセスする前にabのインデックスを結合できますが、これは結合インデックスを使用するよりも優れているとは言えません。結合インデックスを作成するときは、最初に検索される可能性が最も高い列を結合インデックスに配置する必要があります。

データベースがサポートしている場合、[〜#〜] do [〜#〜]は、列ではなくクエリで表示される関数にインデックスを付けます。 (列の関数を呼び出す場合、その列のインデックスは役に立ちません。)

その場で作成および破棄できる真の一時テーブルを備えたデータベースを使用している場合(例:PostgreSQL、MySQL、ただしnotOracle)、次に[〜#〜] do [〜#〜]一時テーブルにインデックスを作成します。

それを許可するデータベース(Oracleなど)を使用している場合、[〜#〜] do [〜#〜]適切なクエリプランでロックします。時間の経過とともにクエリオプティマイザーはクエリプランを変更します。彼らは通常計画を改善します。しかし、時にはそれが劇的に悪化させます。通常、プランの改善に気付くことはありません-クエリはボトルネックではありませんでした。しかし、1つの悪い計画がビジーなサイトをダウンさせる可能性があります。

DO N'T大きなデータロードを実行しようとしているテーブルにインデックスを作成します。テーブルをロードするときにインデックスを維持するよりも、インデックスを削除してデータをロードしてからインデックスを再構築する方がはるかに高速です。

DO N'T大きなテーブルのごく一部以上にアクセスする必要があるクエリでインデックスを使用します。 (ハードウェアに依存する程度は小さいです。5%はまともな経験則です。)たとえば、名前と性別を含むデータがある場合、指定された名前は行全体のごく一部を表すため、名前はインデックス付けの適切な候補です。行の50%にアクセスする必要があるため、性別でインデックスを作成することは役に立ちません。代わりに、完全なテーブルスキャンを使用する必要があります。その理由は、インデックスが大きなファイルにランダムにアクセスし、ディスクシークが必要になるためです。ディスクシークが遅い。適例として、私は最近、次のような1時間のクエリを高速化することができました。

SELECT small_table.id, SUM(big_table.some_value)
FROM small_table
  JOIN big_table
    ON big_table.small_table_id = small_table.id
GROUP BY small_table.id

次のように書き換えて、3分未満にします。

SELECT small_table.id, big_table_summary.summed_value
FROM small_table
  JOIN (
      SELECT small_table_id, SUM(some_value) as summed_value
      FROM big_table
      GROUP BY small_table_id
    ) big_table_summary
    ON big_table_summary.small_table_id =  small_table.id

これにより、データベースはbig_table.small_table_idで魅力的なインデックスを使用しないでください。 (Oracleなどの優れたデータベースは、それ自体でそれを理解する必要があります。このクエリはMySQLで実行されていました。)

pdate:作成したディスクシークポイントについて説明します。インデックスを使用すると、データがテーブルのどこにあるかをすばやく確認できます。あなたが見る必要があるデータだけを見るので、これは通常勝利です。しかし、常にそうであるとは限りません。特に、最終的に大量のデータを見る場合はそうです。ディスクはデータを適切にストリーミングしますが、ルックアップが遅くなります。ディスク上のデータをランダムに検索するには、1/200秒かかります。クエリの遅いバージョンは、そのうちの60万件を処理することになり、1時間近くかかりました。 (それよりも多くのルックアップを行いましたが、キャッシングはそれらのいくつかをキャッチしました。)対照的に、高速バージョンはすべてを読み取り、データを70 MB /秒のような速度でストリーミングする必要があることを知っていました。 3分以内に11 GBのテーブルを通過しました。

4
btilly

基本的に、インデックスは検索を高速化しますが、書き込みを遅くし、スペースを占有します。これがトレードオフです。

結合、検索/比較、または並べ替えに頻繁に使用されるフィールドは、インデックスの候補です。それが本当に有益であることを知るために、測定してください。ただし、大量のレコード(> 1000を超える)があり、挿入数が少ない、高度に結合されたテーブルの外部キーは効果があります。

テキストフィールドの場合、フィールドの一部(たとえば、最初の6文字)にインデックスを付けることができます。これにより、クエリは高速になりますが、インデックスの負荷は軽減されます。全文検索(_like %substring%_での検索)にはさまざまな手法が必要ですが、私はこの手法に慣れていないため、アドバイスはできません。

インデックスが役に立たない重要な状況:日付の一部を検索(/ join/order)するときに、完全な日付フィールドまたは日時フィールドのインデックスを使用できません。 _date_created_のインデックスは、select * from t where year(date_created) = 2011のようなクエリには役立ちません。 mysqlでは、日付の一部にインデックスを作成できません。 (year()ではなく 'between'を使用すると、日付フィールドのインデックスを使用できます。)

マニュアルのMYSQLの詳細情報: http://dev.mysql.com/doc/refman/5.6/en/optimization-indexes.html

2
Inca

実施:クエリや比較を通じて、最も頻繁にアクセスするごく少数のフィールドにインデックスを付けます。

してはいけないこと:テーブル内のすべてのフィールドにインデックスを付け、それが高速になると考えてください。

統計情報はありませんが、できる限り4つ以下のインデックス付きフィールドをテーブルに保持するようにしています。データベースを正規化すると、すべてが数字キーで検索できるようになるため(通常は高速です)、これらの数値を低く抑えることができます。索引付けのために、フルテキストフィールドに近づかないようにしています。彼らはかなり重いです。

2
Joel Etherton

実施:クラスタ化インデックスの合計サイズを最小限に抑えるようにしてください。クラスタ化インデックスエントリは他の非クラスタ化インデックスに含まれ、ここからディスク領域を浪費する可能性があります。

1
user8685

表は、記事が出現順にソートされている(または役に立たない順序である)辞書と考えることができ、テーブルインデックスは、その辞書への本のインデックスと考えることができます。

索引を使用して、本の中で何かをすばやく見つけます。本全体をスキャンする代わりに、インデックスでキーを見つけるだけで済みます(インデックスは通常、何らかの方法で(カテゴリ、科学分野、歴史的エポックなどで)ソートされています)。これは、スキャンする必要がないことも意味しますインデックス全体)をクリックしてから、右側のページにジャンプします。

本とは異なり、表は一度印刷されてから不変になるわけではありません。常に更新されるため、すべてのインデックスを更新する必要があります。もちろん、これにはスペースと時間のコストが伴いますが、これはインデックスの有用性によってのみ正当化できます。

したがって、列が頻繁な検索クエリでキーとして使用されている場合は、その列のインデックスを使用し、そうでない場合は使用しないでください。一般的に言えば、単語頻出は、それが得られるほどの量指定子です。最後に、どれが頻繁であるかを適切に推定し、疑わしい場合は単にインデックスの有無にかかわらずパフォーマンスをベンチマークする必要があります。

1
back2dos