首次dml卡顿源于odp.net core默认启用元数据自动发现,每次新表执行insert/update/delete前隐式查询all_constraints等系统视图;需同时配置metadata performance=enabled、statement cache size=50–200及connection timeout方可根治。
性能抖动不是随机发生的,基本都来自元数据发现机制在首次 dml 时触发的系统表查询,以及连接池和语句缓存未正确启用。
为什么首次执行 INSERT/UPDATE/DELETE 会卡顿
ODP.NET Core 默认开启元数据自动发现,每次对新表执行 DML(如 INSERT INTO user_orders_2024...)前,会隐式执行类似下面的查询:
SELECT ac.constraint_name key_name, acc.column_name key_col, :"SYS_B_0" FROM all_cons_columns acc, all_constraints ac WHERE acc.owner = ac.owner AND acc.constraint_name = ac.constraint_name AND acc.table_name = ac.table_name AND ac.constraint_type = :"SYS_B_1" AND ac.owner = :OwnerName AND ac.table_name = :TableName ORDER BY acc.constraint_name
这个查询本身不慢,但每换一个 OwnerName 或 TableName 就重跑一次,且无法被 EF Core 或 Dapper 层拦截或禁用。租户分表、动态表名场景下抖动会被反复放大。
- 仅影响 DML(
INSERT/UPDATE/DELETE),SELECT列信息获取不受影响 - 只在首次执行某张表的 DML 时发生,后续走缓存,所以本地测试常测不出
- 该行为与是否用 EF Core、Dapper、原生
OracleCommand无关,是驱动层硬编码逻辑
Statement Cache Size=0 是默认值,等于放弃解析优化
Statement Cache Size 控制 SQL 语句的硬解析缓存,默认为 0(即禁用)。一旦关闭,每次执行相同 SQL(哪怕参数不同)都会走完整解析流程,CPU 和共享池压力陡增。
使用tbot机器ID身份文件配合tsh CLI,通过Teleport访问控制SSH登录托管主机或执行远程命令。
- 设为
50–200能显著减少硬解析,尤其适合参数化查询高频场景 - 值超过
500反而增加查找开销和内存占用,不推荐无脑调高 - 必须显式写在连接字符串里,靠代码运行时修改无效
Metadata Performance=Disabled 是多数人忽略的开关
这是唯一能跳过上述系统表查询的配置项。设为 Enabled 后,驱动不再查 all_constraints 等视图,直接基于已知表结构构造 DML 语句。
- 连接字符串中必须明确写:
Metadata Performance=Enabled - 它不影响
SELECT的列元数据获取(比如OracleDataReader.GetFieldType()仍正常) - 若同时用了
ClientCharacterSet,两个参数要共存,顺序无关
真正容易被忽略的是:这三个参数——Statement Cache Size、Metadata Performance、Connection Timeout——只要漏掉任意一个,其他优化基本白做。特别是 Metadata Performance=Enabled,不加它,再大的连接池也救不了首次 DML 的抖动。










