必须先 CREATE TYPE 定义内存优化表类型,再 DECLARE 实例;直接 DECLARE WITH (MEMORY_OPTIMIZED = ON) 会报错。仅本机编译存储过程能发挥性能优势,且需匹配哈希索引、DURABILITY = SCHEMA_ONLY 等约束。

必须先 CREATE TYPE,不能直接 DECLARE MEMORY_OPTIMIZED 表变量
SQL Server 2019 不允许在存储过程中用 DECLARE @t TABLE (...) WITH (MEMORY_OPTIMIZED = ON) 这种写法——会报错 Incorrect syntax near 'AS TABLE'。这是硬性语法限制,不是配置问题。
正确路径是两步:先用 CREATE TYPE 定义内存优化表类型,再在存储过程中 DECLARE 实例。类型必须带 WITH (MEMORY_OPTIMIZED = ON),且只支持 DURABILITY = SCHEMA_ONLY 或 SCHEMA_AND_DATA。
CREATE TYPE dbo.tvp_order_summary AS TABLE (order_id INT INDEX ix_oid HASH WITH (bucket_count = 8000), total DECIMAL(18,2)) WITH (MEMORY_OPTIMIZED = ON, DURABILITY = SCHEMA_ONLY);- 之后才能:
DECLARE @summary dbo.tvp_order_summary; - 如果漏掉
CREATE TYPE步骤,或试图在运行时动态建表(如CREATE TABLE #tmp ... WITH (MEMORY_OPTIMIZED = ON)),都会失败或引发严重编译延迟
只有本机编译存储过程(NATIVE_COMPILATION)能真正提速
普通解释型 T-SQL 存储过程里操作内存优化表变量,几乎不提升性能,反而多一层类型校验开销。真正的速度收益只在 WITH NATIVE_COMPILATION, SCHEMABINDING 的存储过程中兑现。
这类过程有强约束:只能访问内存优化对象(不能 JOIN 普通磁盘表)、不能用 EXEC 或动态 SQL、事务隔离级别限于 SNAPSHOT 或 REPEATABLE READ。
- 声明示例:
CREATE PROCEDURE dbo.usp_calc_summary WITH NATIVE_COMPILATION, SCHEMABINDING AS BEGIN ... END - 若混用磁盘表(如
INSERT INTO @summary SELECT * FROM orders),SQL Server 会拒绝编译 - 非本机编译过程里调用该过程,也不触发原生执行路径——性能优势彻底失效
哈希索引的 bucket_count 必须预估,不能拍脑袋填
哈希索引靠 bucket_count 控制内存布局和冲突链长度。填太小(比如预期 5 万行却设 1000),会导致大量链式查找,退化成 O(n);填太大(比如设 1000000),浪费内存且可能触发 MEMORYCLERK_XTP 持续增长,最终引发错误 701(内存不足)。
- 经验公式:
bucket_count设为预期唯一键数量的 1–2 倍;上限可放宽到 10 倍,但需结合实际监控 - 查当前内存占用:
SELECT type, pages_kb FROM sys.dm_os_memory_clerks WHERE type = 'MEMORYCLERK_XTP'; - 避免对非等值查询字段建哈希索引——
WHERE id > 100这类范围条件无法利用哈希索引,应改用NONCLUSTERED索引
DURABILITY = SCHEMA_ONLY 是临时中间结果的唯一合理选项
把内存优化表当临时表用(比如替代 @table 或 ##temp),必须选 DURABILITY = SCHEMA_ONLY。选 SCHEMA_AND_DATA 会强制写日志、持久化内存、触发 GC,完全抵消内存优势,还可能拖垮并发。
这个选项意味着:重启后数据全丢,但结构保留;不占 tempdb;无磁盘 I/O。它只适合单次请求生命周期内的中间计算。
- 部署时一次性建好类型,不要在运行时反复
DROP/CREATE TYPE -
SCHEMA_ONLY类型不能用于本机编译过程外的场景——否则连基本插入都慢于普通表变量 - 如果误用
SCHEMA_AND_DATA存放会话级中间态,你会看到tempdb.sys.dm_db_xtp_memory_consumers中持续增长的“SYSTEM_TABLES”条目,这是危险信号
真正卡住多数人的,从来不是语法会不会写,而是没意识到:内存优化表变量 ≠ 普通表变量的“更快版本”,它是一套需要重新设计访问路径、索引策略和过程架构的独立执行模型。漏掉任意一个前提(类型定义、本机编译、bucket_count、DURABILITY 选择),就只是徒增复杂度。

















