内存优化表变量必须先用CREATE TYPE定义类型再DECLARE实例化,仅在本机编译存储过程中生效,需设DURABILITY = SCHEMA_ONLY、合理配置bucket_count,并严格监控内存使用。

直接用内存优化表替代临时表或会话级中间结果,能显著减少 tempdb 争用和 I/O,但必须满足几个硬性条件,否则反而拖慢执行——比如没建索引、在非本机编译模块里访问、或者误用了 DURABILITY = SCHEMA_AND_DATA 存持久数据。
必须声明为 TYPE 并分两步创建表变量
内存优化表变量不能像普通表变量那样内联声明。SQL Server 要求你先用 CREATE TYPE 定义类型,再用 DECLARE 实例化。这是语法强制项,跳过就会报错 Incorrect syntax near 'AS TABLE'。
CREATE TYPE dbo.tvp_session_data AS TABLE (id INT INDEX ix_id HASH WITH (bucket_count = 10000), value NVARCHAR(100)) WITH (MEMORY_OPTIMIZED = ON);- 之后才能:
DECLARE @session_data dbo.tvp_session_data; - 不支持
DECLARE @t TABLE (...)直接加WITH (MEMORY_OPTIMIZED = ON)—— 这种写法在 SQL Server 2019 中仍被拒绝
只在本机编译存储过程中启用性能优势
内存优化表变量的极致效率,只在本机编译(NATIVE COMPILATION)的存储过程中兑现。普通解释型 T-SQL 里操作它,依然走传统执行路径,几乎不提速,还多一层类型检查开销。
- 本机编译过程必须用
SCHEMABINDING,且只能引用内存优化对象(不能混用磁盘表) - 哈希索引的
bucket_count必须预估准确:太小导致链式冲突,太大浪费内存;建议设为预期唯一键数量的 1–2 倍,上限可放宽到 10 倍,但别盲目填1000000 - 非聚集索引(
NONCLUSTERED)适合范围查询,但会增加每行约 8–16 字节开销,高频插入场景慎用
避免把 SCHEMA_AND_DATA 表当临时表用
如果只是存一次性的中间计算结果(比如订单汇总中间态),绝对不要用 DURABILITY = SCHEMA_AND_DATA。它会写事务日志、占用持久内存、触发垃圾回收,完全抵消内存优势。
- 该选项适用于需要重启后仍存在的核心参考数据(如国家代码表),不是给临时逻辑用的
- 真正替代
##temp或@table的,是DURABILITY = SCHEMA_ONLY表——它只驻内存、无磁盘痕迹、不占tempdb - 注意:
SCHEMA_ONLY表必须在部署时一次性建好,不能在运行时CREATE TABLE ... WITH (MEMORY_OPTIMIZED = ON, DURABILITY = SCHEMA_ONLY)—— 动态建表会引发严重编译延迟,拖垮并发
内存不足时行为不可控,必须提前估算
内存优化对象没有“缓存淘汰”机制。一旦物理内存耗尽,SQL Server 不会像缓冲池那样踢出冷页,而是直接报错 Could not allocate memory for memory-optimized table,整个批处理失败。
- 单个内存优化表所需内存 ≈ 数据大小 + 索引开销(哈希索引 =
bucket_count * 8字节)+ 行版本控制冗余(建议按 2× 预估) - 监控实际用量看
sys.dm_db_xtp_table_memory_stats,重点关注memory_used_in_bytes和memory_allocated_in_bytes - 别依赖
max server memory设置来“兜底”——In-Memory OLTP 使用独立内存管理器,不受该配置限制
最常被忽略的是:内存优化表变量的生命周期和作用域绑定极紧,超出声明它的批处理或过程就自动释放;而很多人试图跨多个 EXEC 或动态 SQL 复用它,结果发现变量为空——这不是 bug,是设计使然。

















