从我的使用EF核心的ASP.NET应用程序中,我得到了一个对数据库的查询,其中有相当多的连接(13)。当我执行它时,它会工作--但它需要25秒才能完成。
然而,当我在数据库选项中使用"Legacy Cardinality Estimation“时,执行是即时的。据我所知,基数估计是基于统计数据完成的,因此我执行了exec sp_updatestats
。虽然它曾经在相同的数据库(但不同的查询)上提供了帮助,但这一次它没有。
因此,我想到的第一个问题是:如何验证统计数据的正确性?如果是这样,基数估计器为什么会做出糟糕的选择?
或者更笼统地说:我如何在不求助于上述选项的情况下解决这个问题(打开一些遗留的东西听起来不太对)?
发布于 2019-03-15 17:54:10
检查索引rowcnt/rows是一个很好的开始。您通常可以在此处看到问题,尽管可以通过更新统计信息或获取最新的CU (累积更新)或SP (服务包)来修复它,即使这样,它也可能尚未修补。
我在2014年的sp2和sp3中遇到了这个问题,仅靠service packs无法修复基数估计器。您需要获取最新的累积更新。
declare
@table_name varchar(128) = 'TableName'
,@schema_name varchar(128) = 'dbo'
/* 2014 and after I believe */
select max(p.rows) rows from sys.tables t
inner join sys.indexes i on t.object_id = i.object_id
inner join sys.partitions p on t.object_id = p.object_id and p.index_id = i.index_id -- current-ish
where t.name = @table_name and schema_name(t.schema_id) = @schema_name
/* 2008 to 2012 I believe */
select max(i.rows)
from sys.tables t
inner join sys.sysindexes i on i.id = t.object_id -- the old dbo.sysindexes becomes a view
where t.name = @table_name and schema_name(t.schema_id) = @schema_name
/* 2000 and possibly earlier */
select max(i.rows)
from sys.tables t
inner join dbo.sysindexes i on i.id = t.object_id -- a real live table, still selectable
where t.name = @table_name and schema_name(t.schema_id) = @schema_name
发布于 2019-03-18 15:23:53
不幸的是,当涉及到CE时,一切都是相同的。你自己说的。25秒vs <1秒,并且两者使用相同的统计数据、更新与否、相同的索引、相同的查询等等。我做了很多关于CE选择的工作,(在统计,索引和所有标准的推荐操作之后)一个估计器可能工作得很好,另一个可能很差。并且这可以是在具有1个过滤器差异或2个不同查询的非常相同的查询中产生完全相等的结果。在大多数情况下,两者都表现良好或可以接受。然而,有时他们中的一个完全搞砸了。在这里,你必须使用传统的CE2012,或者让你的声明“CE2014友好”。
或者,如果您的语句在代码中有明确的标识,例如'mystatementA021‘,那么您可以保留自己的统计数据,并选择CE2012或2014。但这是一个更长的故事。
https://stackoverflow.com/questions/55187893
复制