参加は怠惰な人のためですか?


169

私は最近、JOIN(SQL)は役に立たないと主張した別の開発者と話し合いました。これは技術的には真実ですが、ジョインを使用すると、コード(C#またはJava)で複数のリクエストとリンクテーブルを作成するよりも効率が悪いと付け加えました。

彼にとっての参加は、パフォーマンスを気にしない怠惰な人々のためのものです。これは本当ですか?結合の使用を避けるべきですか?


114
いいえ。データベースは結合を実行するように最適化されており、特に大規模なデータセットの場合は非常に高速です。アプリケーションで数万行をロードし、それらを手動でマージする必要はありません。
ハーフダン

91
プログラミング言語は怠惰な人々のためのものです。これらは、CPU命令を手動でコーディングするよりも効率的ではありません。:)
マイケル・マッゴーワン

76
開発者の名前は何ですか?彼を絶対に雇わないようにしたい。
ジョー

39
@Michael meh、本物のプログラマは蝶を使います...
マークグラベル

14
あなたの「これは本当」-いいえ、そうではありません。データベースは集合論を介して機能します。セットの結合は非常にうまく機能し、便利に機能します...
Marc Gravell

回答:


188

いいえ、そのような信じられないほど間違った意見を抱いている開発者は避けるべきです。

多くの場合、データベースの結合は、DBのラウンドトリップを回避し、DBがインデックスを使用して結合を実行できるため、クライアントを介して行うものよりも数桁高速です。

私の頭の外では、正しく使用された結合が同等のクライアント側の操作よりも遅い単一のシナリオを想像することさえできません。

編集:カスタムクライアントコードが単純なDB結合よりも効率的に処理できるまれなケースがあります(メリトンによるコメントを参照)。しかし、これは非常に例外です。


1
3方向結合についてはどうですか?「コード内」で実行した方がよい場合はありませんか?
julien_c

56
アプリケーションサーバーに参加することができ、データベースに加入すると、ネットワークを介して送信される結果セットの深刻な冗長性が生じた場合、より効率的であること。Aの各行がBの20行に関連付けられているBのテーブルAとBを考えます。Bには100行しかないため、Aから最初の1000行をフェッチし、Bから関連付けられた行を取得します。データベースに結合すると、20になります。 * 1000タプルがネットワーク経由で送信されます。アプリサーバーで結合が行われた場合(最初にBテーブル全体をメモリにフェッチする)、100 + 1000行だけがネットワーク経由で送信されます。
メリトン

7
ただし、ほとんどの場合、データベースへの結合ははるかに高速であり、したがって、利便性だけでなく必要性もあるという点で、間違いなく正しいです。
メリトン

13
私は幸運にも、マイクロソフトでSQL Serverに取り組んでいる開発者の何人かと話すことができました。それはあなたが彼らがクエリで行う最適化を聞いてめまいをするようになります。彼らがそれより賢いと思っている人は誰でも叩かれる必要があります。
riwalk 2011

2
@メリトン私は少し驚いています。クライアントライブラリがクロス結合を最適化すると期待します。
Phil Lello、

83

あなたの同僚は、SQLなしのドキュメントデータベースまたはキー値ストアでうまくいくように思えます。それ自体が非常に優れたツールであり、多くの問題に適しています。

ただし、リレーショナルデータベースは、セットを操作するために大幅に最適化されています。多くのラウンドトリップよりもはるかに効率的な結合に基づいてデータをクエリする方法は数多くあります。これが、rdbmsの多様性の源です。nosqlストアでも同じことを実現できますが、多くの場合、クエリの異なる性質ごとに適した個別の構造を構築することになります。

要するに:私は同意しません。RDBMSでは、結合が基本です。それらを使用していない場合は、RDBMSとして使用していません。


46

まあ、彼は一般的なケースでは間違っています。

データベースは、オプティマイザヒント、テーブルインデックス、外部キーの関係、および場合によっては他のデータベースベンダー固有の情報を利用して、さまざまな方法で最適化できます。


1
データベースを使い始めたとき、私は結合のパフォーマンスを打ち負かすことができると同じ信念を持っていたことを認めなければなりません。しかし、DBによって驚くほど高速な結合が行われることを理解するのにそれほど時間はかかりませんでした。実際、私はこの状況では、ばか者として彼を解雇するよりも、オープンな方法で従業員と話し合うほうがよいと言います。
LegendLength 2016年

1
@LegendLength彼らがそれほど賢くないなら、私はそれが本当であるとさえ言うでしょう。彼らは私たちが覚えているのと同じ間違いをするので、賢さを想定する必要はありません(実際、私にとっては、それほど賢くないことを意味するかもしれません...)それはより単純です。たまに間違えても大丈夫です!
2016年

24

いいえ、できません。

データベースは特にデータのセットを操作するように設計されています(明らかに...)。したがって、これは非常に効率的です。自分のコードで本質的に手動の結合を行うことにより、彼はその仕事のために特別に設計されたものの役割を引き継ぐことを試みています。彼のコードがデータベースのコードと同じくらい効率的である可能性は非常に低いです。

余談ですが、結合なしで、データベースを使用するポイントは何ですか?彼はテキストファイルを使用することもできます。


2
結合なしでも?自動メモリ内マッピング、自動クエリキャッシング、他の多くのオートマジック機能。ほとんどのファイルシステムではまったく発生しません。ああ、私は細かく制御可能なトランザクションについて言及しましたか?
Piskvorは

19

「怠惰」が少ないコードを記述したい人々として定義されている場合、私は同意する。「怠惰」が、自分の得意なことをツールに実行してもらいたい人々として定義されている場合、私は同意する。したがって、もし彼が(良いプログラマーの属性に関して)ラリー・ウォールに単に同意しているなら、私は彼に同意します。


lazyの精度を追加しました。パフォーマンスを気にせず、少ないコードを書くことを好む怠惰な人々のために。結合は怠惰な人向けだと思いますが、この場合、結合はいくつかの要求よりも優れています。
バスティアンヴァンダム

3
@Dran Dane:参加は怠惰な人向けです、はい。それらがうまく機能する可能性が高いという事実は直交しています。
Piskvorは

16

うーん、結合は、リレーショナルデータベースがテーブルを相互に関連付ける方法です。彼が何をしているのかよくわかりません。

データベースに対して複数の呼び出しを行うと、1つの呼び出しよりも効率的になりますか?さらに、SQLエンジンは、この種のことを行うために最適化されています。

おそらくあなたの同僚はSQLを学ぶのが面倒です。


12

はい、そうすべきです。

また、パフォーマンスのため、C#ではなくC ++を使用する必要があります。C#は怠惰な人向けです。

ダメダメダメ。パフォーマンス上の理由から、C ++ではなくCを使用する必要があります。C ++は怠惰な人向けです。

ダメダメダメ。パフォーマンスのため、Cの代わりにアセンブリを使用する必要があります。Cは怠惰な人向けです。

はい、冗談です。結合なしでより高速なプログラムを作成でき、結合なしでより少ないメモリを使用してプログラムを作成できます。しかし、多くの場合、開発時間はCPU時間とメモリよりも重要です。少しパフォーマンスをあきらめて、あなたの人生を楽しんでください。小さなパフォーマンスのために時間を無駄にしないでください。そして、彼に「あなたの場所からあなたのオフィスまでまっすぐな高速道路を作ってみませんか?」


1
私はこれまであなたのすべての答えを見てきましたが、それらはとても面白いです。今後もよろしくお願いします。それとも、どこであなたのブログを購読してもいいですか?
ジェリー

11

「これは技術的に正しい」-同様に、SQLデータベースは役に立たない:一​​連のCSVファイルを使用して同じ結果を得ることができ、それらをコードで相互に関連付けることができる場合に、SQLデータベースを使用する意味は何ですか?抽象化は怠惰な人々のためのものです。ハードウェア上でマシンコードのプログラミングに戻りましょう。;)

また、彼の主張は、最も複雑な場合を除いてすべて正しくありません。RDBMSは、JOINを高速化するために大幅に最適化されていますリレーショナルデータベース管理システムですね。


2
+1「...技術的に正しい」という語句は、OPが前の文ではunnecessaryなく語句に使用していた場合により効果的uselessでした。ジョインが役に立たないと言うことは、技術的な考慮を必要としないため、明らかに真実ではありません。いずれにせよ、OPのとのRDBMSのポイントの同僚の誤解はsandly珍しいことではありません。stackoverflow.com/q/5575682/47550
ポールSasik

7

私が最後に働いた会社もSQL結合を使用していませんでした。代わりに、この作業を水平方向にスケーリングするように設計されたアプリケーションレイヤーに移動しました。この設計の根拠は、データベース層での作業を回避することです。通常、ボトルネックになるのはデータベースです。データベースよりもアプリケーション層の複製が簡単です。他の理由が考えられます。しかし、これは私が今思い出すことができるものです。

はい、アプリケーション層で行われる結合は、データベースで行われる結合と比較して非効率的であることに同意します。より多くのネットワーク通信も。

SQL結合を回避することについて、私は固い立場に立っていないことに注意してください。


まあ、それはあなたの特定のケースでのJOINに対する合理的な議論のように聞こえます。私はFBエンジニアリングが彼らのブログに同様の何かを投稿したことを覚えています-スケールアウトも彼らの主要な優先事項でした。悲しいかな、これを行う必要があるプログラマはごくわずかですが、多くの人が「OMG Facebookもこれを行うため」と考えています;)
Piskvorが建物を去った

わかりました。データベースサーバーに過負荷をかけるのに十分なトラフィックがあるエンタープライズソリューションでは、これは検討に値するかもしれませんが、レポートストアドプロシージャまたはスケジュールされたバックアップによってパフォーマンスが低下する可能性が高くなります。データベースは、特に支援する必要がある場合に、結合に優れています
Jodrell

@ジョドレル:はい、彼らは結合が得意です。繰り返しますが、より多くのパワーを得るために結合の優雅さを落とさなければならない場合があります。私はそのような状況に遭遇しました。考えられるすべての解決策を試しましたが、実際には、結合しない解決策がその特定の状況で最速でした。いいえ、その特定のサーバーでは他に何も実行されていませんでした。ストアドプロシージャを使用していない場合、速度を低下させることはできません;)
Piskvorが建物を去った

5

結合なしで、注文アイテムを注文にどのように関連付けますか?これが、リレーショナルデータベース管理システムの要点です。結合がない場合、リレーショナルデータは存在せず、テキストファイルを使用してデータを処理することもできます。

彼は概念を理解していないように聞こえるので、彼はそれらが役に立たないように見せようとしています。彼は、excelがデータベースアプリケーションであると考える人と同じタイプです。彼をばかにして、データベースについてもっと読むように言ってください。複数の接続を作成し、データをプルし、C#を介してデータをマージすることは、間違った方法です。


5

「SQLでの結合は役に立たない」というステートメントのロジックがわかりません。作業する前にデータをフィルタリングして制限することは役に立ちますか?あなたが他の回答者であると述べたように、これはデータベースエンジンが行うことであり、彼らが得意なものでなければなりません。

おそらく、怠惰なプログラマーは、彼らが慣れ親しんでいる技術にこだわり、非技術的な理由で他の可能性を回避するでしょう。

私が決めるのはあなたにお任せします。


5

例を考えてみましょう:請求書レコードを含むテーブルと、請求書項目レコードを含む関連テーブル。クライアントの疑似コードを考えてみましょう:

for each (invoice in invoices)
    let invoiceLines = FindLinesFor(invoice)
...

それぞれ10行の100,000の請求書がある場合、このコードは100万のテーブルから10の請求書行を検索し、100,000回実行します。テーブルサイズが大きくなると、選択操作の数が増加し、各選択操作のコストが増加します。

コンピュータが高速であるため、数千レコード以下の場合、2つのアプローチのパフォーマンスの違いに気付かない場合があります。コストの増加は線形を超えるため、レコード数が(たとえば、数百万に)増加すると、違いに気付き始め、データセットのサイズが大きくなるにつれて違いが許容できなくなります。

ただし、結合。テーブルのインデックスを使用し、2つのデータセットをマージします。これは、ランダムにN回アクセスするのではなく、2番目のテーブルを効果的に1回スキャンすることを意味します。外部キーが定義されている場合、データベースには、内部に保存されている関連レコード間のリンクがすでにあります。

これを自分で行うことを想像してみてください。生徒のアルファベット順のリストとすべての生徒の成績レポートが記載されたノート(クラスごとに1ページ)があります。ノートブックは、リストと同じ順序で、生徒の名前順にソートされています。どのように進めますか?

  1. リストから名前を読み取ります。
  2. ノートブックを開きます。
  3. 生徒の名前を見つけます。
  4. 生徒の成績を読み、次の生徒または最後のページに到達するまでページをめくります。
  5. ノートブックを閉じます。
  6. 繰り返す。

または:

  1. ノートブックを最初のページに開きます。
  2. リストから名前を読み取ります。
  3. ノートブックからその名前の評点を読み取ります。
  4. 最後に到達するまで手順2〜3を繰り返します
  5. ノートブックを閉じます。

5

もっと上手に書ける」という古典的なケースのように聞こえます。言い換えれば、彼は首の痛みのようなもの(SQLで一連の結合を作成)を見つけて、「それをもっと上手に書いて、パフォーマンスを向上させることができると確信しています」と言っています。OracleまたはSQL Serverの最適化コードに精通している一般的な人よりも、a)より賢く、b)より教育を受けているかどうかを彼に尋ねる必要があります。彼はそうではありません。


3

彼は間違いなく間違っている。C#やJavaなどの言語内でのデータ操作には明確な長所がありますが、SQL自体の性質により、結合はデータベースで最も高速です。

SQLはデータに関する詳細な統計を保持し、インデックスを正しく作成した場合、数百万のレコードを非常にすばやく見つけることができます。データベースレベルで結合を実行できるのに、なぜすべてのデータをC#にドラッグして結合を実行するのでしょうか。

反復的に何かを行う必要がある場合は、C#を使用するプロが関与します。行ごとに関数を実行する必要がある場合は、C#内で実行する方が高速です。そうでない場合、データの結合はDBで最適化されます。


3

クエリの分解とコードでの結合の方が高速である場合に遭遇したと言います。そうは言っても、私がしなければならなかったのは、MySQLの特定のバージョン1つだけでした。それ以外の場合、データベースはおそらく高速になります(クエリを最適化する必要があるかもしれませんが、それでも高速です)。


3

私は彼がデータベースが何のために使われるべきかについて限られた見解を持っているのではないかと思います。パフォーマンスを最大化する1つの方法は、データベース全体をメモリに読み込むことです。この状況では、パフォーマンスが向上する可能性があり、メモリを効率化するために結合を実行したい場合があります。ただし、これは実際にはデータベースのIMHOとしてデータベースを使用しているわけではありません。


3
ほとんどのデータベースエンジンは、とにかく舞台裏でこれを行います。MySQLなどでは、純粋にメモリ内のテーブル(MEMORYエンジン)を作成できます。データベースなしでデータベース機能を再実装することは、通常、NIHの深刻なケースの兆候です;)
Piskvorは、

@phoog:Not Invented Here- 言い換えれば、「私はそれを考えていなかったので、存在しません」。このため、多くの四角い車輪が再発明されました。(そして、はい、時々ホイールを再発明することは有用です。例えば、レーシングカーを作っている場合。「単に」という理由で再発明することで、より良いホイールが得られる可能性は低くなります)
Piskvorが建物を去った

つまり「作れなかったのでゴミだ」と。これは、「私はテストしていないので、自分の目的に適さない可能性がある」という点でのみ、真実があります。そのため、判断する前にテストしてください。
Peter Lawrey、2011

@Piskvor:必ずしもそうとは限りません。データベースはそれが実行されているシステムのメモリのみを使用できますが、アプリケーションはアプリケーションサーバーのメモリを使用できます。言い換えると、データベースが専用ホスト上にある場合、そのキャッシュにアクセスするには依然としてネットワーク帯域幅が必要であり、ネットワーク遅延の影響を受けますが、アプリケーションが保持するキャッシュは、メモリアクセスの低遅延の速度でクエリを実行できます。
メリトン

2

いいえ、その場限りのC#/ Javaのデータベースコードで結合が最適化されているだけではありません。しかし、通常はいくつかのフィルタリング手法を適用でき、さらに優れたパフォーマンスが得られます。


2

彼は間違っています、結合は有能なプログラマが使用するものです。彼の提案した方法がより効率的であるいくつかの限られたケースがあるかもしれません(そして、私はおそらくDocumantデータベースを使用しているでしょう)ですが、あなたが何らかの適切な量のデータを持っているなら、私はそれを見ることができません。たとえば、次のクエリを見てください。

select t1.field1 
from table1 t1
join table2 t2 
    on t1.id = t2.id
where t1.field2 = 'test'

table1に1000万レコード、table2に100万レコードあるとします。表1の900万件のレコードがwhere句に一致するとします。それらのうち15個だけがtable2にもあると想定します。このsqlステートメントを実行できます。このSQLステートメントは、適切にインデックスが作成されるとミリ秒かかり、1列のデータのみでネットワーク全体に15レコードを返します。または、2列のデータを含む1000万レコードを送信し、1列のデータを含む別の100万レコードをネットワーク経由で個別に送信し、それらをWebサーバーで結合することができます。

またはもちろん、常に大量のデータと継続的に変化するデータがある場合、データベースのコンテンツ全体を常にWebサーバーに保持することもできます。リレーショナルデータベースの品質が必要ない場合は、使用しないでください。ただし、使用する場合は、正しく使用してください。


2

この議論は、ソフトウェア開発者としてのキャリアの中でよく耳にしました。それが述べられているほとんどいつも、主張をしている人はリレーショナルデータベースシステム、それらがどのように機能するか、そしてそのようなシステムがどう使われるべきであるかについてあまり知識を持っていませんでした。

はい、正しく使用しないと、結合は役に立たないか、さらには危険であるように見えます。しかし、正しい方法で使用すると、データベース実装が最適化を実行し、開発者が正しい結果を最も効率的に取得するのを「助ける」ための多くの可能性があります。

JOINデータベースを使用して、データの各部分が相互に関連していると予想される方法をデータベースに通知することを忘れないでください。したがって、データベースに、実行しようとしていることに関するより多くの情報を提供し、必要に応じてデータベースを適合させることができます。

だから答えは間違いなく:いいえ、JOINSまったく役に立たない!


0

これは、アプリケーションで頻繁に使用されない1つの場合にのみ「技術的に当てはまる」(結合内のすべてのテーブルのすべての行がクエリによって返される場合)。ほとんどのクエリでは、各テーブルの行の一部のみが返されます。データベースエンジンは、インデックスに格納された値を使用できるため、実際の行を読み取らずに、インデックスを使用して不要な行を排除することがよくあります。データベースエンジン自体はC、C ++などで記述されており、少なくとも開発者が記述したコードと同じくらい効率的です。


0

私が真剣に誤解していない限り、質問のロジックには非常に欠陥があります

AごとにBに20行ある場合、Aの1000行はBに20k行を意味します。マッピングを含む20k行の多対多テーブル "AB"がない限り、Bに100行はあり得ません。 。

そのため、100行のB行のうち20行が各A行にマップされるすべての情報を取得するには、ABもテーブル化します。したがって、これは次のいずれかになります。

  • 100、1000、20k行の3つの結果セットとクライアントのJOIN
  • 20k行の単一の結合されたA-AB-B結果セット

したがって、クライアントの "JOIN"は、データを調べるときに値を追加しません。それは悪い考えではありません。データベースから1つのオブジェクトを取得する場合は、オブジェクトを個別の結果セットに分割する方が理にかなっています。レポートタイプの呼び出しの場合は、ほぼ常に1つにまとめます。

いずれにせよ、この規模のクロスジョインはほとんど役に立ちません。それは悪い例です。

あなたはどこかに参加する必要があり、それがRDBMSが得意なことです。私は、もっと上手くできると思っているクライアントコードモンキーとは協力したくありません。

結果論:

クライアントに参加するには、DataTables(.net内)などの永続オブジェクトが必要です。フラット化された結果セットが1つある場合は、DataReaderなどの軽量なものを介して消費できます。大量=データベースのJOINを回避するために使用される大量のクライアントリソース。

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