C# 如何提高查询速度?

C# 如何提高查询速度?,c#,sql,performance,linq,C#,Sql,Performance,Linq,我有一张有顾客名单的桌子。 一个客户有0个、1个或多个合同 我必须检索所有启用的客户,在DTO中设置它们,并将当前合同添加到此DTO(如果有) 目前,速度非常慢(超过10分钟) 代码 List<CustomerOverviewDto> result = new List<CustomerOverviewDto>(); customers= context.Customers.Where(c => c.IsEnabled).ToList(); fore

我有一张有顾客名单的桌子。 一个客户有0个、1个或多个合同

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

目前,速度非常慢(超过10分钟)

代码

List<CustomerOverviewDto> result = new List<CustomerOverviewDto>();    
customers= context.Customers.Where(c => c.IsEnabled).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)
                .FirstOrDefault();
        if (contract != null)
        {
            SetContract(customerDto, contract);
        }
        result.add(customerDto);
    }
列表结果=新列表();
customers=context.customers.Where(c=>c.IsEnabled.ToList();
foreach(客户中的客户)
{
CustomerOverviewDto customerDto=GetCustomer(客户);
框架.合同=

customer.Contracts.Where(c=>c.ContractEndDate>=DateTime.Today&&c.ContractStartDate好的,首先,当您使用.ToList()时,您正在执行查询,并将可访问的每一行都拉回到内存中进行处理。您想在数据库方面做更多的工作

result = context.Customers.Where(c => c.IsEnabled); //be lazy
其次,查询只有在有索引的情况下才能很好地执行并被执行引擎适当地优化

在要对其执行比较的字段上添加一些索引

以这行代码为例

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

c、 ContractStartDate使用投影仅返回使用“选择”处理的列。如果您有36列,这将为您提供更好的结果

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


之后,检查queryplan中是否有表扫描或索引扫描。通过设置适当的索引来避免这些扫描。

似乎您只想在返回值时执行某些操作。因此,您可以在初始查询中添加此项,并包括合同:

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);
 }
customers=context.customers
.包括(c=>c.合同)
.其中(c=>c.IsEnabled

&&c.Contracts.Any(con=>con.ContractEndDate>=DateTime.Today&&con.ContractStartDate c.ContractEndDate>=DateTime.Today&&c.ContractStartDate我认为问题在于在循环中检索合同的查询。最好用一个这样的查询检索所有数据:

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);
}
var date=DateTime.Today;
变量查询=
来自上下文中的客户
其中customer=>customer.IsEnabled
选择新的
{
顾客

contract=customer.Contracts.FirstOrDefault(c=>c.ContractEndDate>=date&&c.ContractStartDate由于我不知道域模型结构是什么样子,也不知道为什么不使用导航属性将当前合同映射到客户,所以可以这样做

通过具体化所有客户和合同,然后将它们映射到内存中的DTO对象,您可以对数据库进行两次往返。假设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);
}
列表结果=新列表();
customers=context.customers.Where(c=>c.IsEnabled.ToList();
contracts=context.contracts.Where(c=>c.ContractEndDate>=DateTime.Today&&c.ContractStartDate c.CustomerId==customer.Id).FirstOrDefault();
如果(合同!=null)
{
SETCONTACT(customerDto,合同);
}
结果。添加(customerDto);
}

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

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

我在创建CustomerOverviewDto时直接检索合同,以显示生成的SQL queryCustomer表包含36列(Varchar和Int)还有14478行。你真的需要列的名称吗?我想看看ORM Generate query是如何运行的,也许它效率很低。顺便问一下,确保你的查询没有被另一个事务阻塞。你有IsEnabled、ContractEndDate和ContractStartDate的索引吗?还有,SetContract做什么?这些信息非常有用重要的是要理解为什么查询不可用efficient@lad2025如何查看生成的查询?在visual studio中?他遍历
客户
,而不是
结果
。懒散在这段代码中不会给他带来任何好处。好的,很好,但结果仍然包含每一行(工作已经完成,数据由.toList()返回到变量),我们不知道客户是如何填充的。但是,OP写道:“…我必须检索所有启用的客户…”没有办法避免加载作为输出一部分的所有数据。使用快速加载可能有用,但我们需要更多信息来给出有用的答案。是的,我同意,我们需要了解客户是如何填充的。很好,我需要冒烟!呃,他的帖子刚将结果更改为Customer我无法在第一时间创建Customer Overview查询是因为我需要检索不在CustomerOverview中的客户合同,或者您不需要更改客户实现,只需查询即可。请参阅我的编辑示例。错误。我必须检索所有客户,即使他们没有代码中不清楚的当前合同,但是当您包含合同时,它会被删除将减少到数据库的往返次数。我不能在where之后打电话给Include