我从单个视图查询以检索指标列表。可以从该单个视图中检索指标的所有属性。
以下是代码:
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循环时变慢。 有没有办法让这个查询更快地转换为列表?谢谢。
答案 0 :(得分:4)
看起来你正在进行大量不必要的嵌套查询。
您的core
查询在返回项目之前正在进行一些相对昂贵的过滤和排序。最好只执行一次此查询。
但是,您在此查询中执行了六次不必要的连接。
例如,您的查询Genders
正在重新查询core
,只保留您已经分组的IndicatorId
项目!如果我可以假设item.Indicator
与item.IndicatorId
一对一,则您的论坛indicator
已经包含此子集。
您正在查询AreaTypes
&amp; Sectors
以同样的方式。
现在HasGender
,HasAreaType
和&amp; 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
和&amp;仅Sectors
一次,并将每个创建为列表。这允许我更改x
以立即生成Indicator
的实例。
现在indicators
列表的最终创建很简单:
var indicators = x.ToList();
当我在这个方法上使用我的样本数据时,结果如下:
counter == 100
这意味着此查询只会触及原始core
一次查询!
然后我检查了当我将原始样本数据增加到1,000个项目时嵌套的行为 - 我使用新代码获得了一次点击,使用原始代码获得了6,001次点击 - 并且它变得更快,更慢。
请记住,LINQ是懒惰计算的,因此在您定义查询的地方不会执行执行,而是执行它的位置。
所以这里的建议是,在内存允许的情况下,您应该尽快执行查询,将数据存入内存,然后执行一次计算。
答案 1 :(得分:0)
对于初学者,更改每个Count()&gt; 0进入Any()方法,Count将强制完全扫描您正在查询的表。
如果这不能为您提供所需的性能提升,请尝试重写您的查询。我认为,如果您首先将数据投影到匿名类型,那么性能会更高,而然后按匿名类型分组。
答案 2 :(得分:0)
您的查询中有一些where子句(例如,s.IndicatorId == indicator.Key.IndicatorId)
尝试在此处使用加入语法,这将使其更快。 即您的案例中的核心连接指标。
之类的东西您的
版本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.IndicatorId