与硬编码整数值相比,使用整数变量时 Linq to SQL 查询非常慢
A Linq to SQL query is very slow when using an interger variable compared to a hardcoded integer value
我有一个查询大约需要 10 秒才能执行。
奇怪的是,如果我用硬编码整数(例如 3)替换 "machineNo" 参数,查询需要一瞬间。这是我迄今为止遇到的最不寻常的性能问题。
public static IEnumerable<vwJobAppointment> GetAllJobs(int machineNo)
{
var db = new DbContext();
IEnumerable<vwJobAppointment> list;
list = db.vwJobAppointments.Where(a => a.ResourceId == (machineNo)).AsNoTracking().ToList();
return list;
}
查询需要 10 秒 +
public static IEnumerable<vwJobAppointment> GetAllJobs(int machineNo)
{
var db = new DbContext();
IEnumerable<vwJobAppointment> list;
list = db.vwJobAppointments.Where(a => a.ResourceId == (3)).AsNoTracking().ToList();
return list;
}
这个查询不到一秒钟。
有什么想法吗?我正在使用 Entity Framework 5 和 SQL 2008 数据库
这听起来像是参数嗅探;即典型的参数化计划缓存问题,其中查询计划是使用 initial 示例参数值生成的,结果需要一个与其他一些值截然不同的计划。如果数据有偏差,这很常见 - 例如,某些值会有 3 个匹配项,而其他值会有 300,000 个匹配项。这通常是在 OPTION (OPTIMIZE FOR ... UNKNOWN)
提示发挥作用时,但这需要 您的 ORM 能够指定此提示, 或 让你手写SQL。
EF 查询被翻译成 SQL。 SQL 使用查询计划来优化查询。变量往往会使程序变慢很多。在某些情况下,如果您 select 临时 table 中的输入变量并加入此 table 您通常会检查输入变量的地方,则可以克服此问题。该过程的另一个好处是您可以强制执行查询计划。我建议:
- 创建一个将资源 ID 作为输入的存储过程
- 尝试 select 在临时 table 中输入变量并加入那个
- 如果这对强制执行查询计划没有帮助
您可以稍微优化一下您的 where 表达式。在这种情况下,您可以将参数变量重新分配给局部变量。在我的测试中,我有三种方法:
// Execution time: 00:00:00.0140118
public static IEnumerable<myClass> GetAllJobs(int machineNo)
{
var db = new DbContext();
IEnumerable<myClass> list;
list = db.vwJobAppointments.Where(a => a.ResourceId == (machineNo)).ToList();
return list;
}
// Execution time: 00:00:00.0019991
public static IEnumerable<myClass> GetAllJobs2(int machineNo)
{
var db = new DbContext();
IEnumerable<myClass> list;
list = db.vwJobAppointments.Where(a => a.ResourceId == 55).ToList();
return list;
}
// Execution time: 00:00:00.0010013
public static IEnumerable<myClass> GetAllJobs3(int machineNo)
{
int machineNo2 = machineNo;
var db = new DbContext();
IEnumerable<myClass> list;
list = db.vwJobAppointments.Where(a => a.ResourceId == (machineNo2)).ToList();
return list;
}
我有一个查询大约需要 10 秒才能执行。
奇怪的是,如果我用硬编码整数(例如 3)替换 "machineNo" 参数,查询需要一瞬间。这是我迄今为止遇到的最不寻常的性能问题。
public static IEnumerable<vwJobAppointment> GetAllJobs(int machineNo)
{
var db = new DbContext();
IEnumerable<vwJobAppointment> list;
list = db.vwJobAppointments.Where(a => a.ResourceId == (machineNo)).AsNoTracking().ToList();
return list;
}
查询需要 10 秒 +
public static IEnumerable<vwJobAppointment> GetAllJobs(int machineNo)
{
var db = new DbContext();
IEnumerable<vwJobAppointment> list;
list = db.vwJobAppointments.Where(a => a.ResourceId == (3)).AsNoTracking().ToList();
return list;
}
这个查询不到一秒钟。
有什么想法吗?我正在使用 Entity Framework 5 和 SQL 2008 数据库
这听起来像是参数嗅探;即典型的参数化计划缓存问题,其中查询计划是使用 initial 示例参数值生成的,结果需要一个与其他一些值截然不同的计划。如果数据有偏差,这很常见 - 例如,某些值会有 3 个匹配项,而其他值会有 300,000 个匹配项。这通常是在 OPTION (OPTIMIZE FOR ... UNKNOWN)
提示发挥作用时,但这需要 您的 ORM 能够指定此提示, 或 让你手写SQL。
EF 查询被翻译成 SQL。 SQL 使用查询计划来优化查询。变量往往会使程序变慢很多。在某些情况下,如果您 select 临时 table 中的输入变量并加入此 table 您通常会检查输入变量的地方,则可以克服此问题。该过程的另一个好处是您可以强制执行查询计划。我建议:
- 创建一个将资源 ID 作为输入的存储过程
- 尝试 select 在临时 table 中输入变量并加入那个
- 如果这对强制执行查询计划没有帮助
您可以稍微优化一下您的 where 表达式。在这种情况下,您可以将参数变量重新分配给局部变量。在我的测试中,我有三种方法:
// Execution time: 00:00:00.0140118
public static IEnumerable<myClass> GetAllJobs(int machineNo)
{
var db = new DbContext();
IEnumerable<myClass> list;
list = db.vwJobAppointments.Where(a => a.ResourceId == (machineNo)).ToList();
return list;
}
// Execution time: 00:00:00.0019991
public static IEnumerable<myClass> GetAllJobs2(int machineNo)
{
var db = new DbContext();
IEnumerable<myClass> list;
list = db.vwJobAppointments.Where(a => a.ResourceId == 55).ToList();
return list;
}
// Execution time: 00:00:00.0010013
public static IEnumerable<myClass> GetAllJobs3(int machineNo)
{
int machineNo2 = machineNo;
var db = new DbContext();
IEnumerable<myClass> list;
list = db.vwJobAppointments.Where(a => a.ResourceId == (machineNo2)).ToList();
return list;
}