有人可以让我更好地了解兼容模式功能吗?它的行为与我预期的不同。
据我了解的兼容性模式,它是关于 SQL Server 各个版本之间某些语言结构的可用性和支持。
它不影响数据库引擎版本的内部工作。它将尝试阻止使用早期版本中尚不可用的功能和结构。
我刚刚在 SQL Server 2008 R2 中创建了一个兼容级别为 80 的新数据库。创建了一个带有单个 int 列的表并用几行填充它。
然后执行一个带有row_number()
函数的 select 语句。
我的想法是,由于 row_number 函数是在 2005 年才引入的,这会在兼容 80 模式下引发错误。
但令我惊讶的是,这很好用。然后,当然,只有在您“保存某些内容”时才会评估兼容规则。所以我为我的 row_number 语句创建了一个存储过程。
存储过程的创建很顺利,我可以完美地执行它并获得结果。
有人可以帮助我更好地理解兼容模式的工作原理吗?我的理解显然是有缺陷的。
从文档:
在我的解释中,兼容模式是关于行为和语法解析,而不是解析器说“嘿,你不能使用
ROW_NUMBER()
!”之类的东西。有时,较低的兼容性级别允许您继续使用不再受支持的语法,有时它会阻止您使用新的语法结构。该文档列出了几个明确的示例,但这里有一些演示:将内置函数作为函数参数传递
此代码适用于兼容级别 90+:
但在 80 中,它产生:
这里的具体问题是,在 80 中,您不允许将内置函数传递给函数。如果您想保持 80 兼容模式,可以通过以下方式解决此问题:
将表类型传递给表值函数
与上述类似,在使用 TVP 并尝试将其传递给表值函数时,您可能会遇到语法错误。这适用于现代兼容级别:
但是,将兼容级别更改为 80,并再次运行最后三行;您收到此错误消息:
除了升级兼容级别或以不同的方式获得结果之外,我并没有真正想到任何好的解决方法。
在 APPLY 中使用限定的列名
在 90 兼容模式及更高版本中,您可以毫无问题地执行此操作:
但是,在 80 兼容模式下,传递给函数的限定列会引发通用语法错误:
ORDER BY 恰好与列名匹配的别名
考虑这个查询:
在80兼容模式下,结果如下:
在90兼容模式下,结果大相径庭:
原因?
SELECT
在 80 兼容模式下,表前缀被完全忽略,因此它是按照列表中别名定义的表达式排序的。在较新的兼容性级别中,会考虑表前缀,因此 SQL Server 将实际使用表中的该列(如果找到的话)。如果ORDER BY
在表中未找到别名,则较新的兼容性级别不会容忍歧义。考虑这个例子:结果按
myname
80 中的表达式排序,因为表前缀再次被忽略,但在 90 中会生成以下错误消息:这在文档中也得到了解释:
ORDER BY SELECT 列表中没有的东西
在 90 兼容模式下,您不能这样做:
结果:
但是,在 80 中,您仍然可以使用这种语法。
旧的、讨厌的外连接
80 模式还允许您使用旧的、已弃用的外连接语法 (
*=/=*
):在 SQL Server 2008 / 2008 R2 中,如果您在 90 或更高版本中,您会收到以下详细消息:
在 SQL Server 2012 中,这根本不再是有效的语法,并产生以下结果:
当然,在 SQL Server 2012 中,您不能再使用兼容级别解决此问题,因为不再支持 80。如果您在 80 兼容模式下升级数据库(通过就地升级、分离/附加、备份/恢复、日志传送、镜像等),它将自动为您升级到 90。
没有 WITH 的表格提示
在 80 兼容模式下,您可以使用以下内容,将观察到表格提示:
在 90+ 中,这
NOLOCK
不再是表提示,而是别名。否则,这将起作用:但它没有:
现在,为了证明在第一个示例中未观察到在 90 兼容模式下的行为,请使用 AdventureWorks(确保它处于更高的兼容级别)并运行以下命令:
这个问题特别严重,因为行为发生变化而没有错误消息甚至错误。这也是升级顾问和其他工具甚至可能没有发现的东西,因为据它所知,这是一个表别名。
涉及新日期/时间类型的转换
SQL Server 2008 中引入的新日期/时间类型(例如
date
和)支持的范围比原来的和)datetime2
大得多。无论兼容级别如何,超出支持范围的值的显式转换都将失败,例如:datetime
smalldatetime
产量:
但是,隐式转换将在较新的兼容性级别中自行解决。例如,这将适用于 100+:
但在 80(以及 90)中,它会产生与上述类似的错误:
触发器中的冗余 FOR 子句
这是出现在这里的一个晦涩的场景。在 80 兼容模式下,这样会成功:
在 90 及更高的兼容性中,这不再解析,而是您收到以下错误消息:
枢轴/取消枢轴
某些形式的语法在 80 岁以下不起作用(但在 90 岁以上就可以正常工作):
这产生:
对于一些解决方法,包括
CROSS APPLY
,请参阅这些答案。新的内置功能
尝试在兼容级别 < 110 的数据库中使用新功能
TRY_CONVERT()
。在那里根本无法识别它们。结果:
推荐
仅在您确实需要时才使用 80 兼容模式。由于在 2008 R2 之后的下一个版本中将不再可用,所以你最不想做的就是在这个兼容级别编写代码,依赖你看到的行为,然后当你不能再有一大堆损坏时使用该兼容级别。要有远见,不要试图通过争取时间继续使用旧的、已弃用的语法将自己逼入绝境。
兼容性级别仅用于允许从早期版本的 SQL Server 进行受控迁移。Compat Level 90 不排除使用新功能,它只是意味着以与 SQL Server 2005 工作方式兼容的方式保留数据库的某些方面。
有关详细信息,请参阅http://msdn.microsoft.com/en-us/library/bb510680.aspx。