データベースインデックスに関するベストプラクティス[終了]


17

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

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

DONTは、インデックスを作成する必要がない場合、またはパフォーマンスを損なう可能性のある別のインデックス関連のアクションです。


3
プロファイル、プロフィール、プロフィール
GrandmasterB

回答:


15

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

特定の種類のクエリを多数取得する場合は、クエリのインデックスを作成できますが、データウェアハウスよりもオンライン処理の方が多くなります。クエリで特定の列が頻繁に表示される場合、その列にインデックスが必要になることがあります。これは、多くの異なる予測不可能な方法でクエリされるデータウェアハウスに特に役立ちます。

インデックスを追加または削除するたびに、パフォーマンステストを実行して、その効果を確認してください。それがなければ、あなたはブラインドを撃ちます。

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


17

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

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

SQL ServerOracleに存在します。他のDBMSがそれらを持っているかどうかはわかりませんが、そのような基本的なツールを提供していないことを疑います。

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

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

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


2
列の組み合わせのインデックスに対して+1。列のインデックスabされていないのインデックスと同じ(a, b)。後者はa、条件onのクエリを高速化するためのインデックスonとほぼ同等aaありb、条件on およびのクエリには非常に優れており、クエリon bだけでは役に立ちません。(ほとんどのデータベースはこれを使用しません。Oracleは使用しますが、通常のように燃費を
節約

2
+1を追加すると、「クエリプランを読むことを学習して、インデックスを作成する対象がわかります」
スティーブンA.ロウ

4

@Pierre 303はすでに言っていますが、もう一度言います。 DOは、列の組み合わせにインデックスを使用しています。複合インデックスのオン(a, b)aa単独のインデックスよりもクエリの方がわずかに遅く、クエリが両方の列を結合する場合は非常に優れています。一部のデータベースは、テーブルにヒットする前aとそのb前にインデックスを結合できますが、これは結合インデックスを使用する場合ほど良くありません。結合インデックスを作成する場合、結合インデックスの最初に検索される可能性が最も高い列を配置する必要があります。

お使いのデータベースがサポートしていれば、DOは、クエリではなく、列に表示する機能にインデックスを置きます。(列の関数を呼び出す場合、その列のインデックスは役に立ちません。)

あなたが(例えばPostgreSQLのは、MySQL、しかし作成し、その場で破壊することができるというのは本当一時テーブルを持つデータベースを使用している場合ではないのOracle)を、その後、DO一時テーブル上のインデックスを作成します。

あなたがそれを可能にするデータベース(例えばオラクル)を使用している場合は、DOの良い問合せ計画でロック。クエリオプティマイザーは、時間の経過とともにクエリプランを変更します。彼らは通常、計画を改善します。しかし、時には彼らは劇的に悪化させます。通常、プランの改善に気付くことはありません。クエリはボトルネックではありませんでした。しかし、1つの悪い計画は、忙しいサイトを破壊する可能性があります。

しないでくださいあなたが大規模なデータ・ロードを行うしようとしているテーブルのインデックスを持っています。テーブルをロードするときにインデックスを維持するよりも、インデックスを削除し、データをロードしてからインデックスを再構築する方がはるかに高速です。

大きなテーブルのごく一部以上にアクセスする必要があるクエリでは、インデックスを使用しないでください。(どのくらい小さいかはハードウェアに依存します。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で実行されていました。)

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


こんにちは、あなたの例に混乱しています。インデックスを使用すると処理が速くなると思いましたが、それがインデックスのポイントではありませんか?クエリがテーブルの5%以上にアクセスする場合、検索対象の列にインデックスがあると処理が遅くなると言っていますか?
アップ投票をクリックします

@Click Upvote:クエリがテーブルの5%(ハードウェアとデータに大きく依存する正確な割合)を超える値にアクセスする場合、そのクエリにインデックスを使用しないほうが高速です。インデックスを使用しても、使用しない限り害はありません。その理由について、より詳細に更新します。
-btilly

有用な情報。たとえばmysqlperformanceblog.com/2007/08/28/…の詳細についてですが、「キーを無視する」のは、これをサブクエリにする必要があるということではありませんか?
インカ

@Inca:「キーを無視する」ことを知りませんでした。データベースの切り替えは十分に行っているので、よく気づかないデータベース固有のことがあります。それの音から、それは動作しますが、私の最終的なソリューションよりも大幅に効率が低下します。違いは、それが参加してからグループ化するのに対して、私のものはグループ化してから参加するということです。これにより、結合する必要があるレコードが少なくなるため、結合の作業が節約されます。
-btilly

「優れたデータベース(Oracleではなく、MySQLではない)」:特に、MySQLが複数のインデックスを同時に完全に使用できるという事実を無視する場合は、そのような愚かなプロモーションを避けてください(クエリプランでは「INDEX MERGE」と表記) 。
パトリックAllaert

2

実行:クエリまたは比較、またはその両方を使用して最もアクセスする数少ないフィールドのインデックスを作成します。

禁止:テーブル内のすべてのフィールドをインデックス化して、高速化すると考えてください。

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


2

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

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

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

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

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


1

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


1

表は、記事が出現順にソートされている(またはまったく役に立たない)用語集と見なされ、表索引はその語彙集に対する本の索引と見なされます。

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

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

そのため、その列が頻繁な検索クエリでキーとして使用されている場合はその列にインデックスを使用し、そうでない場合は使用しないでください。頻繁に言う言葉は、一般的に話すとき、それが得るのと同じくらい良い数量詞です。最後に、どれが頻繁に発生するかを適切に見積もる必要があります。その後、疑わしい場合にインデックスを使用して、または使用せずにパフォーマンスをベンチマークします。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.