从Oracle视图(在实体框架中)检索记录使用硬编码的字符串值运行得很快,但使用字符串参数运行得很慢



我正在构建一个ASP.NET MVC 5应用程序,以便一次对2到12行进行只读访问。这些记录存储在Oracle 11中,并通过实体框架6从Oracle中的视图进行访问。正如标题所说,使用硬编码值很快,但使用字符串参数很慢(下面的示例)这运行得很快:

public List<VW_COLLISIONS_TS> GetCollisions(string collisionMRN)
{
var collisions = (from c in TSP_Context.VW_COLLISIONS_TS
where c.COLLISION_MASTER_RECORD_NUMBER.Equals("902770479")
select c).AsNoTracking();
return collisions.ToList();
}

但运行缓慢:

public List<VW_COLLISIONS_TS> GetCollisions(string collisionMRN)
{
var collisions = (from c in TSP_Context.VW_COLLISIONS_TS
where .COLLISION_MASTER_RECORD_NUMBER.Equals(collisionMRN)
select c).AsNoTracking();

return collisions.ToList();
}

使用该参数大约需要30秒才能返回记录。为什么会这样?

更新:我设置了一个跟踪,这就是我得到的:

[#1 - with hard-coded string value]
Opened connection at 2/9/2017 9:48:29 AM -05:00
SELECT 
"Extent1"."PERSON_MASTER_RECORD_NUMBER" AS "PERSON_MASTER_RECORD_NUMBER", 
"Extent1"."VEHICLE_MODEL" AS "VEHICLE_MODEL", 
"Extent1"."PERSON_AGE" AS "PERSON_AGE"
FROM "DWOBDEV"."VW_COLLISIONS_TS" "Extent1"
WHERE ('902770479' = "Extent1"."COLLISION_MASTER_RECORD_NUMBER")
-- Executing at 2/9/2017 9:48:29 AM -05:00
-- Completed in 5 ms with result: OracleDataReader
Closed connection at 2/9/2017 9:44:29 AM -05:00
[2. With string parameter]
Opened connection at 2/9/2017 9:44:17 AM -05:00
SELECT 
"Extent1"."PERSON_MASTER_RECORD_NUMBER" AS "PERSON_MASTER_RECORD_NUMBER", 
"Extent1"."VEHICLE_MODEL" AS "VEHICLE_MODEL", 
"Extent1"."PERSON_AGE" AS "PERSON_AGE"
FROM "DWOBDEV"."VW_COLLISIONS_TS" "Extent1"
WHERE (("Extent1"."COLLISION_MASTER_RECORD_NUMBER" = :p__linq__0) OR (("Extent1"."COLLISION_MASTER_RECORD_NUMBER" IS NULL) AND   (:p__linq__0 IS NULL)))
-- p__linq__0: '902770479' (Type = Object)
-- Executing at 2/9/2017 9:44:17 AM -05:00
-- Completed in 12364 ms with result: OracleDataReader
Closed connection at 2/9/2017 9:48:29 AM -05:00

我同事的观点是:"我认为,当你硬编码时,它会被视为数字/整数,当你使用字符串时,它也会被视为由varchar/text,然后寻找null。试着使用COLLISION_MASTER_REDRORD_number作为整数变量,如果COLLISION-MASTER_REGRORD_number是数字/int数据类型。">

你们怎么看[注意:当前,COLLISION_MASTER_RECORD_NUMBER是Oracle数据库中的varchar2"数字"(无alpha)]

更新(已回答!):根据Alexander V发布的内容(包括EF链接),我想出了这个:

var collisions = (from c in TSP_Context.VW_COLLISIONS_TS
where c.COLLISION_MASTER_RECORD_NUMBER == (DbFunctions.AsNonUnicode(collisionMRN))
select c).AsNoTracking();

我在上下文构造函数中添加了这个:

this.Configuration.UseDatabaseNullSemantics = true;

效果很好。

在这两种情况下,您都需要检查sql查询生成了什么。

尝试在ToList()调用之前添加此项:

var sql = ((System.Data.Entity.Core.Objects.ObjectQuery)collisions)
.ToTraceString();

如果您可以返回sql查询,我们将看到这里发生了什么。

更新:(基于@R.Jo发布的sql查询更新)

我认为第二个查询中的性能问题与额外的NULL检查有关:所以尝试使用== "something"而不是.Equals("something")因为Equals可以为可为null的类型生成额外的null检查;当您执行Equals时,我们EF需要处理两种不同的数据类型,我们也希望避免这种情况。(参见下面的示例)。如果示例中的代码不起作用,请尝试以下操作UseDatabaseNullSemantics = true;也许有帮助。(请参阅此处的更多信息为什么EF使用不必要的null检查生成SQL查询?.

编辑:

如果碰撞_MASTERRECORD_NUMBER,那么我们可以做一些类似的事情

public List<VW_COLLISIONS_TS> GetCollisions(string collisionMRN)
{
int collision = int.Parse(collisionMRN);
var collisions = (from c in TSP_Context.VW_COLLISIONS_TS
where .COLLISION_MASTER_RECORD_NUMBER == collision
select c).AsNoTracking();

return collisions.ToList();
}

请告诉我它是否对你有用。

最新更新