Sql server 查询执行计划(Sql Server 2000)中意外估计的行

Sql server 查询执行计划(Sql Server 2000)中意外估计的行,sql-server,performance,sql-execution-plan,Sql Server,Performance,Sql Execution Plan,如果我运行这个查询 select user from largetable where largetable.user = 1155 (注意,我查询用户只是为了将其简化为最简单的情况) 看看执行计划,计划了索引查找[largetable在用户上有一个索引],估计的行是正确的 但如果我这样做了 select user from largetable where largetable.user = (select user from users where externalid = 100)

如果我运行这个查询

select user from largetable where largetable.user = 1155 
(注意,我查询用户只是为了将其简化为最简单的情况)

看看执行计划,计划了索引查找[largetable在用户上有一个索引],估计的行是正确的

但如果我这样做了

select user from largetable where largetable.user = (select user from users where externalid = 100)
[子查询的结果是单值1155,就像上面我硬编码时一样]

查询优化器估计结果中有117000行。largetable中约有6000000行,用户中约有1700行。当然,当我运行查询时,我会返回正确的29行,尽管估计的行数很大

我用fullscan更新了相关索引中两个表的统计数据,当我查看统计数据时,它们似乎是正确的

需要注意的是,对于任何给定的用户,largetable中的行不超过3000行

那么,为什么估计的执行计划会显示如此多的估计行呢?优化器是否应该知道,根据统计数据,它正在寻找一个包含29行对应行的结果,或者最多3000行,即使它不知道子查询将选择的用户?为什么会有这么大的估计?问题是,这个较大的估计值会影响较大查询中的另一个连接,以执行扫描而不是搜索。如果我用子查询运行较大的查询,需要1分钟40秒。如果使用1155硬编码运行,则需要2秒钟。这对我来说很不寻常

谢谢

克里斯,你试过这个吗

SELECT lt.user
FROM Users u
     INNER JOIN largeTable lt
        ON u.User = lt.User
WHERE u.externalId = 100
请看这个:

你试过这个吗

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

请看这一点:

优化器尽其所能,但统计数据和行数估计仅限于此(如您所见)

我假设,如果没有子查询,您更复杂的查询很难重写为联接。如果可以,你应该先尝试一下


如果做不到这一点,那么现在是时候利用关于数据性质的额外知识来帮助优化器进行优化了。具体查看
索引
提示中的
forceseek
选项。请注意,如果您的数据稍后更改,这可能会很糟糕,因此请注意。

优化器会尽其所能,但统计数据和行数估计仅限于此(如您所见)

我假设,如果没有子查询,您更复杂的查询很难重写为联接。如果可以,你应该先尝试一下


如果做不到这一点,那么现在是时候利用关于数据性质的额外知识来帮助优化器进行优化了。具体查看
索引
提示中的
forceseek
选项。请注意,如果您的数据以后发生更改,这可能会很糟糕,因此请注意。

forceseek
仅限2008年。行动是在2000年。啊,我没意识到。不久前迁移了2000,所以我没有任何东西可以测试它:(谢谢Donnie;当我重写为联接时,我得到了同样的效果。我不认为SS2000有forceseek,但是,我会检查一下。。哎呀,看有人同意我的看法。我修复了这个问题,只做了一个addnl查询来获得子查询结果,然后进入主查询。但是,我真的很奇怪为什么优化器会这样做!@Querylous-第2页“Inside Microsoft SQL Server 2005:Query Tuning and Optimization”中的第26条如果您有副本,则会特别提到此方法…
forceseek
仅限2008年。OP是2000年版。啊,我没有意识到这一点。不久前已迁移到2000年版,因此我没有任何可测试的内容:(谢谢Donnie;当我重写为联接时,我得到了同样的效果。我不认为SS2000有forceseek,但是,我会检查一下。。哎呀,看有人同意我的看法。我修复了这个问题,只做了一个addnl查询来获得子查询结果,然后进入主查询。但是,我真的很奇怪为什么优化器会这样做!@Querylous-第2页“Inside Microsoft SQL Server 2005:Query Tuning and Optimization”(内部Microsoft SQL Server 2005:Query Tuning and Optimization)中的第26条如果您有副本,则会特别提到此方法……是的,并且,作为联接重写也有同样的问题!是的,并且作为联接重写也有同样的问题!