データベースインデックスを追加するのは時期尚早な最適化ですか?


61

今日の私の同僚は、アプリケーションのすべてのクエリを調べ、それに応じてインデックスを追加することを提案しました。

私たちのアプリケーションはまだリリースされていないため、これは時期尚早な最適化だと思います。ライブになったら遅いクエリを監視し、それに応じてインデックスを追加することをお勧めします。

データベースを設計する際の一般的なコンセンサスは何ですか?新しいクエリを作成するたびに一致するインデックスを追加する必要がありますか?それとも、それがどのように進行するかを監視して確認する方が良いでしょうか?


32
意見の問題かもしれませんが、一部のインデックスはアプリオリに追加できると思います。
バジルStarynkevitch

2
@BasileStarynkevitchは、主キーインデックスとその作業が既にあることに完全に同意します。しかし、どこで線を引きますか?
マルコデジョン

1
私の経験からの2セント:私はデータベースのサブセットで初期の検索クエリのいくつかをテストしていました。私が実行したテストは、ローカルコピーではまったく問題ありませんでした。次に、データベース全体をホストするステージング領域にアプリケーションをプッシュしました。テストは500ミリ秒未満で実行されましたが、ステージングシステムの解決には数分かかりました。上司は、アプリが読み込まれなかった理由について完全に混乱していました。説明の操作は非常に少なくとも、少なくとも、大きなテーブルのシーケンシャルスキャンを探して...あなたの友人です-type!
クリスサイレフィス

2
インデックスを追加しないことは、バブルソートを使用するようなものです。ほとんどの場合、テストしても問題は見つかりませんが、ライブでプログラムがスケールアップし始めると、多くの問題が発生します。また、インデックスを使用すると、速度の差が100倍になります。
ピーターB

3
常に覚えておいてください:インデックスは、クエリを高速化する魔法のようなものではありません。インデックスは、ほとんどのDML操作でコストを発生させ、タイプによっては、多くの人が同じテーブルを更新するときに多くの待ち時間が発生する可能性があります。クエリの場合:FTSが最速の場合、またはパーティション化がすべての作業を行う場合、インデックスの恩恵をまったく受けないクエリが多数あります。-有益であることがわかっている場所にのみインデックスを追加してください!
ファルコ

回答:


132

時期尚早の最適化は、特にコードの可読性と保守性を損なうため、おそらく遅くなるという漠然とした直感的な感覚のために、何かを「最適化」してます。パフォーマンスに関して確立された優れた慣行に従わないという意味ではありません。

描画するのが難しい場合もありますが、ライブを開始する前にインデックスを追加しないのは遅すぎる最適化だと間違いなく言います。これは、最も熱心で最も重要なユーザーであるアーリーアダプターを罰し、レビューやディスカッションなどでネガティブな見方を広めます。良いアイデアですが、ベータ版までにそれを行うようにします。


11
はい、それは負荷テスト段階で行われるべきです
アルバロ

152
遅い部分がどこにあるかを知る前に最適化することは、時期尚早な最適化です。遅い部分がどこにあるかを知る前に物をリリースするのは早すぎるリリースです!
MathematicalOrchid

4
@MathematicalOrchid:それは素晴らしいフレージングです!他の場所で借りてもいいですか?
ピータージャーケンズ

3
@PieterGeerkensもちろん、ノックアウト!;-) 91人以上の賛成票が返事をもらえないのは残念です。
MathematicalOrchid

3
@MathematicalOrchidは答えだったはずです。「これまでで最小のストレート」答えを実行できます。
マインドウィン

48

ライブになったら遅いクエリを監視する

なぜなら、ユーザーにデザインの欠如に苦しむような品質はありません!

テーブルを設計するとき、どのクエリがインデックスを必要とするか、where句と結合でどの列がクエリされるかを知っている必要があります。負荷や保存されたデータが増加すると、ライブ環境では明らかにならないことがすぐに明らかになる可能性があるため、これらはすでにインデックス付けされている必要があります。これが発生したときにしたくないことは、すべての「遅い」クエリでインデックスをスラップすることで、すべてのインデックスになります。


10
右。データベース設計の一部としてインデックスを検討してください。インデックスを使用して、エンドユーザーが通常リアルタイムで実行するクエリの全テーブルスキャンを回避します。
AE

1
@DocBrownテーブルを設計するときに、その使用方法をある程度理解している(または持っている必要がある)かどうかはわかりません。個人テーブルは、ID、または姓でクエリされます。誰かがDoB、住所、または電話番号を介してアクセスし始めたら、すべてのフィールドにインデックスを追加します-そしてそれはどこで終わりますか?!
gbjbaanb

4
@gbjbaanb:人々が製品に機能を追加するのをやめると終了します。これはあなたの方法論によっては「決して」ないかもしれません。
スティーブジェソップ

1
@SteveJessopつまり、アクセスするプライマリ列に従ってインデックスを作成します。個人テーブルの場合、検索機能を使用できます(ユーザー名を忘れた場合、たとえば電子メールで検索できます)が、その後は常にIDを使用します。したがって、インデックス作成が必要なのはIDだけです。他のフィールドで多くの検索を行う場合、インデックスが必要になる可能性がありますが、これはやがて出てきますが、誰かが非標準のクエリを書くことを決めたという理由だけですべての列にインデックスを付けたくありませんが、これらの「1回限りの」ケースには異なるメカニズムを利用します。
gbjbaanb

2
@gbjbaanb:確かに、テーブルの適切なキーよりも保持するのにやや便利なハンドルであるため、人々はテーブルで同じ姓を繰り返し検索するべきではありません。テーブルが姓でインデックス付けされているかどうかは事実です。実際には、「同じユーザー」ですべてが動作していると仮定しているが、これを表現することができないコードのストレッチについて非常に怪しいものがあるからです私は、クライアントがそれを言及するまで逆引き参照の必要性が予想されなかった場合を想像して:-) IDを覚えることにより、コード内の...
スティーブ・ジェソップ

26

「時期尚早な最適化」とは、軽rog的な意味で、必要のないかもしれない費用のかかる最適化を意味します。それはしません破産を防ぐために、できるだけ最新のポイントの前に実装されたすべての最適化を意味します!

特に、公開する前にパフォーマンステストに基づいて最適化し、アプリが完全に吸い込まれないようにするための合理的な(おおよその)要件を満たすことができるようにすることは正当です。

最低限、データベースに妥当な量のテストデータをロードし、アプリの応答性を確認する必要があります。あなたはそれが起こることを知っているので、これは時期尚早ではありません、そして、それはばかげて遅いスキャンをトリガーするクエリをキャッチします。AEがコメントで述べているように:

インデックスを使用して、エンドユーザーが一般的にリアルタイムで実行するクエリの全テーブルスキャンを回避します。

少なくとも、使用中に成長する予定のテーブルの場合。

それへの近道として、データベースエンジンのかなりの経験があり、コードの最初のカットを書くときにすでにテストを計画しているなら、あなたはそれを実行することなくあなたがしているクエリであることをしばしば知るでしょうインデックスなしでは書き込みが遅すぎます。もちろん、知らないふりをして、インデックスを追加する前にテストが失敗するのを見て自由にできますが、既知の障害のあるコード(応答しないため)がライブになる理由はありません。


20

私たちのアプリケーションはまだリリースされていないため、これは時期尚早な最適化だと思います。ライブになったら遅いクエリを監視し、それに応じてインデックスを追加することをお勧めします。

エンドユーザーや実稼働環境を品質保証のように扱うことはできません。言い換えれば、実稼働環境でそれを理解するということです。私はそれが正しい方法だとは思わないし、そのアプローチは毎日ひどく間違っている思う

広いブラシでペイントすることはできないため、1つ注意する必要があります。

共通のワークロードは何ですか?

それは明白または退屈に聞こえるかもしれませんが、実際には重要です。ワークロードの98%を構成する10個のクエリがある場合(非常に一般的ですが、信じられないかもしれませんが)、私の推奨事項は、運用前のハード分析です。現実的で代表的なデータを使用して、これらの10個のクエリが可能な限り良好であることを確認します(完璧は貴重な時間の無駄であり、ほとんど達成不可能です)。

ワークロードの2%を構成する他の200のクエリについて、これらは多くの労力を費やす価値がほとんどないクエリであり、実稼働環境での異常なトラブルシューティングのコーナーケースを構成します。それも現実であり、ひどく悪いことではありません。しかし、それは、インデックス作成のベストプラクティスを無視したり、データの取得に関する推定を行うことを意味するものではありません。

運用前にデータベースのパフォーマンスを把握することは一般的であり、良い習慣です。実際、このタイプの開発DBAと呼ばれるものには、比較的一般的な立場があります。

しかし...

一部の人はそれを取りすぎて、「念のために」インデックスを追加することに夢中になります。誰かがこれが欠落しているインデックスであることを推奨していますか?それと、他の4つのバリエーションを追加します。また悪い考え。データの取得だけでなく、データの変更についても考える必要がありますか?テーブルにインデックスが多いほど、一般的に言えば、データを変更するときのオーバーヘッドが大きくなります。

ほとんどのものと同様に、健全なバランスがあります。

ちょっとした面白いメモとして...「インデックス」の複数形

「インデックス」は金融関係者向けです

「インデックス」は私たちのためです


2
これにはさらに投票が必要です。私はこれ以上同意できませんでした。
ラバーダック

「ジャストインケース」ビットの+1(これ時期尚早の最適化になります)。できれば、「共通の作業負荷」ビットに再度投票します。
デビッド

どの10個のクエリが98%に属し、どのクエリがそうではないかを事前に知っていることを願っています。
パエロエベルマン

@PaŭloEbermannほとんどのDBMSには、その情報を非常に迅速かつ簡単にキャプチャする機能があります。この場合、知らない理由はありません。
トーマスストリンガー

@ThomasStringerもちろん、これは、実稼働に移行する前のテストケースが実稼働中の実際のユーザーによって行われた処理に何らかの形で関連している場合にのみ機能します。
パエロエベルマン

4

いいえ、それは時期尚早の最適化ではありませんが、最適化が行われるべきであるように正しく行われなければなりません。

ここに私がやることがあります:

  1. 実稼働負荷をまねるのに十分なテストデータをデータベースにロードします。これを100%正確に取得することはできませんが、それで問題ありません。十分なデータを入力するだけです。1つのテーブルに固定量のデータがありますか?それをロードします。このサイトで質問を保持するテーブルなど、多くのデータを保持するテーブルが1つありますか?ダミーデータだけでも数百万件のレコードをロードします。
  2. データベースサーバーでプロファイリングを有効にします。
  3. 自動化されたスクリプト(ボリュームを提供)と実際のユーザー(彼らは物事を壊す方法を知っている)の組み合わせを使用して、アプリケーションに飛びつきます。
  4. プロファイリングデータを確認します。特定のクエリは遅いですか?Explainプランを確認し、データベースサーバーがインデックスが必要であるが存在しないことを通知しているかどうかを確認します。

データベースサーバーは、複雑でインテリジェントなソフトウェアです。耳を傾ける方法を知っていれば、それらを最適化する方法を教えてくれます。

重要なのは、最適化の前後にパフォーマンスを測定し、データベースに必要な情報を伝えることです


3

既知の問題(IDでレコードを見つけるなど)の実証済みのパターンに従うことは、時期尚早ではありません。それは賢明なことです。

ただし、インデックスは必ずしも簡単なビジネスではありません。設計段階で、どのインデックスがトラフィックに依存し、どのオペレーションが書き込み操作のボトルネックになるかを知るのは難しい場合がよくあります。したがって、「明白な」スキーマ設計のベストプラクティスを活用することを主張します(設計された読み取り/書き込みパターンとインデックスFKに適したPKを使用します)。ただし、ストレステストで必要になるまで、他のインデックスを付けないでください。


パフォーマンスを改善するためにほぼ確実で、害を及ぼす可能性がほとんどないことを行うために余分な30秒を費やすことは、「時期尚早な最適化」ではありません。テーブルの操作の90%が特定の列をキーとして使用する場合、インデックスを作成するとパフォーマンスが向上するか、パフォーマンスが問題になるほど遅くなることはなく、インデックスを作成するためのコードを追加すると、それが本当に必要です。
supercat

@supercat "never" ...
運用

列をキーとして使用する操作の90%と一貫性があり、インデックスを追加するとデッドロックが発生する場所はどのような現実的なシナリオですか?
スーパーキャット

@supercat私はあなたの探求を完全に理解しているかどうかはわかりません。アクティブなアプリケーションに関しては、実行時間またはiosの数をほとんど増やすと、デッドロックが発生する可能性があります。...しかし、もっと重要なことは、ほとんどのアプリケーションでのインデックスの有無は、データベースがクリティカルサイズや同時実行レベルに達するまで無視できることです。たとえば、すべてのインデックスがメモリに収まらなくなったとき
...-svidgen

1
要点は、一般的なユースケースがストレステストを実行するまで(または運用環境で予期しないユーザーの動作に関する問題が発生するまで)、クエリの構成を知るのは難しいことです。tablex.fieldyをキーオフするページがあるが、1000回の挿入ごとに1回しかヒットしない場合...インデックスは正味の劣化につながる可能性があります。
svidgen

2

アプリケーションがリリースされると、手遅れになります。

ただし、適切な開発プロセスにはパフォーマンステストを含める必要があります。

パフォーマンステストの結果を使用して、追加するインデックスを決定し、パフォーマンステストを繰り返してその効果を確認します。


アプリケーションがリリースされたら、インデックスを微調整するのに本当に良いタイミングです。このサイトを見てください、stachexchange、あなたはそれがライブになってから長い時間を経てインデックスが変わったことにあなたの帽子を賭けることができます。
LosManos

@LosManos:Stack Exchangeを使用するために支払う人はいません。
ライトネスレースとモニカ

@LightnessRacesinOrbit:反対に、広告主はStack Exchangeを使用するために支払います。

@JonofAllTrades:インデックスが欠落しているために数時間パフォーマンスが低下しても気にしません。私のポイントは、永続的な配布サイクルを備えた大規模な無料のコミュニティ向けWebサイトは、定期的にリリースされる自己完結型の商用製品とは大きく異なるということです。したがって、SEは良い例ではありません。
モニカーとの軽さのレース

1

すべてのクエリを最適化する必要はないと思いますが、インデックスはRDBMSの一部であるため、リリースする前に考慮する必要があります。クエリを実行するとき、他の形式のプログラミングとは異なり、クエリの実行方法をシステムに指示していません。彼らは独自の計画を策定し、ほとんどの場合、インデックスの可用性に基づいています。データの構成と量も後ほど考慮されます。

ここに私が検討するいくつかのものがあります:

  1. 初期の開発で、頻繁に使用されることがわかっているクエリをいくつか特定する必要があります。それらに焦点を当てます。
  2. クエリが遅くなります。最初にインデックスを作成することにより、パフォーマンスがまだ十分に速くないかどうかを判断し、再設計を検討できます(非正規化は時期尚早かもしれません)。リリースする前にこれをやりたいです。インベントリで何かを見つけるのに10分かかるシステムは誰も望んでいません。
  3. インデックスはクエリのパフォーマンスを向上させる可能性がありますが、データの変更を妨げるものではありません。
  4. 多くのシステムにはクエリを分析するツールがありますので、使用することを恐れないでください。

最初のレビューの後、これを再度レビューするタイミングと、これを行うために情報を収集する方法(使用状況の監視、クライアントデータのコピーの取得など)を検討する必要があります。

時期尚早に最適化する必要はありませんが、データベースのインデックスを作成しないとパフォーマンスが低下することはほぼ確実です。これを邪魔にならないようにすることで、パフォーマンスの問題を引き起こす他の領域があるかどうかを判断できます。


0

また、予想されるユーザー数にも依存します。必ず負荷テストを行い、データベースが10〜100〜1000の同時リクエストに対応できることを確認してください。繰り返しますが、それはあなたがどれだけのトラフィックを期待するか、そしてどのエリアが他よりも多く使われると期待するかによります。

一般に、ユーザーが最初にヒットすると予想される領域を微調整します。その後、ユーザーエクスペリエンスの観点から遅いものはすべて微調整します。ユーザーが何かを待たなければならないときはいつでも、彼らは悪い経験を得て、断られるかもしれません。良くない!


0

事前分析により、どの列にインデックスが必要かを特定することをお勧めします。インデックスがまったくない場合は、データベースのサイズが大きくなるため、運用環境でパフォーマンスが徐々にまたは予期せず低下する実際のリスクがあります。回避したい状況は、一般的に実行されるクエリで多数のテーブル行をスキャンする必要がある場合です。重要な列にインデックスを追加するのは時期尚早な最適化ではありません。必要な情報の多くが利用可能であり、潜在的なパフォーマンスの違いが大きいためです(桁違い)。また、インデックスの利点がデータにあまり明確でないか、データに依存しているという状況もあります。おそらく、これらのケースのいくつかについて決定を据え置くことができます。

質問する必要があるのは次のとおりです。

  • 各テーブルのサイズの設計上の制限は何ですか?

テーブルが常に小さい場合(100行未満など)、データベースがテーブル全体をスキャンする必要がある場合、それは災害ではありません。インデックスを追加することは有益な場合がありますが、これを決定するには、もう少し専門知識または測定が必要です。

  • 各クエリはどのくらいの頻度で実行され、必要な応答時間はどれくらいですか?

クエリが頻繁に実行されず、厳密な応答時間要件(レポート生成など)がなく、行数がそれほど大きくない場合、インデックスの追加を延期することはおそらくかなり安全です。繰り返しますが、専門知識または測定は、それが有益であるかどうかを判断するのに役立ちます。

  • クエリでは、主キー以外の何かでテーブルを検索する必要がありますか?たとえば、日付範囲でフィルタリングし、外部キーに参加しますか?

これらのクエリが頻繁に実行され、多くの行を持つテーブルに触れる場合は、インデックスをプリエンプティブに追加することを真剣に検討する必要があります。これがクエリに当てはまるかどうかわからない場合は、データベースに現実的な量のデータを入力し、クエリプランを見てください。

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