本机编译的查询仅能用于内存优化表。如果你还需要访问传统表,那么你必须使用解释执行的查询。这意味着你不能使用内存优化表不支持的数据类型。
为了换取性能,本机编译的查询在灵活性方面有很大的限制。不出所料的,你不能使用表自身并不支持的变量数据类型。你也不能使用废弃的技术,例如游标。
更令人惊讶的是不支持的标准操作。这些内容多的让人难以概括,所以我们把完整列表展示了出来。
类型 | 功能 | 决议 |
功能 | 表值参数 | 本机编译的存储过程的参数不能使用表类型。使用标量数据类型替代。 |
功能 | 内联表变量 | 声明变量时表类型不能被声明为内联的。必须使用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也是为存储过程创建的。这可能解释了本机编译的存储过程为什么不能被改变的原因。作为替代你必须丢弃旧的过程,然后创建它的替代品。