如何提高查询速度?

时间:2015-10-27 09:09:55

标签: c# sql performance linq

我有一张包含客户列表的表格。 一个客户有0个,1个或更多的合同。

我必须检索所有已启用的客户,在DTO中设置它们并将当前合同添加到此DTO(如果有)

目前,它非常缓慢(超过10分钟)。

CODE

1777: '23.5R25 Bridgestone VLT **',

6 个答案:

答案 0 :(得分:2)

使用投影仅使用"选择"返回您使用的列。如果您有36列,这将为您提供更好的结果。

customers= context.Customers.Where(c => c.IsEnabled).Select(cust => new Customer
{
    Id = cust .Id
}).ToList();

https://www.talksharp.com/entity-framework-projection-queries

之后检查查询计划是否有表扫描或索引扫描。尽量通过设置适当的索引来避免它们。

答案 1 :(得分:1)

我认为问题是在循环中检索契约的查询。最好用一个查询检索所有数据,如下所示:

var date = DateTime.Today;
var query =
    from customer in context.Customers
    where customer => customer.IsEnabled
    select new 
    {
        customer,
        contract = customer.Contracts.FirstOrDefault(c => c.ContractEndDate >= date && c.ContractStartDate <= date)
    };
var result = new List<CustomerOverviewDto>();
foreach (var entry in query)
{
    CustomerOverviewDto customerDto = GetCustomer(entry.customer);
    if (entry.contract != null)
        SetContract(customerDto, entry.contract);
    result.add(customerDto);
}

答案 2 :(得分:0)

好的,首先,当你使用.ToList()时,你正在那里执行查询,并将IsEnabled的每一行拉回到内存中进行处理。你想在数据库方面做更多的事情。

result = context.Customers.Where(c => c.IsEnabled); //be lazy

其次,如果查询具有可以使用的索引,那么查询只会很好地执行并由执行引擎进行优化。

在您正在执行比较的字段上添加一些索引。

想想这行代码

    customer.Contracts.Where(c => c.ContractEndDate >= DateTime.Today && 
c.ContractStartDate <= DateTime.Today).FirstOrDefault();

您是否拥有从客户到合同的外键,并且您在ContractStartDate和ContractEndDate上没有索引,它将执行非常糟糕的操作并且将为每个客户运行一次&#39;的IsEnabled&#39;

答案 3 :(得分:0)

似乎你只想在返回值时做一些事情。因此,您可以在初始查询中添加此项,并包含合同:

customers= context.Customers
                           .Include(c => c.Contracts)
                           .Where(c => c.IsEnabled
                                     && c.Contracts.Any(con => con.ContractEndDate >= DateTime.Today && con .ContractStartDate <= DateTime.Today))
                           .ToList();

 foreach (Customer customer in customers)  
 {
    CustomerOverviewDto customerDto = GetCustomer(customer);
    Framework.Contract contract =
    customer.Contracts.Where(c => c.ContractEndDate >= DateTime.Today && c.ContractStartDate <= DateTime.Today)
        .First();
    SetContract(customerDto, contract);
 }

答案 4 :(得分:0)

由于我不知道您的域模型结构是什么样的,或者您没有使用导航属性将CURRENT合同映射到客户,因此您可以执行类似的操作。

通过实现所有客户和合同,然后将内存映射到DTO对象,您可以只对数据库进行2次往返。假设您将CustomerId设置为FK,将Customer.Id设置为PK。

List<CustomerOverviewDto> result = new List<CustomerOverviewDto>();    

customers = context.Customers.Where(c => c.IsEnabled).ToList();
contracts = context.Contracts.Where(c => c.ContractEndDate >= DateTime.Today && c.ContractStartDate <= DateTime.Today).ToList();

foreach (Customer customer in customers)
{
    var customerDto = GetCustomer(customer);
    var contract = contracts.Where(c => c.CustomerId == customer.Id).FirstOrDefault();
    if (contract != null)
    {
        SetContract(customerDto, contract);
    }

    result.add(customerDto);
}

答案 5 :(得分:0)

我终于通过使用1个查询和投影解决了这个问题

context.Customers.Where(c => c.IsEnabled).Select(c => new CustomerOverviewDto{...}).ToList();

我在创建CustomerOverviewDto时直接检索合约