2009-11-23 40 views
4

我有两个表与600K行之间的关系,我的第一个问题是,是很多的数据?它似乎并不像很多(中排,而不是字节为单位)什么是太多的SQL Server数据,我如何分析我的执行计划

我可以写一个这样的查询

SELECT EntityID, COUNT(*) 
FROM QueryMembership 
GROUP BY EntityID 

而且它现在的时间都完成,但是当我做到这一点。

SELECT EntityID, COUNT(*) 
FROM QueryMembership 
WHERE PersonID IN (SELECT PersonID FROM GetAcess(1)) 
GROUP BY EntityID 

该事情需要3-4秒才能完成,尽管刚刚返回约183行。 SELECT * FROM QueryMembership大约需要12-13秒。

我不明白的是,一旦我引入这个表值函数,像这样的过滤器会花费那么长时间。函数本身并不需要任何时间来返回它的结果,无论我将它写成CTE还是一些奇怪的子查询,结果都是一样的。

但是,如果推迟过滤器,通过将第一个选择的结果插入临时表#temp,然后使用GetAccess UDF,整个过程的速度将快三倍。

我真的很想在这个问题上提供一些深入的技术帮助。我应该在哪里开始寻找,以及我如何分析执行计划以确定发生了什么。

+1

不,600K行不是很多。在企业应用程序中拥有数百万行是非常普遍的。 – DOK 2009-11-23 16:25:04

+0

谈论6亿行 - 是的,那么你开始进入“大量数据”...... – 2009-11-23 16:25:59

+0

这就是我认为,至少有一些估计继续下去。 – 2009-11-23 19:02:38

回答

0
SELECT EntityID, COUNT(*) 
FROM QueryMembership 
WHERE PersonID IN (SELECT PersonID FROM GetAcess(1)) 
GROUP BY EntityID 

嵌入子查询是昂贵的。正如你所说的使用临时表是完美的替代解决方案。

1

600k行不是特别大的数量。但是,您已经到了服务器配置(磁盘,非SQL负载等)很重要的地步,所以如果您的服务器没有仔细组装在一起,您应该现在看看,而不是稍后。

分析执行计划是随着时间的推移而逐渐增加的事情之一。 “Inside SQL Server”这本书对于学习内部工作是如何工作的非常好,这有助于引导你进行一些优化。

我个人会尝试重写上述查询作为连接,IN往往表现不如您希望的那样。喜欢的东西:

SELECT 
    EntityID, 
    COUNT(*) 
FROM 
    QueryMembership q 
    join GetAccess(1) a on a.PersonID = q.PersonID 
GROUP BY 
    EntityID 
+0

不幸的是,JOIN和其他一切一样慢。唯一更快的是临时表方法,我不知道为什么。 – 2009-11-23 19:06:16

0

我怀疑你减速的原因可能是类似于在此quesiton:

how to structure an index for group by in Sql Server

执行计划会回答这个问题,为什么第二个查询速度慢,但我怀疑这会是因为SQL Server可以使用索引(如COUNTMAX)使用相对廉价的查找聚集函数某些指数的操作。

但是,如果组合筛选器和组,则SQL服务器不能再使用此技巧,并且必须基于筛选结果集来评估COUNTMAX的值,从而导致查找费用过高。

600k行是一个相当合理的/小的表大小,但是它的大小足以使表扫描或RDI查找对表的大部分开始变得昂贵。

我很想看看执行计划,以了解发生了什么。