同僚との最近の会話では、この問題についてさまざまな見解が生まれました。SOのメンバーはどうですか?
スケーラビリティの概念でさえ、非常に多くの異なる方法や文脈で捉えることができますが、これが話題になったときの議論の一部でした. スケーラビリティが実際に意味するものについて、誰もが異なる見方をしているように見えました。ここでもさまざまなテイクが見られることに興味があります。実際、私はその概念のためだけに質問を投稿しました。
同僚との最近の会話では、この問題についてさまざまな見解が生まれました。SOのメンバーはどうですか?
スケーラビリティの概念でさえ、非常に多くの異なる方法や文脈で捉えることができますが、これが話題になったときの議論の一部でした. スケーラビリティが実際に意味するものについて、誰もが異なる見方をしているように見えました。ここでもさまざまなテイクが見られることに興味があります。実際、私はその概念のためだけに質問を投稿しました。
私たちが行ったテストでは、オブジェクトへのLINQ(ForEach)は、foreachループの約2倍の速度でした。
LINQ to SQL(MS SQLデータベース)は、データリーダーを使用した直接クエリよりもほぼ10倍遅く、ほとんどの場合、式ツリーからSQLを作成します(したがって、CPUにバインドされ、データベースはアイドリング状態になります)。これを回避するには、次のことを行う必要があります。コンパイルされたクエリを使用します。
詳細については、こちらをご覧ください。投稿のほとんどの情報は、.NET3.5SP1でも引き続き有効です。
確認する最善の方法はベンチマークを作成することだと思いますが、私の意見では、LINQ には同様のコードを手書きする場合にはない最適化の可能性があります。それらをどれだけうまく活用しているかはまだわかりません。
LINQ を使用すると、生成方法ではなく、必要なものを表現できます。明らかな利点の 1 つは、LINQ が自動的に並列化できることです ( PLINQを参照)。
LINQ のもう 1 つの利点は、レイジーであるため、必要に応じてコレクションから描画して計算を実行できることです。同等のものを手作業でコーディングすることもできますが、LINQ で正しく行う方がはるかに簡単な場合があります。
この質問は、「コレクションはどれくらいスケーラブルですか?」という質問に少し似ています。
オブジェクトへの LINQ について話しましょう。一般的に言えば、ほとんどの実装がIEnumerable<T>
基になるコレクション内のすべての項目を反復処理するという点で、LINQ はスケーリングが不十分になる可能性が非常に高くなります。List<Foo>
1,000 万個のアイテムを含む を作成し、次のようなものを作成します。
var list = from Foo f in fooList
where f.Value = "Bar"
select f;
遅くなります。しかし、それは LINQ のせいではありません。1,000 万のアイテムのリストを作成したのはあなたです。
これは、LINQ が存在しない場合と同じ方法で対処します。検索スペースを削減するのに役立つ Dictionaries や SortedLists などを作成します。
LINQ は、クエリの遅延実行によってスケーラビリティを向上させることができます(つまり、スケーラビリティを実現しやすくします)。リストを作成し、それを新しいリストにフィルター処理し、それを新しいリストにフィルター処理するなどの単純なメソッドを、一連の LINQ クエリに置き換えることができます。
var list1 = from Foo f in fooList where f.Value1 = "Bar" select f;
var list2 = from Foo f in list1 where f.Value2 = "Baz" select f;
var list3 = from Foo f in list2 where f.Value3 = "Bat" select f;
これらはすべて、最終的なリストを反復処理する必要がある場合 (およびその場合) に、基になるコレクションを介して 1 回のパスで実行されます。繰り返しますが、これは何も新しいことではありません。もし LINQ がなかったら、単純なメソッドを同じことをするメソッドに置き換えることになるでしょう。しかし、LINQ を使用すると、はるかに簡単になります。
私の意見では、LINQは、スケーラビリティに対処するためではなく、開発の観点から物事を単純化することを目的としています。
実際、LINQを使用すると、多くの複雑な問題を隠蔽することで非常に簡単になり、無責任に使用すると、スケーラビリティの問題が発生する可能性があります。
他の回答にも例がたくさんありますが、最も重要な例は次のとおりです。
オブジェクトコレクションをクエリしている場合、そのサイズを無視することはできません。おそらく、LINQを使用してモデルでそれを行うと、クエリするオブジェクトがいくつかある場合は良さそうに聞こえます...しかし、サイズが大きくなるにつれて、クエリはモデルではなくデータベースで行われる必要があることが明らかになります。
LINQを使用してSQLを自動生成している場合、私が知る限り、たとえば、クエリをコンパイルする方法についてデータベースにヒントを与えることはできませんWITH (NOLOCK)
。テーブルのサイズが大きくなるにつれて、これらの問題に対処できることが不可欠です。
上記と同様ですが、より一般的かもしれません。DBでスケーラビリティの問題に対処する場合は、DBの動作を制御する必要があります。SQLにコンパイルされ、実行プランに再度コンパイルされる言語を使用すると、制御が不要になります。
データベーススキーマをよりスケーラブルにするために変更する必要があり、ストアドプロシージャがないためにコードがデータベーススキーマに強く結びついている場合はどうなりますか?
単純に見えますが、多くの苦労なしにLINQプロバイダーを変更することはできません。SQLServerのクエリは、オブジェクトのクエリやXMLのクエリと同じではありません。ただし、LINQは非常に似ています。スケーラビリティを念頭に置いて物事を行う方法を学ぶよりも簡単なので、後輩の開発者の何人かは「LINQスプリー」に参加することを期待しています。
結論として、LINQを使用してスケーラブルなコードを作成することは可能だと思いますが、それは慎重に使用することによってのみ可能です。キラーツールはなく、キラーコードのみです。
いくつかの点でのスケーラビリティに関する質問は、LINQ を何に使用しているかによって異なります。ビジネス アプリケーションでは、多くの SQL コマンドが実行されることはありません。それらは遅く、DBMS でコンパイルする必要があります。代わりに、多数のストアド プロシージャ コールが表示されます。これらは、LINQ でわずかに高速になります。
LINQ to SQL などは ADO.NET の上に構築されていることに注意してください。まったく異なる方法論などではありません。確かに、LINQ to XML は内部でさまざまな API を使用します。これはコンパイラによく似ています。人間が実行できる最適化の方が高速である可能性は常にありますが、ほとんどの場合、これらの API は、自分で記述したコードよりも高速でバグの少ないコードを生成できます。
スケール アウトに関しては、データを少し分散させたい場合や、SQL サーバー レプリケーションを使用する場合は、いつでも LINQ を Web サービスの背後に置くことができます。ADO.NET よりもスケーラブルであってはなりません。
スケーラビリティとパフォーマンスは 2 つの異なるものですが、関連するものです。パフォーマンスを測定したい場合は、1 つのボックスでサポートできるユーザー数 (たとえば) を確認する必要があります。スケーラビリティを測定するとき、別のボックスを追加して、元の量の 2 倍をサポートできるかどうかを確認しますか? 可能性は低く、処理能力を 75% しか追加できず、次の処理では元のユニットの 50% しか追加されないため、すぐにゼロになります。この速度でボックスをいくつ追加しても、サポートされるユーザー数が 2 倍になるのは幸運です。それがスケーラビリティです。
Linq モジュールがどのようにスケールするかは、おそらくデータベース、マシンの性能、データベースの設計、アプリケーションの設計に大きく依存します。
決定的な何かを明らかにすることになっているマイクロ ベンチマークをよく目にしますが、それらは問題全体の重要な穴のビューにすぎないため、実際には決して行われません。
古き良き 20/80 の例をここから引き出すことができます。おそらく 20% はツールに関するもので、80% はアプリケーションを構成するあらゆる種類の具体的なものに関するものです。
実際の例を探している場合は、stackoverflow が Linq を多用している場合は、この投稿/ポッドキャストを確認してください。
Linq to SQL フレームワークを使用してオブジェクトをオンデマンドでキャッシュおよびロードするには、料金がかかります。オブジェクトが要求に応じて自身の一部を遅延ロードできる場合、各オブジェクト内にデータ コンテキストへの参照が存在する可能性が非常に高くなります。ちなみに、データ コンテキストは、要求されたすべてのオブジェクトもキャッシュします。つまり、オブジェクトの 1 つを保持している場合 (キャッシュ内または後で使用するという理由だけで)、そのオブジェクトを保持するだけでなく、データ コンテキストによって要求されたすべてのオブジェクトを保持することになります。これらはまだ参照されているため、ガベージ コレクションは行われません。
すべてのオブジェクティブの寿命が短く、アプリケーションが新しい作業を行うたびに新しい DataContext を作成する場合、これは問題になりません。しかし、各オブジェクトに追加の負担がかかることを誰かが認識していないと、スケーラビリティの問題がどのように発生するかがわかります。
Linq は多くの点でスケーラブルです。
1 つの側面は、linq の背後にある仕様の実装です。これにより、別の言語 (Linq2Sql、Linq2Hibernate)、または map-reduce クラスター ( DryadLINQ )などの分散コンピューティング環境で、Expression をプロセス外で実行するように解釈できます。
もう 1 つの側面は、linq が言語に提供するセマンティクスです。プロバイダーが遅延読み込みをサポートしている場合、またはクエリを並列化または最適化できる場合 (PLINQ または i4o)、メモリ内のコレクションを埋めることなく、数十億のオブジェクトを反復処理できます。