小心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来关闭新的基数评估,使用老的基数评估。
启用跟踪标记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后出现了性能问题。例如:
参考资料:
http://dba.stackexchange.com/questions/95609/sql-server-performance-is-slow-when-migrated-from-sql-server-2012-to-sql-server
/article/4991240.html
其实当数据库的兼容级别为120的时候,默认使用新的基数评估。也就是说启用了新的基数评估,那么我们现在使用查询跟踪标记9481来关闭新的基数评估,使用老的基数评估。
DBCCTRACEON(9481,1);
GO
启用跟踪标记9481后,这个SQL语句的执行计划变了(可以对比图4),可以看到CardinalityEstimationModelVersion的值也变为了70。SQL语句一秒就执行完了。这个是因为基数评估出现了偏差导致了不合适的JOIN算法。
我们对比下面”图四:旧执行计划“,发现其实还是使用NestedLoops,只是外部循环表与内部循环表变了。
图四:旧执行计划
那么关于新的基数评估(CardinalityEstimator)特性,你想多了解一些这方面的知识,可以参考官方文档
对于基数评估,每个执行计划中的运算符都有评估值输入,这个值决定了优化器使用什么算法的操作符,同时也决定了最终的执行计划。所以如果评估出现偏差,会导致执行计划选择出现偏差,导致无法选出一个高效的执行计划。
评估出现偏差会出现以下结果:
如果评估过小:
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
参考资料:相关文章推荐
- Mongodb 笔记04 特殊索引和集合、聚合、应用程序设计
- Oracle redo 与 undo 区别
- mysql设置定时任务
- mysql设置定时任务
- 常见的数据库
- 2016 第一篇 之数据库
- 第四次实验:安装配置sqoop-1.4.6并与mySQL连接
- mysql 优化
- redis初步入门
- oracle 解锁用户和修改密码
- 邮件系统服务器搭建记录(五)(Postfix+Cyrus-sasl+Courier-authlib+Dovecot+ExtMail+MySQL)
- hibernate 与MYSQL 求两个字符串数组的交集
- oracle 11g 安装
- SQL SERVER使用ODBC 驱动建立的链接服务器调用存储过程时参数不能为NULL值
- 数据库重点知识总结
- 01@MySQL_Course_LabVIEW+MySQL程序开发
- [实战]MVC5+EF6+MySql企业网盘实战(26)——音乐列表
- 一则简单演示样例看Oracle的“无私”健壮性
- 数据库并发控制 你选乐观锁还是悲观锁?
- 随机抽取记录的sql语句