我从单个视图进行查询,以检索指标列表。指示器的所有属性都可以从该单个视图中检索到。
代码如下:
data = new DataContext();
var core = from item in data.Items
where countryIDs.Contains(item.CountryId)
&& indicatorIDs.Contains(item.IndicatorId)
orderby item.Indicator
select item;
var x = from item in core.Distinct()
group item by new { item.IndicatorId, item.Indicator }
into indicator
select new
{
IndicatorID = indicator.Key.IndicatorId,
IndicatorDescription = indicator.Key.Indicator,
Genders = from g in core
where g.Gender != null
&& g.IndicatorId == indicator.Key.IndicatorId
select new Gender
{
GenderID = g.GenderId,
GenderDescription = g.Gender
},
HasGender = (from g in core
where g.Gender != null
&& g.IndicatorId == indicator.Key.IndicatorId
select g.GenderId).Count() > 0,
AreaTypes = from rat in core
where rat.IndicatorId == indicator.Key.IndicatorId
&& rat.AreaType != null
select new AreaType
{
AreaTypeId = rat.AreaTypeId,
AreaDescription = rat.AreaType
},
HasAreaType = (from rat in core
where rat.IndicatorId == indicator.Key.IndicatorId
&& rat.AreaType != null
select rat.AreaTypeId).Count() > 0,
Sectors = from s in core
where s.IndicatorId == indicator.Key.IndicatorId
&& s.Sector != null
select new Sector
{
SectorID = s.SectorId,
Title = s.Sector
},
HasSector = (from s in core
where s.IndicatorId == indicator.Key.IndicatorId
&& s.Sector != null
select s.SectorId).Count() > 0
};
List<Indicator> indicators = new List<Indicator>();
Indicator i = new Indicator();
foreach (var item in x)
{
i = new Indicator()
{
IndicatorID = item.IndicatorID,
IndicatorDescription = item.IndicatorDescription,
Genders = item.Genders.ToList(),
AreaTypes = item.AreaTypes.ToList(),
Sectors = item.Sectors.ToList(),
HasGender = item.HasGender,
HasAreaType = item.HasAreaType,
HasSector = item.HasSector
};
indicators.Add(i);
}
return indicators;当x被转换时,当它到达foreach循环时,它会变慢。有没有什么方法可以让这个查询更快地转换成列表?谢谢。
发布于 2012-06-26 15:43:01
看起来你做了很多不必要的嵌套查询。
您的core查询在返回项目之前执行一些相对开销较大的过滤和排序。最好只执行该查询一次。
但是,您在此查询中返回执行了6个不必要的连接。
例如,您的查询Genders正在重新查询core,并且只保留与您已经分组的IndicatorId相同的项目!如果我可以假设item.Indicator在item.IndicatorId上是一对一的,那么您的组indicator已经包含了这个子集。
您正在以同样的方式查询AreaTypes & Sectors。
现在,HasGender、HasAreaType和HasSector中的每一个都重复上面的查询,并强制对它们中的每一个执行.Count(),以检查该值是否大于零。这是一种浪费,因为.Any()将为您检查至少一个值,成本要低得多。
现在,为了测试core查询被访问了多少次,我创建了以下测试代码:
var countryIDs = Enumerable.Range(0, 100).ToArray();
var indicatorIDs = Enumerable.Range(0, 100).ToArray();
data.Items.AddRange(
Enumerable
.Range(0, 100)
.Select(n =>
new Item()
{
CountryId = n,
IndicatorId = n,
Indicator = "Indicator",
GenderId = n,
Gender = "Gender",
AreaTypeId = n,
AreaType = "Area",
SectorId = n,
Sector = "Sector",
}));我修改了core,使其如下所示:
var counter = 0;
var core =
(from item in data.Items
where countryIDs.Contains(item.CountryId)
&& indicatorIDs.Contains(item.IndicatorId)
orderby item.Indicator
select item).Do(_ => counter++);Do操作符来自Reactive Extensions System.Interactive程序集。
运行你的代码,我得到了以下结果:
counter == 60100由于我已经在集合中放置了100个条目,这告诉我您的查询正在调用core的新执行601次!
可以很容易地将其更改为执行一次core。
首先,我将core修改为如下所示:
var query =
from item in data.Items
where countryIDs.Contains(item.CountryId)
&& indicatorIDs.Contains(item.IndicatorId)
orderby item.Indicator
select item;
var core = query.ToArray();.ToArray()将查询结果放入内存。
然后,将x查询修改为如下所示:
var x =
from item in core.Distinct()
group item by new
{
item.IndicatorId,
item.Indicator
} into indicator
let Genders = (
from g in indicator
where g.Gender != null
select new Gender
{
GenderID = g.GenderId,
GenderDescription = g.Gender,
}).ToList()
let AreaTypes = (
from rat in indicator
where rat.AreaType != null
select new AreaType
{
AreaTypeId = rat.AreaTypeId,
AreaDescription = rat.AreaType,
}).ToList()
let Sectors = (
from s in indicator
where s.Sector != null
select new Sector
{
SectorID = s.SectorId,
Title = s.Sector,
}).ToList()
select new Indicator()
{
IndicatorID = indicator.Key.IndicatorId,
IndicatorDescription = indicator.Key.Indicator,
Genders = Genders,
AreaTypes = AreaTypes,
Sectors = Sectors,
HasGender = Genders.Any(),
HasAreaType = AreaTypes.Any(),
HasSector = Sectors.Any(),
};注意,我只计算了一次Genders、AreaTypes和Sectors,并将它们创建为一个列表。这允许我更改x以立即生成Indicator的实例。
现在,indicators列表的最终创建非常简单:
var indicators = x.ToList();当我在这个方法上使用我的样本数据时,我的结果是:
counter == 100这意味着这个查询只命中了原始core查询一次!
然后,当我将原始样本数据增加到1000个项目时,我检查了嵌套的行为-新代码只有一次命中,原始代码有6,001次命中-而且速度要慢得多。
请记住,LINQ是延迟计算的,因此执行不会发生在定义查询的位置,而会发生在执行查询的位置。
因此,这里的建议是,在内存允许的情况下,您应该尽可能快地执行查询,以便将数据放入内存中,然后执行一次且仅执行一次计算。
发布于 2012-06-26 14:07:04
对于初学者,将table Count() >0更改为Any()方法,Count将强制对正在查询的表进行完全扫描。
如果这不能给你带来你想要的性能提升,试着重写你的查询。我认为如果您首先将数据投影到您的匿名类型中,然后按该匿名类型进行分组,则性能会更高。
发布于 2012-06-26 14:09:50
查询中有一些where子句(例如where s.IndicatorId == indicator.Key.IndicatorId)
尝试在这里使用Join语法,这将使它更快。即您的案例中的核心连接指示器。就像这样
您的版本
from g in core
where g.Gender != null && g.IndicatorId == indicator.Key.IndicatorId会得到像这样的东西
From g In core Join indi In indicator
on g.IndicatorId Equals indi.Key.IndicatorIdhttps://stackoverflow.com/questions/11201472
复制相似问题