到目前为止,所有版本的SQL Server都会将T-SQL编写的存储过程编译成中间语言的形式,然后再进行解释。在SQL Server 2014中,我们现在拥有了一个将存储过程一直向下编译成机器码然后再使用的选项。
本机编译的查询仅能用于内存优化表。如果你还需要访问传统表,那么你必须使用解释执行的查询。这意味着你不能使用内存优化表不支持的数据类型。
为了换取性能,本机编译的查询在灵活性方面有很大的限制。不出所料的,你不能使用表自身并不支持的变量数据类型。你也不能使用废弃的技术,例如游标。
更令人惊讶的是不支持的标准操作。这些内容多的让人难以概括,所以我们把完整列表展示了出来。
类型 |
功能 |
决议 |
功能 |
表值参数 |
本机编译的存储过程的参数不能使用表类型。使用标量数据类型替代。 |
功能 |
内联表变量 |
声明变量时表类型不能被声明为内联的。必须使用CREATE TYPE声明显式地声明表类型。 |
功能 |
游标 |
在本机编译的存储过程上或者其内部并不支持游标。 ·从客户端执行存储过程的时候需要使用RPC而不是游标API。在ODBC中要避免使用Transact-SQL语句EXECUTE,相反的要直接指定存储过程的名字。 ·从一个Transact-SQL批处理命令或者从另外的存储过程中执行存储过程的时候,要避免在本机编译的存储过程中使用游标。 ·创建一个本机编译的存储过程的时候,要使用基于集合的逻辑或者使用WHILE循环,不要使用游标。 |
功能 |
非常量参数默认值 |
在本机编译的存储过程上使用参数默认值的时候,值必须是常量。从参数声明中移除所有的通配符。 |
功能 |
本机编译的存储过程不能有编号。从CREATE PROCEDURE语句中移除;编号。 |
|
功能 |
多行表值构造器 |
在一个本机编译的存储过程中不能使用同样的INSERT语句插入多行。要为每一行创建一个INSERT语句。 |
功能 |
WITH子句 |
本机编译的存储过程并不支持通用表表达式(CTE)。需要重写查询。 |
功能 |
递归查询 |
不支持递归查询。从本机编译的存储过程中移除这种查询。 |
功能 |
子查询 |
不支持子查询。需要重写查询。 |
功能 |
COMPUTE |
不支持COMPUTE子句。从查询中移除这种子句。 |
功能 |
SELECT INTO |
不支持带INTO子句的SELECT语句。按照INSERT INTO Table SELECT的形式重写查询。 |
功能 |
OUTPUT |
不支持OUTPUT子句。将它从查询中移除。 |
功能 |
不完全插入列列表 |
在INSERT语句中,必须为表中的所有列指定值。 |
函数 |
函数(Function) |
本机编译的存储过程并不支持内置的函数。从存储过程中移除这些函数。 |
功能 |
CASE |
本机编译的存储过程里面的查询并不支持CASE语句。为每一种情况创建一个查询。 |
功能 |
用户定义的函数 |
用户定义的函数不能在本机编译的存储过程中使用。从存储过程定义中移除对这种函数的引用。 |
功能 |
用户定义的聚合函数 |
用户定义的聚合函数不能在本机编译的存储过程中使用。从存储过程中移除对这种函数的引用。 |
功能 |
浏览模式元数据 |
本机编译的存储过程并不支持浏览模式元数据。确保将会话选项NO_BROWSETABLE设置为OFF。 |
功能 |
DELETE中的FROM 子句 |
在本机编译的存储过程中DELETE语句并不支持FROM子句。 |
功能 |
UPDATE中的FROM 子句 |
在本机编译的存储过程中UPDATE语句并不支持FROM子句。 |
功能 |
临时过程 |
临时的存储过程并不能被本机编译。或者创建一个永久的本机编译的存储过程,或者创建一个临时解释的Transact-SQL存储过程。 |
隔离级别 |
READ UNCOMMITTED |
本机编译的存储过程并不支持隔离级别READ UNCOMMITTED。使用它所支持的隔离级别,例如SNAPSHOT。 |
隔离级别 |
READ COMMITTED |
本机编译的存储过程并不支持隔离级别READ UNCOMMITTED。使用它所支持的隔离级别,例如SNAPSHOT。 |
功能 |
临时表 |
不能在本机编译的存储过程中使用tempdb中的表。可以使用一个表变量或者使用一个DURABILITY=SCHEMA_ONLY的内存优化表。 |
功能 |
多种活动结果集(MARS) |
本机编译的存储过程并不支持多种活动结果集(MARS)。这个错误还能表明链接服务器的使用。链接服务器可以使用MARS。但是本机编译的存储过程并不支持链接服务器。你需要直接连接到本机编译的存储过程所寄宿的服务器和数据库。 |
功能 |
DTC |
不能在分布式事务中访问内存优化表和本机编译的存储过程。使用SQL事务替代。 |
功能 |
non-bin2排序规则 |
在本机编译的存储过程中,对字符型字符串的比较、排序以及其他操作必须使用BIN2排序规则。使用COLLATE子句或者使用带有恰当排序规则的列和变量。可以查看排序规则和代码页面获取更多信息。 |
功能 |
UTF-16数据的截断 |
带有_SC排序规则的字符型字符串使用UTF-16编码。将一个n(var)char值转换成一个长度更短的n(var)char值涉及到截断。在本机编译的存储过程中UTF-16值并不支持这些功能。避免截断UTF-16编码的字符串。 |
功能 |
EXECUTE WITH RECOMPILE |
本机编译的存储过程并不支持WITH RECOMPILE选项。 |
功能 |
从专有的管理连接中执行 |
本机编译的存储过程不能从专有的管理连接(DAC)中执行。使用一个常规的连接。 |
操作 |
ALTER PROCEDURE |
本机编译的存储过程不能被改变。如果想要改变过程定义,丢弃(drop)并重新创建存储过程。 |
操作 |
保存点 |
不能在拥有一个活动保存点的事务中调用本机编译的存储过程。从事务中移除保存点。 |
操作 |
ALTER AUTHORIZATION |
不能改变已有内存优化表和本机编译的存储过程的拥有者。如果想要改变所有关系那么需要丢弃并重新创建表或者存储过程。 |
操作符 |
OPENROWSET |
不支持该操作符。从本机编译的存储过程中移除OPENROWSET。 |
操作符 |
OPENQUERY |
不支持该操作符。从本机编译的存储过程中移除OPENQUERY。 |
操作符 |
OPENDATASOURCE |
不支持该操作符。从本机编译的存储过程中移除OPENDATASOURCE。 |
操作符 |
OPENXML |
不支持该操作符。从本机编译的存储过程中移除OPENXML。 |
操作符 |
CONTAINSTABLE |
不支持该操作符。从本机编译的存储过程中移除CONTAINSTABLE。 |
操作符 |
FREETEXTTABLE |
不支持该操作符。从本机编译的存储过程中移除FREETEXTTABLE。 |
功能 |
表值函数 |
不能在本机编译的存储过程中引用表值函数。使用引用表替代。 |
操作符 |
CHANGETABLE |
不支持该操作符。从本机编译的存储过程中移除CHANGETABLE。 |
操作符 |
GOTO |
不支持该操作符。使用其他的过程式结构,例如WHILE。 |
操作符 |
EXECUTE, INSERT EXEC |
不支持嵌套的本机编译的存储过程。必须的操作可以被指定为内联的,作为存储过程定义的一部分。 |
操作符 |
OFFSET |
不支持该操作符。从本机编译的存储过程中移除OFFSET。 |
操作符 |
UNION |
不支持该操作符。从本机编译的存储过程中移除UNION。可以使用一个表变量将一些结果集连接到一个单独的结果集中。 |
操作符 |
INTERSECT |
不支持该操作符。从本机编译的存储过程中移除INTERSECT。 在某些情况下可以使用一个INNER JOIN获取同样的结果。 |
操作符 |
EXCEPT |
不支持该操作符。从本机编译的存储过程中移除EXCEPT。 |
操作符 |
OUTER JOIN |
不支持该操作符。从本机编译的存储过程中移除OUTER JOIN。 |
操作符 |
APPLY |
不支持该操作符。从本机编译的存储过程中移除APPLY。 |
操作符 |
PIVOT |
不支持该操作符。从本机编译的存储过程中移除PIVOT。 |
操作符 |
UNPIVOT |
不支持该操作符。从本机编译的存储过程中移除UNPIVOT。 |
操作符 |
OR, IN |
本机编译的存储过程中的查询并不支持析取(OR、IN)。为每一种情况创建单独的查询。 |
操作符 |
CONTAINS |
不支持该操作符。从本机编译的存储过程中移除CONTAINS。 |
操作符 |
FREETEXT |
不支持该操作符。从本机编译的存储过程中移除FREETEXT。 |
操作符 |
NOT |
不支持该操作符。从本机编译的存储过程中移除NOT。在某些情况下,可以使用不等式替代NOT。例如,NOT a=b可以被替换为a!=b。 |
操作符 |
TSEQUAL |
不支持该操作符。从本机编译的存储过程中移除TSEQUAL。 |
操作符 |
LIKE |
不支持该操作符。从本机编译的存储过程中移除LIKE。 |
操作符 |
NEXT VALUE FOR |
在本机编译的存储过程内部不能引用序列。使用解释型Transact-SQL获取值,然后将其传入本机编译的存储过程。查看在内存优化表中实现IDENTITY获取更多信息。 |
操作符 |
~, &, |, ^ (按位操作符) |
不支持按位操作符。从本机编译的存储过程中移除它们。 |
操作符 |
% (modulo) |
不支持模块操作符。从本机编译的存储过程中移除%。 |
设置选项 |
选项 |
在本机编译的存储过程里面不能改变SET选项。可以使用BEGIN ATOMIC语句设置某些选项。可以查看本机编译的存储过程中的原子块章节。 |
操作数 |
TABLESAMPLE |
不支持该操作数。从本机编译的存储过程中移除TABLESAMPLE。 |
选项 |
RECOMPILE |
本机编译的存储过程在创建的时候编译。如果想要重新编译一个本机编译的存储过程,需要丢弃并重新创建它。从过程定义中移除RECOMPILE。 |
选项 |
ENCRYPTION |
不支持该选项。从过程定义中移除ENCRYPTION。 |
选项 |
FOR REPLICATION |
本机编译的存储过程不能被重复创建。从过程定义中移除FOR REPLICATION。 |
选项 |
FOR XML |
不支持该选项。从本机编译的存储过程中移除FOR XML。 |
选项 |
FOR BROWSE |
不支持该选项。从本机编译的存储过程中移除FOR BROWSE。 |
连接提示 |
HASH, MERGE |
本机编译的存储过程仅支持嵌套循环的连接。并不支持哈希和合并连接。移除连接提示。 |
查询提示 |
Query提示 |
在本机编译的存储过程内部并没有这个查询提示。查看查询提示(Transact-SQL)说明了解支持的查询提示。 |
选项 |
DISTINCT |
不支持该选项。从本机编译的存储过程中的查询中移除DISTINCT。 |
选项 |
PERCENT |
TOP子句并不支持该选项。从本机编译的存储过程中的查询中移除PERCENT。 |
选项 |
WITH TIES |
TOP子句并不支持该选项。从本机编译的存储过程中的查询中移除WITH TIES。 |
聚合函数 |
聚合函数(Aggregate function) |
不支持这些子句。想要获取与本机编译的存储过程中的聚合函数相关的更多信息,可以查看本机编译的存储过程指南。 |
排名函数 |
排名函数(Ranking function) |
本机编译的存储过程并不支持排名函数。将它们从过程定义中移除。 |
函数 |
函数(Function) |
不支持该函数。从本机编译的存储过程中移除它。 |
语句 |
语句(Statement) |
不支持该语句。从本机编译的存储过程中移除它。 |
功能 |
深类型的MIN/MAX |
在本机编译的存储过程内不能将聚合函数MIN和MAX用于字符和二进制字符串值。 |
功能 |
没有聚合函数的GROUP BY |
在本机编译的存储过程中,如果一个查询有一个GROUP BY子句,那么该查询也必须使用一个聚合函数。向查询中添加一个聚合函数。 |
功能 |
不在GROUP BY列表中的ORDER BY 表达式 |
对于既包含GROUP BY又包含ORDER BY子句的查询,ORDER BY列表中的每一个条目也必须出现在GROUP BY列表中。 |
功能 |
ROLLUP |
在本机编译的存储过程中ROLLUP不能和GROUP BY子句一起使用。从过程定义中移除ROLLUP。 |
功能 |
CUBE |
在本机编译的存储过程中CUBE不能和GROUP BY子句一起使用。从过程定义中移除CUBE。 |
功能 |
GROUPING SETS |
在本机编译的存储过程中GROUPING SETS不能和GROUP BY子句一起使用。从过程定义中移除GROUPING SETS。 |
请记住,这个列表会随着时间的推移而变化。随着最终版本的临近,Microsoft期望放松这其中的某些限制。
模式绑定
在大多数内存数据库关注无模式设计的时候,Microsoft则是走了另一条路子。本机编译的存储过程必须要使用“SCHEMABINDING”选项。这个选项将它们锁定到它们关联的表。如果没有丢弃引用表的所有存储过程,那么这些过程引用的任何表都不能被丢弃。
不幸的是,在SQL Server 2014中正常的存储过程并不支持这个选项。
执行
本机编译的存储过程不会作为调用方执行。相反的,它们始终会使用设置为“OWNER”、“SELF”或者一个指定用户的“EXECUTE AS”选项创建。
原子块
原子块和我们通常看见的内容有点不同,但是这是必须的,下面这段是来自于文档的引用。
BEGIN ATOMIC是ANSI SQL标准的一部分。SQL Server仅在本机编译的存储过程的顶层支持原子块。
- 每一个本机编译的存储过程仅会包含一个Transact-SQL语句块。这是一个原子(ATOMIC)块。
- 非本机的、解释执行的Transact-SQL存储过程和特别的批处理不支持原子操作。
原子块在事务中执行。如果块中有任何一个命令执行失败,那么它就会回滚到块开始的时候创建的保存点。另外,对于原子块而言会话设置是固定的。在会话中使用不同的设置执行同样的原子块将会导致同样的行为,当前会话的独立设置。
内部原理
最初,这个报告被题为“本机编译的查询”,但是这不能公正地表达出它运行的深入程度。在创建一个内存优化表的时候,SQL Server将会明确地为该表逐字地创建一个DLL。这个DLL包含了为了修改表中的数据而编写的机器码。甚至索引也会被编译成这种DLL,所以修改一个索引意味着重新构建表。
文档上有一些不明确的内容,但是好像DLL也是为存储过程创建的。这可能解释了本机编译的存储过程为什么不能被改变的原因。作为替代你必须丢弃旧的过程,然后创建它的替代品。
查看英文原文:Natively Compiled Tables in SQL Server 2014