从Oracle视图(在Entity Framework中)检索记录使用硬编码字符串值快速运行,但使用字符串参数

时间:2017-02-06 15:44:12

标签: c# oracle entity-framework parameters

我正在构建一个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处理,然后查找空值。尝试使用COLLISION_MASTER_RECORD_NUMBER作为整数变量,如果COLLISION_MASTER_RECORD_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();

我在Context构造函数中添加了这个:

this.Configuration.UseDatabaseNullSemantics = true;

效果很好。

1 个答案:

答案 0 :(得分:0)

您需要检查两种情况下sql查询生成的内容。

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

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

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

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

我认为第二个查询中的性能问题与额外的NULL检查有关: 因此,请尝试使用== "something"代替.Equals("something") 因为Equals可以为可空类型生成额外的空值检查; 当你做Equals时我们EF需要在这里使用2种不同的数据类型,我们也希望避免这种情况。 (见下面的例子)。 如果示例中的代码不起作用,试试这个' UseDatabaseNullSemantics = true;也许有帮助。 (点击此处Why is EF generating SQL queries with unnecessary null-checks?了解更多信息。

修改

如果COLLISION_MASTER_RECORD_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();
 }

请告诉我它是否适合您。