当前位置:  开发笔记 > 编程语言 > 正文

查询250k行需要53秒

如何解决《查询250k行需要53秒》经验,为你挑选了1个好方法。

运行此查询的框是在数据中心中运行的专用服务器.

AMD Opteron 1354四核2.20GHz 2GB内存Windows Server 2008 x64(是的,我知道我只有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%,Membery是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

所有这三个查询都是即时的.

Exec计划第一次查询.
http://i43.tinypic.com/xp6gi1.png

Exec计划其他3个查询(按顺序).
http://i43.tinypic.com/30124bp.png
http://i44.tinypic.com/13yjml1.png
http://i43.tinypic.com/33uejf.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);

cdonner.. 13

尝试在Stories.LastActivityAt上添加索引.我认为执行计划中的聚簇索引扫描可能是由于排序造成的.

编辑:由于我的查询在瞬间返回,行只有几个字节长,但已经运行了5分钟,并且在我添加了2K varchar之后仍在继续,我认为Mitch有一个观点.它是无关紧要的数据量,但这可以在查询中修复.

尝试将join,sort和top(10)放在视图或嵌套查询中,然后再与故事表联接以获取所需的10行的其余数据.

像这样:

select * from 
(
    SELECT TOP(10) id, categoryID, userID
    FROM Stories
    ORDER BY Stories.LastActivityAt
) s
INNER JOIN Stories ON Stories.ID = s.id
INNER JOIN Categories ON Categories.ID = s.CategoryID
INNER JOIN Users ON Users.ID = s.UserID

如果你有LastActivityAt的索引,这应该运行得非常快.



1> cdonner..:

尝试在Stories.LastActivityAt上添加索引.我认为执行计划中的聚簇索引扫描可能是由于排序造成的.

编辑:由于我的查询在瞬间返回,行只有几个字节长,但已经运行了5分钟,并且在我添加了2K varchar之后仍在继续,我认为Mitch有一个观点.它是无关紧要的数据量,但这可以在查询中修复.

尝试将join,sort和top(10)放在视图或嵌套查询中,然后再与故事表联接以获取所需的10行的其余数据.

像这样:

select * from 
(
    SELECT TOP(10) id, categoryID, userID
    FROM Stories
    ORDER BY Stories.LastActivityAt
) s
INNER JOIN Stories ON Stories.ID = s.id
INNER JOIN Categories ON Categories.ID = s.CategoryID
INNER JOIN Users ON Users.ID = s.UserID

如果你有LastActivityAt的索引,这应该运行得非常快.

推荐阅读
wurtjq
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有