我的项目有两个EF 4.1上下文,一个是模型优先,另一个是代码优先。这两个上下文都扩展了DbContext,并且连接到Oracle数据库。
当对一个大表(5M条记录)执行更新时,model-first上下文会像预期的那样生成SQL,并且运行速度很快(毫秒级):
update <schema.table_name> set field = 'value' where id = 1234
当对一个大表(4.7M条记录)执行更新时,code-first上下文会产生一些奇怪的PL/SQL:
declare
"UWI" nvarchar2(
128)
;
begin
update
"SCHEMA"."TABLE"
set "FIELD" = 'VALUE' /* :p0 */,
where ("UWI" = '2224434' /* :p37 */)
returning
"UWI" into
"UWI";
open '' /* :p38 */ for select
"UWI" as "UWI"
from dual;
end;
此更新语句需要3秒才能完成。
下面是代码优先上下文的代码优先EntityTypeConfiguration:
public WellEntityConfiguration()
{
this.ToTable("TABLE", "SCHEMA");
this.HasKey(entity => entity.Uwi);
this.Property(entity => entity.Uwi).HasColumnName("UWI");
... //lots of properties being set
}
我是否可以设置一个配置来强制EF生成简单的更新语句,而不是疯狂的PL/SQL?
这个问题的答案是双重的。
从生成的SQL中删除PL/SQL
数据库中的列名是全大写的("UWI"),而类上的属性是驼峰大小写的("UWI")。我将属性名称更改为全大写,EF删除了PL/SQL代码,只生成SQL:
UPDATE "SCHEMA"."TABLE"
SET "FIELD" = "VALUE"
WHERE ("UWI" = '2224434')
但是,这并不能提高性能。
为什么Update Was Slow
在与DBA一起跟踪查询之后,我们发现EF将Uwi的值绑定到一个十六进制字符串,而不是"2224434"。这将导致Oracle执行全表扫描,从而影响性能。我需要在Uwi
属性上指定列类型,如下所示:
this.Property(entity => entity.Uwi).HasColumnName("UWI").HasColumnType("VARCHAR2");
HasColumnType
是神奇子弹,我的更新语句在80毫秒内返回。