您的位置:首页 > 数据库

小心SQL SERVER 2014新特性——基数评估引起一些性能问题

2016-01-10 11:32 375 查看
在前阵子写的一篇博文“SQLSERVER2014下IFEXITS居然引起执行计划变更的案例分享”里介绍了数据库从SQLSERVER2005升级到SQLSERVER2014后,发现一个SQL出现性能问题,当时分析后发现执行计划变了,导致SQL出现了性能问题。但是没有彻底搞清楚为什么出现这种情况。当时看到ActualNumberofRows与EstimatedNumberofRows之间的偏差较大(统计信息是最新的),以为是优化器的Bug造成的。其实罪魁祸首是SQLSERVER2014新特性——基数评估(CardinalityEstimator)所引起的。IFEXISTS完全成了我这个标题党的替罪羊(罪过罪过)。下面我再就这个问题展开做一次分析。查看该SQL语句的实际执行计划,在属性里面我们可以看到CardinalityEstimationModelVersion的值为120,120表示这是新的基数评估,70就是老的基数评估

其实当数据库的兼容级别为120的时候,默认使用新的基数评估。也就是说启用了新的基数评估,那么我们现在使用查询跟踪标记9481来关闭新的基数评估,使用老的基数评估。

DBCCTRACEON(9481,1);
GO

启用跟踪标记9481后,这个SQL语句的执行计划变了(可以对比图4),可以看到CardinalityEstimationModelVersion的值也变为了70。SQL语句一秒就执行完了。这个是因为基数评估出现了偏差导致了不合适的JOIN算法。






我们对比下面”图四:旧执行计划“,发现其实还是使用NestedLoops,只是外部循环表与内部循环表变了。
图四:旧执行计划




那么关于新的基数评估(CardinalityEstimator)特性,你想多了解一些这方面的知识,可以参考官方文档OptimizingYourQueryPlanswiththeSQLServer2014CardinalityEstimator。中文翻译版本可以参考SQLServer2014新特性——基数评估(白皮书阅读笔记)。下面是官方文档关于基数评估出现偏差可能会造成的一些后果:
对于基数评估,每个执行计划中的运算符都有评估值输入,这个值决定了优化器使用什么算法的操作符,同时也决定了最终的执行计划。所以如果评估出现偏差,会导致执行计划选择出现偏差,导致无法选出一个高效的执行计划。
评估出现偏差会出现以下结果:
如果评估过小:
1.原本可以使用并行计划更加有效的,现在使用串行计划
2.不合适的join算法
3.不合适的索引选择,和索引访问方法
如果评估过大:
1.原本使用串行计划更加有效,现在使用并行计划
2.不合适的join算法
3.不合适的索引选择,和索引访问方法
4.过多的内存分配
5.内存浪费和没必要的并发
上面这段对应的英文资料如下所示(英语原文作参考,这才是原汁原味的信息):
Theindividualoperatorcostmodelsreceivetheestimatesasinput.Theestimatesareamajorfactorindecidingwhichphysicaloperatoralgorithmsandplanshapes(suchasjoinorders)arechosen.Theyalsodeterminethefinalqueryplanthatexecutes.Giventhesecriticalplanchoices,whenthecardinalityestimationprocesscontainsasignificantlyskewedassumption,thiscanleadtoaninefficientplanchoice.Thiscan,inturn,resultindegradedperformance.

Underestimatingrowscanleadtomemoryspillstodisk,forexample,wherenotenoughmemorywasrequestedforsortorhashoperations.Underestimatingrowscanalsoresultin:

Theselectionofserialplanwhenparallelismwouldhavebeenmoreoptimal.

Inappropriatejoinstrategies.

Inefficientindexselectionandnavigationstrategies.

Inversely,overestimatingrowscanleadto:

Selectionofaparallelplanwhenaserialplanmightbemoreoptimal.

Inappropriatejoinstrategyselection.

Inefficientindexnavigationstrategies(scanversusseek).

Inflatedmemorygrants.

Wastedmemoryandunnecessarilythrottledconcurrency.

Improvingtheaccuracyofrowestimatescanimprovethequalityofthequeryexecutionplanand,asaresult,improvetheperformanceofthequery.

.csharpcode,.csharpcodepre
{
font-size:small;
color:black;
font-family:consolas,"CourierNew",courier,monospace;
background-color:#ffffff;
/*white-space:pre;*/
}
.csharpcodepre{margin:0em;}
.csharpcode.rem{color:#008000;}
.csharpcode.kwrd{color:#0000ff;}
.csharpcode.str{color:#006080;}
.csharpcode.op{color:#0000c0;}
.csharpcode.preproc{color:#cc6633;}
.csharpcode.asp{background-color:#ffff00;}
.csharpcode.html{color:#800000;}
.csharpcode.attr{color:#ff0000;}
.csharpcode.alt
{
background-color:#f4f4f4;
width:100%;
margin:0em;
}
.csharpcode.lnum{color:#606060;}

其实关于SQLSERVER2014这个新的基数评估(CardinalityEstimator)特性,确实造成了不少SQL出现性能问题。我们数据库升级到SQLSERVER2014后,被这个新特性坑惨了,由于没有选择最优的执行计划,导致一些SQL出现严重的性能问题,也间接导致了SQL之间的阻塞(block)急剧上升。开发人员和我都在救火队员的角色中疲于奔命。最后我不得不采取将数据库的兼容基本从120降为110。从而立马解决了这个问题。另外从我搜索的一些资料看,SQLSERVER2014这个新的基数评估(CardinalityEstimator)这个新特性确实还有很多不完善的地方。因为也有不少人都发现升级到SQLServer2014后出现了性能问题。例如:

MSSQLServerCPUloadgoesupdramaticallywhenturningon2014featuresbysettingcompatibilitylevel

QueryisslowinSQLServer2014,fastinSQLServer2012

参考资料:
http://dba.stackexchange.com/questions/95609/sql-server-performance-is-slow-when-migrated-from-sql-server-2012-to-sql-server
/article/4991240.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: