我是C#的新手,我正在使用Linq对c#中的数据表进行一些操作。我的方法大约需要35秒才能完成处理。有人可以建议如何改善表现吗?
此方法的输入DataTable有35个KPI,每个KPI将为每个会计年度和foreach国家/地区提供13个月的数据。因此,每个会计年度,dt将有35 * 13 = 455条记录。无论如何,将有2个财政年度。所以455 * 2 =每个国家900条记录。因此,我们在输入数据表中记录的记录数小于1000
void NeedtoImprovePerformance(DataTable dt)
{
DataView dv = dt.DefaultView;
dv.Sort = "Fiscal_Year ASC";
dt = dv.ToTable();
var kpilist = from table in dt.AsEnumerable()
orderby table.Field<int>("Sub_Service_Type_Id")
group table by new { kpiName = table["KpiName"] } into groupby
select new
{
value = groupby.Key,
columnvalues = groupby
};
var uniqueCountry = from table in dt.AsEnumerable()
group table by new { country = table["CountryName"] } into groupby
select new
{
value = groupby.Key,
columnValues = groupby
};
foreach (var kpi in kpilist)
{
var KpiValues = from table in dt.AsEnumerable()
where table.Field<string>("KpiName") == kpi.value.kpiName.ToString()
select table;
foreach (var countryName in uniqueCountry)
{
var availablePeriods = from table in dt.AsEnumerable()
where table.Field<string>("KpiName").ToString() == kpi.value.kpiName.ToString() &&
table.Field<string>("CountryName").ToString() == countryName.value.country.ToString()
select table.Field<int>("Period").ToString();
if (availablePeriods.Count() < 13 && availablePeriods.Count() > 0)
{
for (int period = 5; period < 17; period++)
{
DataRow dr = dt.NewRow();
if (!availablePeriods.ToList().Contains(period.ToString()))
{
dr[1] = KpiValues.ToList()[0]["KpiName"].ToString();
dr[2] = countryName.value.country.ToString();
dr[3] = (period).ToString();
var availableFiscalYear = from table in dt.AsEnumerable()
where table.Field<int>("Period").ToString() == period.ToString()
select table.Field<string>("Fiscal_Year").ToString();
if (availableFiscalYear == null || availableFiscalYear.Count() == 0)
{
if (ddlFiscalYear.SelectedItem.Text == ddlFiscalYear.Items[ddlFiscalYear.Items.Count - 1].Text)
{
if (period > 10)
dr[4] = ddlFiscalYear.SelectedValue.ToString();
else
dr[4] = (Convert.ToInt32(ddlFiscalYear.SelectedValue) - 1).ToString();
if (period == Convert.ToInt32(ddlMonth.SelectedValue) || period < Convert.ToInt32(ddlMonth.SelectedValue))
dr[4] = (Convert.ToInt32(ddlFiscalYear.SelectedValue) + 1).ToString();
}
else
{
if (period > Convert.ToInt32(ddlMonth.SelectedValue))
dr[4] = (Convert.ToInt32(ddlFiscalYear.SelectedValue) - 1).ToString();
else
{
if (period == Convert.ToInt32(ddlMonth.SelectedValue))
dr[4] = (Convert.ToInt32(ddlFiscalYear.SelectedValue) + 1).ToString();
else
dr[4] = ddlFiscalYear.SelectedValue.ToString();
}
}
}
else
{
dr[4] = availableFiscalYear.ToList()[0].ToString();
}
dr[5] = "";
dr[6] = KpiValues.ToList()[0]["Frequency"].ToString();
dr[7] = KpiValues.ToList()[0]["Sub_Service_Type_Id"].ToString();
dr[8] = KpiValues.ToList()[0]["Service_Type_Id"].ToString();
dr[9] = KpiValues.ToList()[0]["ServiceName"].ToString();
dr[10] = KpiValues.ToList()[0]["OrderBy"];
dt.Rows.Add(dr);
}
if (ddlMonth.SelectedValue == period.ToString())
{
var selectedPeriod = availablePeriods.Where(k => k == ddlMonth.SelectedValue).ToList();
if (selectedPeriod != null && selectedPeriod.Count == 1)
{
var PeriodFiscalYear = from table in dt.AsEnumerable()
where table.Field<string>("KpiName").ToString() == kpi.value.kpiName.ToString() &&
table.Field<string>("CountryName").ToString() == countryName.value.country.ToString()
&& table.Field<int>("Period") == period
select table.Field<string>("Fiscal_Year");
dr = null;
dr = dt.NewRow();
dr[1] = KpiValues.ToList()[0]["KpiName"].ToString();
dr[2] = countryName.value.country.ToString();
dr[3] = (period).ToString();
var availableFiscalYear = from table in dt.AsEnumerable()
where table.Field<int>("Period").ToString() == period.ToString() &&
table.Field<string>("Fiscal_Year").ToString() != PeriodFiscalYear.ToList()[0]
select table.Field<string>("Fiscal_Year").ToString();
if (availableFiscalYear == null || availableFiscalYear.Count() == 0)
{
if (ddlFiscalYear.SelectedItem.Text == ddlFiscalYear.Items[ddlFiscalYear.Items.Count - 1].Text)
{
if (period > 10)
dr[4] = ddlFiscalYear.SelectedValue.ToString();
else
dr[4] = (Convert.ToInt32(ddlFiscalYear.SelectedValue) - 1).ToString();
if (period == Convert.ToInt32(ddlMonth.SelectedValue) || period < Convert.ToInt32(ddlMonth.SelectedValue))
dr[4] = (Convert.ToInt32(ddlFiscalYear.SelectedValue) + 1).ToString();
}
else
{
if (period > Convert.ToInt32(ddlMonth.SelectedValue))
dr[4] = (Convert.ToInt32(ddlFiscalYear.SelectedValue) - 1).ToString();
else
{
if (period == Convert.ToInt32(ddlMonth.SelectedValue))
dr[4] = (Convert.ToInt32(ddlFiscalYear.SelectedValue) + 1).ToString();
else
dr[4] = ddlFiscalYear.SelectedValue.ToString();
}
}
}
else
{
dr[4] = availableFiscalYear.ToList()[0].ToString();
}
dr[5] = "";
dr[6] = KpiValues.ToList()[0]["Frequency"].ToString();
dr[7] = KpiValues.ToList()[0]["Sub_Service_Type_Id"].ToString();
dr[8] = KpiValues.ToList()[0]["Service_Type_Id"].ToString();
dr[9] = KpiValues.ToList()[0]["ServiceName"].ToString();
dr[10] = KpiValues.ToList()[0]["OrderBy"];
dt.Rows.Add(dr);
}
}
}
}
}
}
dv = dt.DefaultView;
dv.Sort = "KpiName ASC, Fiscal_Year ASC, Sub_Service_Type_Id ASC";
dt = dv.ToTable();
}
由于
答案 0 :(得分:1)
该代码示例中存在许多性能问题。一些改进:
dt.AsEnumerable()
移到var table = dt.AsEnumerable()
这两个循环之外,然后再使用.ToList()
上的KpiValues
移至第一个foreach并使用结果列表availablePeriods
次(2次.Count()
,2次.ToList()
),您可以通过拨打.ToList()
一次并在所有位置使用该列表来改进一般情况下:尝试尽可能少地查询。变量KpiValues
和availablePeriods
不是事物列表,而是查询定义。每次从中获取一些数据时,它将执行查询以获取数据,而不是重复使用您可能期望的先前结果。