このクエリが実行されているボックスは、データセンターで実行されている専用サーバーです。
AMD Opteron 1354 クアッドコア 2.20GHz 2GB の RAM Windows Server 2008 x64 (はい、RAM が 2GB しかないことはわかっています。プロジェクトが稼働したら 8GB にアップグレードします)。
そこで、テーブルに 250,000 のダミー行を作成して、LINQ to SQL が生成するいくつかのクエリを実際にストレス テストし、それらがそれほどひどいものではないことを確認しました。
インデックスを使用してこのクエリを17秒に短縮しましたが、この回答のために最初から最後まで削除しました。インデックスのみが主キーです。
Stories table --
[ID] [int] IDENTITY(1,1) NOT NULL,
[UserID] [int] NOT NULL,
[CategoryID] [int] NOT NULL,
[VoteCount] [int] NOT NULL,
[CommentCount] [int] NOT NULL,
[Title] [nvarchar](96) NOT NULL,
[Description] [nvarchar](1024) NOT NULL,
[CreatedAt] [datetime] NOT NULL,
[UniqueName] [nvarchar](96) NOT NULL,
[Url] [nvarchar](512) NOT NULL,
[LastActivityAt] [datetime] NOT NULL,
Categories table --
[ID] [int] IDENTITY(1,1) NOT NULL,
[ShortName] [nvarchar](8) NOT NULL,
[Name] [nvarchar](64) NOT NULL,
Users table --
[ID] [int] IDENTITY(1,1) NOT NULL,
[Username] [nvarchar](32) NOT NULL,
[Password] [nvarchar](64) NOT NULL,
[Email] [nvarchar](320) NOT NULL,
[CreatedAt] [datetime] NOT NULL,
[LastActivityAt] [datetime] NOT NULL,
現在、データベースには 1 人のユーザー、1 つのカテゴリ、250,000 のストーリーがあり、このクエリを実行しようとしました。
SELECT TOP(10) *
FROM Stories
INNER JOIN Categories ON Categories.ID = Stories.CategoryID
INNER JOIN Users ON Users.ID = Stories.UserID
ORDER BY Stories.LastActivityAt
クエリの実行に 52 秒かかり、CPU 使用率は 2 ~ 3% で推移します。メンバーは 1.1GB、900MB の空き容量がありますが、ディスクの使用率は制御不能のようです。@ 100MB/秒で、その 2/3 が tempdb.mdf に書き込まれ、残りが tempdb.mdf から読み取られます。
さて、興味深い部分は...
SELECT TOP(10) *
FROM Stories
INNER JOIN Categories ON Categories.ID = Stories.CategoryID
INNER JOIN Users ON Users.ID = Stories.UserID
SELECT TOP(10) *
FROM Stories
INNER JOIN Users ON Users.ID = Stories.UserID
ORDER BY Stories.LastActivityAt
SELECT TOP(10) *
FROM Stories
INNER JOIN Categories ON Categories.ID = Stories.CategoryID
ORDER BY Stories.LastActivityAt
これら 3 つのクエリはすべて、ほぼ瞬時に実行されます。
最初のクエリの実行計画。
http://i43.tinypic.com/xp6gi1.png
他の 3 つのクエリの実行計画 (順番)。
http://i43.tinypic.com/30124bp.png
http://i44.tinypic.com/13yjml1.png
http://i43.tinypic.com/33ue7fb.png
どんな助けでも大歓迎です。
インデックスを追加した後にプランを実行します (再び 17 秒まで短縮)。
http://i39.tinypic.com/2008ytx.png
皆さんからたくさんの有益なフィードバックをいただきました。ありがとうございます。新しい角度から試してみました。必要なストーリーをクエリしてから、別のクエリでカテゴリとユーザーを取得し、3 つのクエリで 250 ミリ秒しかかかりませんでした...問題はわかりませんが、問題が解決した場合は 250 ミリ秒で当分の間それに固執します。これをテストするために使用したコードは次のとおりです。
DBDataContext db = new DBDataContext();
Console.ReadLine();
Stopwatch sw = Stopwatch.StartNew();
var stories = db.Stories.OrderBy(s => s.LastActivityAt).Take(10).ToList();
var storyIDs = stories.Select(c => c.ID);
var categories = db.Categories.Where(c => storyIDs.Contains(c.ID)).ToList();
var users = db.Users.Where(u => storyIDs.Contains(u.ID)).ToList();
sw.Stop();
Console.WriteLine(sw.ElapsedMilliseconds);