gpt4 book ai didi

c# - 使用 IQueryable 和自定义函数时优化对数据库的访问次数

转载 作者:太空宇宙 更新时间:2023-11-03 21:54:32 26 4
gpt4 key购买 nike

在我的C# 类库项目 中,我有一个方法需要计算一些统计信息GetFaultRate , 给定一个 date , 计算有缺陷的产品数量超过生产的产品数量。

float GetFaultRate(DateTime date)
{
var products = GetProducts(date);
var faultyProducts = GetFaultyProducts(date);

var rate = (float) (faultyProducts.Count() / products.Count());

return rate;
}

两种方法,GetProductsGetFaultyProductsRepository 类中获取数据 _productRepository .

IEnumerable<Product> GetProducts(DateTime date)
{
var products = _productRepository.GetAll().ToList();

var periodProducts = products.Where(p => CustomFunction(p.productionDate) == date);

return periodProducts;
}

IEnumerable<Product> GetFaultyProducts(DateTime date)
{
var products = _productRepository.GetAll().ToList();

var periodFaultyProducts = products.Where(p => CustomFunction(p.ProductionDate) == date && p.Faulty == true);

return periodFaultyProducts;
}

在哪里GetAll有签名:

IQueryable<Product> GetAll();

数据库中的产品很多,检索和转换需要很多时间ToList() .我需要枚举集合,因为任何自定义函数,如 CustomFunction , 无法在 IQueryable<T> 中执行.

我的应用卡了很久才得到故障率。我猜是因为要检索的对象很多。我确实可以删除这两个功能 GetProductsGetFaultyProducts并实现 GetFaultRate 中的逻辑.但是因为我有其他使用 GetProducts 的函数和 GetFaultyProducts ,对于后一种解决方案,我只有一个数据库访问权限,但有很多重复代码。

什么是好的妥协?

最佳答案

首先,不要将 IQueryable 转换为列表。它强制将整个数据集一次性全部存入内存,而不是直接在查询上调用 Where,这样您就可以在数据传入时对其进行过滤。这将显着 减少您的内存占用,并(非常)略微提高运行速度。如果您需要将 IQueryable 转换为 IEnumerable 以便数据库不执行 Where,只需使用 AsEnumerable.

接下来,获取所有数据是您应该尽可能避免的事情,尤其是多次。您需要向我们展示您的日期函数的作用,但它可能是可以在数据库上完成的事情。您可以在数据库中执行的任何过滤都将显着提高性能。

接下来,您真的不需要这里的两个查询。第二个查询只是第一个查询的一个子集,所以如果您知道您将始终使用这两个查询,那么您应该只执行第一个查询,将结果存入内存(即使用ToList 您存储的)然后使用 Where 进一步过滤结果。这将避免另一次数据库访问以及所有数据处理/过滤。

如果您不会总是使用这两个查询,但有时会只使用一个或另一个,那么您可以通过在获取所有项目之前过滤掉 Faulty 来改进第二个查询。添加 Where(p => p.Faulty) 在调用 AsEnumerable 之前 并在调用之后 过滤日期信息AsEnumerable(如果您无法将任何日期过滤转换为可以在数据库中完成的过滤)。

看来最后您只需要计算有缺陷的项目与总数的比率。这可以通过单个查询轻松完成,而不是两个。

您曾说过 Count 在您的代码中运行得非常慢,但事实并非如此。 Count 只是实际枚举查询的方法,而所有其他方法只是构建查询,而不是执行查询。但是,您可以通过完全组合查询来大幅降低性能成本。

var lookup = _productRepository.GetAll()
.AsEnumerable()//if at all possible, try to re-write the `Where`
//to be a valid SQL query so that you don't need this call here
.Where(p => CustomFunction(p.productionDate) == date)
.ToLookup(product => product.Faulty);

int totalCount = lookup[true].Count() + lookup[false].Count();
double rate = lookup[true].Count() / (double) totalCount;

关于c# - 使用 IQueryable<T> 和自定义函数时优化对数据库的访问次数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12820939/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com