web-dev-qa-db-ja.com

データベース結合はいつ、なぜ高価ですか?

私はデータベースの研究をしており、リレーショナルDBの制限を調べています。

大きなテーブルの結合は非常に高価になると思いますが、その理由は完全にはわかりません。結合操作を実行するためにDBMSで必要なことは何ですか?
非正規化はこの費用を克服するのにどのように役立ちますか?他の最適化手法(たとえば、インデックス付け)はどのように役立ちますか?

個人的な経験は大歓迎です!リソースへのリンクを投稿する場合は、ウィキペディアを避けてください。私はそれをどこで見つけるかすでに知っています。

これに関連して、BigTableやSimpleDBなどのクラウドサービスデータベースで使用される非正規化アプローチについて疑問に思っています。 この質問 を参照してください。

338
Rik

パフォーマンスを改善するための非正規化?説得力があるように聞こえますが、水を保持しません。

テッド・コッド博士と協力してリレーショナルデータモデルの最初の支持者だったクリスデイトは、正規化に対する誤った情報に基づく議論に忍耐を失い、科学的手法を使用して体系的に破壊しました:彼は大規模なデータベースを取得し、テスト済みこれらの主張。

彼はRelational Database Writings 1988-1991に書いたと思うが、この本は後にIntroduction to Database Systemsの第6版にロールバックされたtheデータベースの理論と設計に関する決定的なテキスト。執筆中の第8版であり、今後数十年間は印刷され続ける可能性があります。私たちのほとんどがまだ裸足で走り回っていたとき、クリス・デイトはこの分野の専門家でした。

彼はそれを見つけました:

  • それらのいくつかは、特別な場合のために保持します
  • それらのすべては、一般的な使用のために完済しません
  • それらのすべては、他の特別な場合には著しく悪いです

すべては、ワーキングセットのサイズを緩和することに帰着します。正しく設定されたインデックスを持つ適切に選択されたキーを含む結合は、結果の大幅なプルーニングを許可するため、安価で高価ではありませんbefore行が具体化されます。

結果の具体化には、バルクディスク読み取りが含まれます。これは、演習で最もコストのかかる側面です。対照的に、結合を実行するには、論理的にkeysのみを取得する必要があります。実際には、キー値さえもフェッチされません。キーハッシュ値は結合比較に使用され、複数列結合のコストを軽減し、文字列比較を含む結合のコストを根本的に削減します。キャッシュに大幅に収まるだけでなく、実行するディスク読み取りがはるかに少なくなります。

さらに、優れたオプティマイザーは、結合を実行する前に最も制限の厳しい条件を選択して適用し、カーディナリティの高いインデックスの結合の高い選択性を非常に効果的に活用します。

確かにこのタイプの最適化は非正規化されたデータベースにも適用できますが、スキーマを非正規化するwantのような人は、インデックスを設定する場合(通常)、カーディナリティを考慮しません。

テーブルスキャン(結合の作成中にテーブル内のすべての行を調べる)は実際にはまれであることを理解することが重要です。クエリオプティマイザーは、次の1つ以上が当てはまる場合にのみ、テーブルスキャンを選択します。

  • リレーションに含まれる行は200未満です(この場合、スキャンはより安価になります)
  • 結合列に適切なインデックスがありません(これらの列で結合することが意味がある場合、なぜインデックス化されないのですか?修正してください)
  • 列を比較する前に型強制が必要です(WTF ?!修正するか、家に帰ります)ADO.NET ISSUEの注を参照
  • 比較の引数の1つは式(インデックスなし)です

操作を実行すると、実行しないよりもコストがかかります。ただし、wrong操作を実行し、無意味なディスクI/Oを強制的に実行し、本当に必要な結合を実行する前にドロスを破棄することはmuchより高価です。 「誤った」操作が事前に計算され、インデックスが適切に適用された場合でも、重大なペナルティが残ります。結合を事前計算するための非正規化は、更新の異常を伴うにもかかわらず、特定の結合へのコミットメントです。 different joinが必要な場合、そのコミットメントにかかる費用はbigになります。

変化する世界であることを誰かに思い出させたいと思うなら、gruntierハードウェア上のより大きなデータセットはDateの調査結果の広がりを誇張するだけだと思う​​でしょう。

課金システムまたはジャンクメールジェネレーター(恥ずかしがり屋)に取り組んでおり、keyboardしげなくキーボードに手を当てて、非正規化の方が速いという事実を知っていることを教えてくれている皆さん、申し訳ありませんが、あなたは特別な場所に住んでいますケース-具体的には、データのallを順番に処理するケース。それは一般的なケースではなく、あなたの戦略でare正当化されます。

あなたはnotを誤って一般化することで正当化されています。データウェアハウジングシナリオでの非正規化の適切な使用の詳細については、「メモ」セクションの最後を参照してください。

私も対応したい

結合はリップグロスを含む単なるデカルト製品です

大量の塊。制限はできるだけ早く適用され、最も制限の厳しいものが最初に適用されます。あなたは理論を読みましたが、あなたはそれを理解していません。結合は扱われるとして「述語が適用されるデカルト積」のみクエリオプティマイザーによって。これは、シンボリック分解を促進するシンボリック表現(実際には正規化)であるため、オプティマイザーは同等の変換をすべて生成し、コストと選択性でランク付けして、最適なクエリプランを選択できます。

最適化プログラムを使用してデカルト積を生成する唯一の方法は、述語SELECT * FROM A,Bを指定しないことです。


ノート


David Aldridgeは、いくつかの重要な追加情報を提供します。

実際、インデックスとテーブルスキャン以外にもさまざまな戦略があり、最新のオプティマイザーは実行計画を作成する前にそれらすべてを犠牲にします。

実用的なアドバイス:外部キーとして使用できる場合は、インデックス戦略がオプティマイザに対してavailableになるようにインデックスを作成します。

以前は、MSSQLオプティマイザーよりも賢い人でした。それは2バージョン前に変更されました。現在では、一般的にmeを教えています。非常に現実的な意味で、エキスパートシステムであり、ルールベースのシステムが有効であるほど十分に閉じられたドメイン内の多くの非常に賢い人々のすべての知恵を成文化します。


「ボロック」は無傷だったかもしれません。私はあまりless慢にならないように頼まれ、数学は嘘をつかないことを思い出した。これは事実ですが、数学的モデルのすべての意味を必ずしも文字通りに解釈する必要はありません。負の数の平方根は、それらの不合理さを慎重に調べないようにし(そこでしゃがみます)、方程式を解釈する前にそれらをすべて取り消すようにしておくと非常に便利です。

私があまりにも野respondに答えた理由は、言葉通りの声明がそれを言うからです

結合areデカルト積...

これは意図されたものではないかもしれませんが、それはis書かれたものであり、それは明確に間違っています。デカルト積は関係です。結合は機能です。より具体的には、結合は関係値関数です。空の述語を使用すると、デカルト積が生成されます。これを確認することは、データベースクエリエンジンの1つの正当性チェックですが、教室外では実用的な価値がないため、実際には制約のない結合を記述しません。

読者がモデルとモデル化されたものを混同する古代のtrapに陥りたくないので、私はこれを呼びました。モデルは、便利な操作のために意図的に簡略化された近似です。


テーブルスキャン結合戦略の選択のカットオフは、データベースエンジンによって異なる場合があります。ツリーノードのフィルファクター、キー値のサイズ、アルゴリズムの微妙さなど、多くの実装の決定の影響を受けますが、大まかに言って高性能なインデックス付けの実行時間はk log- n + c。 C項は、ほとんどがセットアップ時間で構成される固定オーバーヘッドであり、曲線の形状は、nが数百になるまで(線形検索と比較して)利益を得られないことを意味します。


時には非正規化が良い考えです

非正規化は、特定の結合戦略へのコミットメントです。前述のように、これはother結合戦略を妨害します。しかし、ディスクスペースのバケット、予測可能なアクセスパターン、およびその大部分またはすべてを処理する傾向がある場合、結合の事前計算は非常に価値があります。

また、操作で通常使用されるアクセスパスを把握し、それらのアクセスパスのすべての結合を事前計算することもできます。これは、データウェアハウスの背後にある前提です。または、少なくとも、流行語のコンプライアンスのためだけでなく、なぜ自分がやっていることをしているのかを知っている人々によって構築される場合です。

適切に設計されたデータウェアハウスは、正規化されたトランザクション処理システムからのバルク変換によって定期的に生成されます。この操作データベースとレポートデータベースの分離は、OLTPとOLAP(オンライントランザクション処理、つまりデータ入力、オンライン分析処理、つまりレポート)間の衝突を排除するという非常に望ましい効果があります。

ここで重要な点は、定期的な更新とは別に、データウェアハウスが読み取り専用であることです。これにより、更新の異常の問題が未解決になります。

OLTPデータベース(データ入力が発生するデータベース)の非正規化の間違いをしないでください。課金実行の方が高速かもしれませんが、そうすると更新の異常が発生します。 Reader's Digestにあなたのものの送信を停止させようとしたことがありますか?

最近のディスク容量は安いので、ノックアウトしてください。ただし、非正規化はデータウェアハウスの話の一部にすぎません。はるかに大きなパフォーマンスの向上は、事前に計算されたロールアップされた値(1か月の合計など)から得られます。 alwaysは、ワーキングセットの削減についてです。


型の不一致に関するADO.NETの問題

Varchar型のインデックス付き列を含むSQL Serverテーブルがあり、AddWithValueを使用してこの列のクエリを制約するパラメーターを渡すとします。 C#文字列はUnicodeであるため、推定されるパラメータータイプはNVARCHARになりますが、これはVARCHARと一致しません。

VARCHARからNVARCHARへの変換は拡張変換であるため、暗黙的に行われますが、インデックス作成に別れを告げ、その理由を解明することができます。


「ディスクヒットのカウント」(Rick James)

すべてがRAMにキャッシュされている場合、JOINsはかなり安価です。つまり、正規化には多くのパフォーマンスペナルティがありません。

「正規化された」スキーマによってJOINsがディスクに頻繁にヒットするが、同等の「非正規化された」スキーマがディスクにヒットする必要がない場合、非正規化はパフォーマンスの競争に勝ちます。

原作者からのコメント:最新のデータベースエンジンは、アクセスシーケンスを整理して、結合操作中のキャッシュミスを最小限に抑えることができます。上記は真実ですが、大きなデータでは結合が必然的に費用がかかることを意味するものとして誤解される可能性があります。これにより、経験の浅い開発者の意思決定が不十分になります。

454
Peter Wone

ほとんどのコメント者が注意を怠っているのは、複雑なRDBMSで利用可能なさまざまな結合方法論であり、非正規化者は非正規化データを維持するためのコストが高いことを常に示しています。すべての結合がインデックスに基づいているわけではなく、データベースには、結合コストを削減することを目的とした、最適化された多くのアルゴリズムと結合方法があります。

いずれにせよ、結合のコストはその種類といくつかの他の要因に依存します。それはまったく高価である必要はありません-いくつかの例。

  • バルクデータが等価結合されるハッシュ結合は、実際には非常に安価であり、ハッシュテーブルをメモリにキャッシュできない場合にのみコストが大きくなります。インデックスは不要です。結合されたデータセット間の等分割は、非常に役立ちます。
  • ソート/マージ結合のコストは、マージではなくソートのコストに左右されます。インデックスベースのアクセス方法は、ソートのコストを事実上排除できます。
  • インデックスに対するネストされたループ結合のコストは、Bツリーインデックスの高さとテーブルブロック自体のアクセスによって決まります。高速ですが、バルク結合には適していません。
  • クラスターに基づくネストされたループ結合ははるかに安価で、結合行ごとに必要な論理IOが少なくなります。結合テーブルが両方とも同じクラスターにある場合、結合行のコロケーションによって結合は非常に安くなります。

データベースは結合するように設計されており、結合方法が非常に柔軟であり、結合メカニズムが間違っていない限り、一般に非常にパフォーマンスが高くなります。

44
David Aldridge

質問全体が誤った前提に基づいていると思います。大きなテーブルの結合は、not必ずしも高価です。実際、結合を効率的に行うことが、リレーショナルデータベースが存在する主な理由の1つですまったく。大きいsetsでの結合は多くの場合高価ですが、大規模なテーブルAのコンテンツ全体を大規模なテーブルBのコンテンツ全体と結合することはほとんどありません。代わりに、各テーブルの重要な行のみが使用され、結合によって保持される実際のセットが小さくなるようにクエリを記述します。

さらに、最終結果セットが具体化されるまで、各レコードの重要な部分のみをメモリに格納する必要があるように、Peter Woneが述べた効率性があります。また、多くの結合を持つ大規模なクエリでは、通常、小さなテーブルセットから始めて、大きなテーブルセットまで処理して、メモリ内に保持されるセットが可能な限り小さくなるようにします。

適切に行われると、結合は通常、大量のデータを比較、結合、またはフィルター処理するための最良の方法になります。

27
Joel Coehoorn

ボトルネックはほとんどalways disk I/O、さらに具体的には-ランダムディスクI/Oです(比較すると、シーケンシャルリードはかなり高速で、先読み戦略でキャッシュできます)。

結合canランダムシークを増やします-大きなテーブルの小さな部分を読んでジャンプしている場合。しかし、クエリオプティマイザーはそれを探し、それがより良いと思う場合、シーケンシャルテーブルスキャンに変換します(不要な行を破棄します)。

単一の非正規化テーブルにも同様の問題があります。行が大きいため、単一のデータページに収まりません。別の行から遠く離れた行が必要な場合(および行サイズが大きいと行がさらに離れます)、よりランダムなI/Oが発生します。繰り返しますが、これを避けるためにテーブルスキャンが強制される場合があります。ただし、今回は、行サイズが大きいため、テーブルスキャンでより多くのデータを読み取る必要があります。それに加えて、あなたがデータのコピーを1つの場所から複数の場所に移動すると、RDBMSにはさらに多くの読み取り(およびキャッシュ)が必要になります。

2つのテーブルを使用すると、2つのクラスター化インデックスも取得できます。また、挿入/更新のオーバーヘッドが少ないため、通常より多くのインデックスを作成でき、パフォーマンスが大幅に向上します(主に、インデックスが(比較的)小さく、ディスクからの読み取りが速いためです) (またはキャッシュが安価)、ディスクから読み取る必要があるテーブル行の量を減らします)。

結合の唯一のオーバーヘッドは、一致する行を把握することから得られます。 SQL Serverは、主にデータセットサイズに基づいて3種類の結合を使用して、一致する行を見つけます。オプティマイザーが誤った結合タイプを選択した場合(不正確な統計、不適切なインデックス、またはオプティマイザーのバグやエッジの場合)、クエリ時間に大きな影響を与える可能性があります。

  • ループ結合は、(少なくとも1つの)小さなデータセットに対しては非常に安価です。
  • マージ結合では、最初に両方のデータセットの並べ替えが必要です。ただし、索引付けされた列で結合する場合、索引はすでにソートされているため、追加の作業は必要ありません。そうしないと、ソート時にCPUとメモリのオーバーヘッドが発生します。
  • ハッシュ結合には、メモリ(ハッシュテーブルを格納するため)とCPU(ハッシュを構築するため)の両方が必要です。繰り返しになりますが、これはディスクI/Oに関してはかなり高速です。 ただし、ハッシュテーブルを格納するのに十分なRAMがない場合、SQL Serverはtempdbを使用してハッシュテーブルの一部と見つかった行を格納し、次にハッシュテーブルの一部のみを処理します時間。すべてのディスクと同様に、これはかなり遅いです。

最適な場合、これらはディスクI/Oを引き起こさないため、パフォーマンスの観点からは無視できます。

全体として、最悪の場合、同じ量のlogicalのデータをx個の結合テーブルから読み取る方が高速です。これは、ディスク読み取りが少ないため、単一の非正規化テーブルからのものです。同じ量の物理データを読み取るには、若干のオーバーヘッドが発生する可能性があります。

クエリ時間は通常I/Oコストに左右され、データのサイズは非正規化によって変化しないため(非常に小さな行オーバーヘッドを差し引くことはありません)、テーブルをマージするだけでは大きな利点はありません。パフォーマンスを向上させる傾向がある非正規化のタイプであるIMEは、計算に必要な10,000行を読み取る代わりに、計算値をキャッシュします。

11
Mark Brackett

テーブルを結合する順序は非常に重要です。データのセットが2つある場合は、最初に最小のものを使用してクエリで処理する必要があるデータ量を削減するような方法でクエリを作成してください。

一部のデータベースでは重要ではありません。たとえば、MS SQLはほとんどの場合、適切な結合順序を知っています。一部の(IBM Informixなど)の場合、順序によってすべての違いが生じます。

4
Ilya Kochetov

結合の複雑度クラスを考慮する場合、非正規化するか正規化するかを決定するのは非常に簡単なプロセスです。たとえば、クエリがO(k log n)である場合、正規化を使用してデータベースを設計する傾向があります。ここで、kは目的の出力の大きさに関連しています。

パフォーマンスを非正規化して最適化する簡単な方法は、正規化構造の変更が非正規化構造にどのように影響するかを考えることです。ただし、非正規化された構造で動作するためにトランザクションロジックが必要になる場合があるため、問題が発生する可能性があります。

問題は膨大であるため、正規化と非正規化の議論は終わりません。自然な解決策が両方のアプローチを必要とする多くの問題があります。

一般的なルールとして、私は常に再構築可能な正規化された構造と非正規化されたキャッシュを保存しています。最終的に、これらのキャッシュは、将来の正規化の問題を解決するために私の尻を救います。

0
MathGladiator