2010-12-01 65 views
1

如果我运行此查询意外的估计行

select user from largetable where largetable.user = 1155 

(请注意,我查询用户只是将这一数字减少到最简单的情况下)

再看看执行计划,索引查找计划[largetable对用户的索引],估计行是正确的29

但如果我这样做

select user from largetable where largetable.user = (select user from users where externalid = 100) 

[当我硬编码时,子查询的结果是单个值1155就像上面一样]

查询优化器估计结果中有117,000行。大表中约有6,000,000行,用户有1700行。当我运行查询的时候,尽管估计的行数很大,我仍然可以找回正确的29行。

我已经在相关索引的两个表上使用fullscan更新了统计数据,当我查看统计数据时,他们看起来是正确的。

值得注意的是,对于任何给定的用户,大表中不超过3,000行。

那么,为什么估计执行计划会显示如此大量的估计行?优化器不应该根据统计信息知道它正在查找具有29个相应行的结果,或者最多3,000行,即使它不知道子查询将选择哪个用户?为何这个巨大的估计?问题是,这个大的估计会影响另一个更大的查询中的连接,而不是查找。如果我用子查询运行较大的查询,则需要1分40秒。如果使用1155硬编码运行,则需要2秒。这是非常不寻常的,我...

感谢,

克里斯

回答

0

你试试这个?

SELECT lt.user 
FROM Users u 
    INNER JOIN largeTable lt 
     ON u.User = lt.User 
WHERE u.externalId = 100 

请看到这一点:subqueries-vs-joins

+1

是的,并且作为连接重写有同样的问题! – Querylous 2010-12-02 15:39:38

1

优化器最好是可以的,但统计和行数的估计只能走这么远(如你所看到的)。

我假设你的更复杂的查询不能轻易被重写为没有子查询的连接。如果可以,你应该首先尝试。

如果没有,那么您应该使用关于数据性质的其他知识来帮助优化器hints。请特别注意index提示中的forceseek选项。请注意,如果稍后您的数据发生更改,这可能会很糟糕,因此请注意。

+0

`forceseek`仅限2008年。该OP是在2000年。 – 2010-12-01 15:40:27