运行此查询的机器是在数据中心中运行的专用服务器。
AMD Opteron 1354 四核 2.20GHz 2GB RAM Windows Server 2008 x64(是的,我知道我只有 2GB 的 RAM,当项目上线时我将升级到 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);