スケーラビリティを検討するときに結合が悪いのはなぜですか?


92

参加が悪い、または「遅い」のはなぜですか。これを何度も聞いたことがあります。この見積もりを見つけました

問題は、結合が比較的遅いこと、特に非常に大きなデータセットの場合、結合が遅い場合、ウェブサイトが遅いことです。これらの個別の情報をすべてディスクから取り出し、それらをすべてまとめ直すには長い時間がかかります。

ソース

特にPKを検索するときは、特に高速だと思っていました。なぜ「遅い」のですか?

sql  join 

回答:


98

スケーラビリティとは、ワークユニットごとのリソースの使用を最小限に抑えるために、繰り返される作業を必要最低限​​のものまで事前計算、分散、または削減することです。適切にスケーリングするために、ボリュームに必要のないことは何もせず、実際に行っていることを確実に行うには、可能な限り効率的に行います。

そのコンテキストでは、もちろん、2つの別個のデータソースを結合することは、少なくともそれらを結合しないことと比較すると、ユーザーが要求した時点でライブで行う必要がある作業であるため、比較的低速です。

ただし、別の方法では2つの別個のデータがまったく存在しないことに注意してください。2つの異なるデータポイントを同じレコードに配置する必要があります。どこかに影響を与えずに2つの異なるデータを結合することはできないため、トレードオフを理解するようにしてください。

良いニュースは、最新のリレーショナルデータベースが結合に優れていることです。良いデータベースがうまく使用されていれば、結合を遅いと考えてはいけません。生の結合を取り、それをはるかに高速にするためのスケーラビリティに適した方法がいくつかあります。

  • 自然キーではなく、代理キー(オートナンマ/ ID列)で結合します。これは、結合操作中の比較が小さい(したがって高速)であることを意味します。
  • インデックス
  • マテリアライズド/インデックス付きビュー(これは事前計算された結合または管理された非正規化と考えてください)
  • 計算された列。これを使用して、結合のキー列をハッシュまたは別の方法で事前計算できます。これにより、結合の複雑な比較がはるかに小さくなり、事前にインデックスが作成される可能性があります。
  • テーブルパーティション(複数のディスクに負荷を分散するか、テーブルスキャンをパーティションスキャンに限定することにより、大きなデータセットを支援します)
  • OLAP(特定の種類のクエリ/結合の結果を事前に計算します。これは正確ではありませんが、これを一般的な非正規化と考えることができます)
  • レプリケーション、可用性グループ、ログ配布、または複数のサーバーが同じデータベースの読み取りクエリに応答できるようにする他のメカニズム。したがって、ワークロードを複数のサーバー間でスケールアウトします。
  • 複雑な結合を必要とするクエリの再実行を回避するためのRedisのようなキャッシュレイヤーの使用。

私は限り言うように行くだろう、リレーショナルデータベースがまったく存在した主な理由は、あなたが効率的に参加しないようにすることです*。確かに、構造化されたデータを保存するだけではありません(csvやxmlなどのフラットファイル構成でそれを行うことができます)。私がリストしたいくつかのオプションでは、事前に完全に結合を構築することもできるため、クエリを発行する前に、データを非正規化した場合と同じように、結果が既に行われています(確かに、書き込み操作が遅くなります)。

結合が遅い場合は、データベースを正しく使用していない可能性があります。

非正規化は、これらの他の手法が失敗した後にのみ行う必要があります。そして、「失敗」を本当に判断できる唯一の方法は、意味のあるパフォーマンス目標を設定し、それらの目標を測定することです。測定していない場合、非正規化について考えることも早すぎます。

*つまり、単なるテーブルのコレクションとは異なるエンティティとして存在します。実際のRDBMSのもう1つの理由は、安全な同時アクセスです。


14
インデックスはおそらくリストの一番上にあるはずです。多くの(咳をする)開発者は、小さなデータセットでテストするときにそれらを忘れて、データベースを本番環境に移行します。インデックスを追加するだけで、クエリが100,000倍の速度で実行されることを確認しました。そして、これは、左端のプレフィックスマッチングに最適な組み合わせを決定するための詳細なデータ分析さえも行わない、任意のインデックスです。
ダンカン

私は正しい順序を持っていると思います-ほとんどの開発者がすでに最初の項目を実行しているだけなので、インデックスは変更を行う必要がある最初の項目です。
Joel Coehoorn、2010

3番目の項目では、「マテリアライズド/インデックス付きビュー」について言及しています。通常のSQLビューなどについて話しているのですか?
slolife 2010

@slolifeの通常のSQLビューは、ビューを参照するクエリを使用するときに、追加のクエリをオンザフライでバックグラウンドで実行するようなものです。ただし、一部のビューを「具体化」するようにSQLサーバーに指示することもできます。これを行うと、SQLサーバーは、通常のテーブルと同じように、ビューのデータの追加のコピーを保持します。これにより、クエリでビューを参照するときに、データが既にあるため、このクエリをバックグラウンドで実行する必要がなくなります。 。ソーステーブルとは異なるインデックスをビューに配置して、パフォーマンスをさらに調整することもできます。
Joel Coehoorn

ジョエル、ありがとう。それを調べなければならない。
slolife

29

結合は、非正規化によって回避するより遅くなる可能性がありますが、適切に使用すると(適切なインデックスを持つ列での結合など)、本質的に遅くなりません

非正規化は、適切に設計されたデータベーススキーマにパフォーマンスの問題がある場合に検討できる最適化手法の1つです。


2
... MySQLを除きます。これは、インデックスの外観に関係なく、多数の結合でパフォーマンスの問題があるようです。あるいは、少なくとも過去にはそうでした。
Powerlord 2010

2
要点として、特定のDBMS(場合によってはバージョン)に既知の問題がある場合、このアドバイスは理にかなっていますが、一般的なアドバイスとして、リレーショナルデータベースを使用している場合はかなり誤解を招きます。非リレーショナルストレージメカニズムの人気が高まっていることから、AmazonのSimpleDBとCouchDB(couchdb.apache.org)がその例です。リレーショナルモデルを残しておくほうがよい場合は、おそらく背後で最適化された製品も残して、他のツールを探す必要があります。
Tendayi Mawushe

13

記事には、結合がない場合と比較すると遅いと記載されています。これは非正規化で実現できます。したがって、速度と正規化の間にはトレードオフがあります。時期尚早の最適化も忘れないでください:)


これは難しい規則ではありませんが、テーブルで結合すると、mysqlはその結合を実行するためにインデックスを使用する可能性があります。参加しない場合、mysqlは通常、where句がどのように形成されていても、1つのインデックスのみを使用します(これは最も効率的なインデックスではない可能性があります)。
leeeroy

11

まず、リレーショナルデータベースの存在理由(存在理由)は、エンティティ間の関係をモデル化できるようにすることです。結合は、これらの関係をたどるメカニズムです。これらは確かにわずかなコストで提供されますが、結合なしでは、リレーショナルデータベースを用意する理由はありません。

学問の世界では、さまざまな正規形(1次、2次、3次、ボイスコッドなど)のようなものについて学び、さまざまなタイプの鍵(主、外部、代替、一意など)とその方法について学びますこれらを組み合わせてデータベースを設計します。また、SQLの基礎と、構造とデータ(DDLとDML)の両方の操作について学びます。

企業の世界では、多くの学術的構成要素は、私たちが信じていたよりも実質的に実行可能性が低いことが判明しています。完璧な例は、主キーの概念です。学術的には、テーブル内の1つの行を一意に識別する属性(または属性のコレクション)です。したがって、多くの問題領域で、適切な学術的主要キーは3つまたは4つの属性の複合です。ただし、現代の企業世界のほとんどすべての人が、自動生成された連続した整数をテーブルの主キーとして使用しています。どうして?2つの理由。1つ目は、FKをあちこちに移行する場合にモデルがよりクリーンになるためです。2番目の、そしてこの質問に最も密接に関係しているのは、結合を介してデータを取得する方が、単一の整数の方が4つのvarchar列よりも高速で効率的であることです(既に数人が言及しているように)。

ここで、実世界のデータベースの2つの特定のサブタイプについてもう少し詳しく見ていきましょう。最初のタイプはトランザクションデータベースです。これは、最新のサイトを推進する多くの電子商取引またはコンテンツ管理アプリケーションの基盤です。トランザクションDBを使用すると、「トランザクションスループット」に向けて大幅に最適化できます。ほとんどのコマースアプリやコンテンツアプリでは、(特定のテーブルからの)クエリのパフォーマンスと(他のテーブルからの)挿入のパフォーマンスのバランスをとる必要がありますが、各アプリには解決すべき独自のビジネス主導の問題があります。

2番目のタイプの実世界データベースは、レポートデータベースです。これらは、ほぼ独占的にビジネスデータを集約し、意味のあるビジネスレポートを生成するために使用されます。これらは通常、データが生成されるトランザクションデータベースとは形状が異なり、大規模または複雑なデータセットでのバルクデータロード(ETL)の速度とクエリパフォーマンスのために高度に最適化されています。

どちらの場合も、開発者またはDBAは、機能とパフォーマンスの両方の曲線のバランスを慎重に取る必要があり、方程式の両側には、パフォーマンスを強化するための多くのトリックがあります。Oracleでは、「説明計画」と呼ばれる処理を実行できるので、クエリがどのように解析および実行されるかを具体的に確認できます。DBのインデックスの適切な使用を最大化しようとしています。本当に厄介なのは、クエリのwhere句に関数を配置することです。これを行うときはいつでも、Oracleがその特定の列でインデックスを使用しないことを保証し、Explainプランでテーブルの完全または部分的なスキャンが行われる可能性があります。これは、クエリがどのように記述されて低速になる特定の例にすぎず、結合とは何の関係もありません。

また、テーブルスキャンについて説明している間、テーブルのサイズに比例してクエリ速度に明らかに影響します。100行のフルテーブルスキャンは目立ちません。1億行のテーブルで同じクエリを実行すると、来週に戻って戻ってくる必要があります。

正規化について少し話しましょう。これは、過度にストレスがかかる可能性のある、もう1つの大きな肯定的な学術トピックです。私たちが正規化について話すとき、ほとんどの場合、それは実際にそれを独自のテーブルに入れてFKを移行することによって重複データを排除することを意味します。人々は通常、2NFと3NFによって記述される依存関係の全体をスキップします。さらに、極端な場合でも、非常に正規化されているため、巨大で完全な獣をコード化する完璧なBCNFデータベースを作成することは確かに可能です。

では、どこでバランスを取るのでしょうか?単一のベストアンサーはありません。より良い答えはすべて、構造の保守の容易さ、データの保守の容易さ、およびコードの作成/保守の容易さの間の妥協である傾向があります。一般に、データの重複が少ないほど良いです。

では、なぜ結合が遅くなるのですか?時々それは悪い関係設計です。時々それは効果的な索引付けではありません。時々それはデータ量の問題です。ひどく書かれたクエリである場合もあります。

このように長々とした答えで申し訳ありませんでしたが、私は4箇条書きの応答をただガタガタと鳴らすのではなく、コメントの周りにもっと重要なコンテキストを提供することを強いられました。


10

テラバイトサイズのデータ​​ベースを使用している人々は、パフォーマンスの面で機能させることができれば、結合を使用できます。

デノマライズしない理由はたくさんあります。まず、選択クエリの速度だけがデータベースの主な関心事ではありません。データの整合性が最初の関心事です。非正規化する場合は、親データが変更されたときにデータを非正規化しておくための手法を導入する必要があります。したがって、client_Idでクライアントテーブルに参加するのではなく、すべてのテーブルにクライアント名を格納するとします。ここで、クライアントの名前が変更された場合(クライアントの名前の一部が時間とともに変更される可能性は100%です)、その変更を反映するようにすべての子レコードを更新する必要があります。カスケード更新でこれを実行し、100万の子レコードがある場合、それがどのくらいの速さであり、ロック問題が発生し、それが発生している間、作業の遅延を被るユーザーは何人いると思いますか?さらに、非正規化するほとんどの人は

非正規化は複雑なプロセスであり、正しく実行するには、データベースのパフォーマンスと整合性を完全に理解する必要があります。スタッフにそのような専門知識がない限り、非正規化を試みないでください。

いくつかのことを行うと、結合は非常に高速になります。最初にサゴゲートキーを使用します。int結合は、最速の結合です。次に、常に外部キーにインデックスを付けます。派生テーブルまたは結合条件を使用して、フィルタリングする小さなデータセットを作成します。大規模で非常に複雑なデータベースがある場合は、巨大なデータベースの分割と管理の経験を持つ専門のデータベース担当者を雇います。結合を削除せずにパフォーマンスを向上させるためのテクニックはたくさんあります。

クエリ機能だけが必要な場合は、そうです。非正規化が可能で、ユーザーデータエントリではなくETLツール(速度を最適化したもの)を介して入力されるデータウェアハウスを設計できます。


8

結合が遅い場合

  • データのインデックスが不適切である
  • 結果のフィルタリングが不十分
  • 不十分に書かれたクエリの結合
  • 非常に大きく複雑なデータセット

したがって、確かに、データセットが大きいほど、クエリに必要な処理が多くなりますが、上記の最初の3つのオプションを確認して作業すると、多くの場合素晴らしい結果が得られます。

ソースはオプションとして非正規化を提供します。これは、より良い代替手段を使い果たしている場合にのみ問題ありません。


7

両側のレコードの大部分をスキャンする必要がある場合、結合が遅くなる可能性があります。

このような:

SELECT  SUM(transaction)
FROM    customers
JOIN    accounts
ON      account_customer = customer_id

でインデックスが定義されている場合でもaccount_customer、後者のすべてのレコードをスキャンする必要があります。

クエリリストの場合、適切なオプティマイザはインデックスアクセスパスを考慮せずHASH JOINMERGE JOIN代わりにa またはa を実行します。

次のようなクエリの場合は注意してください。

SELECT  SUM(transaction)
FROM    customers
JOIN    accounts
ON      account_customer = customer_id
WHERE   customer_last_name = 'Stellphlug'

結合はおそらく高速になります。最初に、customer_last_nameすべてのStellphlug(もちろん、それほど多くはありません)をフィルターするためにインデックスオンが使用されます。次に、account_customerStellphlugごとにインデックススキャンが発行され、トランザクションを見つけます。

これらはaccountsおよびcustomersで数十億のレコードになる可能性があるという事実にもかかわらず、実際にスキャンする必要があるのはごくわずかです。


しかし、それを避けるのは難しいです。この種のクエリが頻繁に実行されないようにアプリを設計してください。
Andrey

1
accounts(account_customer)ほとんどのRDBMSでインデックスが定義されている場合、そのインデックスを使用して、customersスキャンする必要があるデータベースの行を正確に特定します。
jemfinch 2010

はい、とにかく安くはありません。合計をいくつかのフィールドに格納し、各トランザクションで更新できます。
Andrey

@jemfinch:いいえ、彼らはしません。これには、顧客を除外するためだけにインデックス全体をスキャンしてから、ネストされたループで顧客のインデックスをスキャンする必要があります。AのHASH JOIN方がはるかに高速なのでMySQL、を除くすべての主要なデータベースを除いて使用されます。ただし、customersネストされたループで先頭に立つだけです(サイズが小さいため)
Quassnoi

4

Joins are fast.結合は、適切に正規化されたデータベーススキーマを使用する標準的な方法と見なされます。結合を使用すると、データの異なるグループを有意義な方法で結合できます。参加を恐れないでください。

注意点は、インデックスの正規化、結合、および適切な使用を理解する必要があることです。

すべての開発プロジェクトで失敗する最大の原因は期限を満たしているため、時期尚早の最適化に注意してください。プロジェクトを完了し、トレードオフを理解したら、正当化できればルールを破ることができます。

データセットのサイズが大きくなると、結合のパフォーマンスが非線形的に低下するのは事実です。したがって、単一のテーブルクエリほどうまく拡張できませんが、拡張は可能です。

鳥が翼を持たずに速く飛ぶのは真実であるということも事実です。


3

結合では、データを「結合」するためにより多くのファイルとインデックスを調べる必要があるため、追加の処理が必要です。ただし、「非常に大きなデータセット」はすべて相対的です。largeの定義は?結合の場合、それは全体的なデータセットではなく、大きな結果セットへの参照だと思います。

ほとんどのデータベースは、プライマリテーブルから5つのレコードを選択し、各レコードの関連テーブルから5つのレコードを結合するクエリを非常に迅速に処理できます(正しいインデックスが設定されている場合)。これらのテーブルには、それぞれ数億、または数十億のレコードを含めることができます。

結果セットが成長し始めると、状況は遅くなります。同じ例を使用して、プライマリテーブルの結果が100Kレコードの場合、500Kの「結合された」レコードが見つかる必要があります。追加の遅延を伴い、データベースからデータをプルするだけです。

結合は避けないでください。データセットが「非常に大きく」なると、最適化/非正規化が必要になる場合があることを知っておいてください。


3

また、引用した記事から:

何十億ものレコード、ペタバイトのデータ、何千もの同時ユーザー、1日に何百万ものクエリが実行される多くのメガスケールのWebサイトは、シャーディングスキームを使用しており、データ層を構築するための最適な戦略として非正規化を主張しているウェブサイトもあります。

そして

そして、あなたが本当に大規模なウェブサイトでなければ、おそらくこのレベルの複雑さについて心配する必要はないでしょう。

そして

データベースにこの作業をすべて行わせるよりもエラーが発生しやすくなりますが、最上位のデータベースでも処理できる範囲を超えて拡張することができます。

この記事では、Ebayのようなメガサイトについて説明しています。その使用レベルでは、単純なバニラリレーショナルデータベース管理以外のものを検討する必要があるでしょう。しかし、「通常の」ビジネスコース(数千のユーザーと数百万のレコードを持つアプリケーション)では、これらのより高価でエラーが発生しやすいアプローチは過剰です。


2

結合は一般にボトルネックであり、簡単に分散または並列化できないため、スケーラビリティに対する反対の力と見なされます。


これが本当かどうかはわかりません。Teradataは確かにアンプ間で結合を分散できることを知っています。明らかに、特定の種類の結合は、他の結合よりも扱いにくい/扱いにくい場合があります。
Cade Roux

インデックスは、mysqlからoracleまでのRDBMSでパーティション化できます。拡大縮小するAFAIK(分散され、並列化できる)。
Unreason

2

適切なインデックスと適切に作成されたクエリを含む適切に設計されたテーブルは常に遅くなるとは限りません。あなたが聞いたことがあるところ:

参加が悪い、または「遅い」のはなぜですか

彼らが何について話しているのか分かりません!!! ほとんどの結合は非常に高速になります。一度に多くの行を結合する必要がある場合は、非正規化されたテーブルと比較してヒットする可能性がありますが、それは適切に設計されたテーブルに戻ります。重いレポートシステムでは、レポート用に非正規化テーブルのデータを分割するか、データウェアハウスを作成します。トランザクションの多いシステムでは、テーブルを正規化します。


1

生成される一時データの量は、結合に基づいて膨大になる可能性があります。

たとえば、ここで使用している1つのデータベースには、すべてのフィールドがオプションである一般的な検索機能がありました。検索ルーチンは、検索が始まる前にすべてのテーブルで結合を行いました。これは最初はうまくいきました。しかし、メインテーブルには1,000万行以上あるので、それほど多くはありません。検索には30分以上かかります。

検索ストアドプロシージャを最適化する必要がありました。

最初に行ったのは、メインテーブルのフィールドのいずれかが検索されている場合、それらのフィールドのみで一時テーブルを選択しました。その後、残りの検索を行う前に、すべてのテーブルをその一時テーブルに結合しました。メインテーブルフィールドの1つが10秒未満である検索。

メインテーブルのフィールドが検索されない場合は、他のテーブルに対しても同様の最適化を行います。私が終わったとき、検索に30秒以上かかることはなく、ほとんどの場合10以下です。

SQLサーバーのCPU使用率もWAY DOWNになりました。


@BoltBait:結合を実行する前に、常に行数を減らすようにすべきであるというメッセージはありますか?
unutbu 2010

それは確かに私の場合には不思議に働いた。しかし、必要になるまではシステムを最適化しません。
BoltBait 2010

通常、結合時に一時データは生成されません(もちろん、選択性、使用可能なメモリ、および結合バッファーのサイズによって異なります)。ただし、一時的なデータは通常、そのような操作に使用できるインデックスがない場合、順番に作成され、区別されます。
Unreason

1

結合(おそらく正規化された設計が原因)は明らかに単一のテーブルからの読み取りよりもデータの取得が遅くなる可能性がありますが、非正規化されたデータベースは、トランザクション全体のフットプリントが最小にならないため、データの作成/更新操作が遅くなる可能性があります。

正規化されたデータベースでは、データの一部が1か所にしか存在しないため、更新のフットプリントは最小限に抑えられます。非正規化されたデータベースでは、複数の行またはテーブル間で同じ列を更新する必要がある可能性があります。つまり、フットプリントが大きくなり、ロックとデッドロックの可能性が高くなります。


1

ええ、ええ、1つの非正規化されたテーブルから行を選択する(クエリに適切なインデックスがあると仮定)と、複数のテーブルの結合から構築された行を選択するよりも、特に結合に有効なインデックスがない場合は、より速くなる可能性があります。

記事で引用されている例-FlickrとeBay-はIMOの例外的なケースなので、例外的な応答があります(それに値します)。著者は、記事のRIの欠如とデータ重複の程度を具体的に指摘しています。

ほとんどのアプリケーション(ここでもIMO)は、RDBMSによって提供される検証と重複の削減の恩恵を受けます。


0

だらしないと遅くなることがあります。たとえば、結合で「select *」を実行すると、データを取り戻すのにしばらく時間がかかります。ただし、各テーブルから返す列を慎重に選択し、適切なインデックスを配置すれば、問題はありません。

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