【发布时间】:2023-03-19 10:13:01
【问题描述】:
我正在处理另一家公司的项目,该公司开发了一种使用 Entity Framework 6 从数据库中检索信息的方法,以填充网格组件。
我们在使用这种方法时面临着巨大的性能问题,即使我们只有几行,比如 70、100 等。我只是不知道该怎么做。
如果您能告诉我正确的方法,我将不胜感激。
一些信息: 视觉工作室 2013 .NET 4.5 SQL Server 2017
这个方法:
[HttpPost]
public object RetornaRelatorioEnvioSms(RetornaRelatorioEnvioSmsRequestModel model)
{
try
{
using (ctx = new SebraeContainer())
{
ctx.Configuration.LazyLoadingEnabled = false;
ctx.Configuration.ProxyCreationEnabled = false;
ctx.Configuration.AutoDetectChangesEnabled = false;
decimal cpfDecimal = string.IsNullOrWhiteSpace(model.CPF) ? decimal.Zero : decimal.Parse(model.CPF.Replace(".", string.Empty).Replace("-", string.Empty));
decimal cnpjDecimal = string.IsNullOrWhiteSpace(model.CNPJ) ? decimal.Zero : decimal.Parse(model.CNPJ.Replace(".", string.Empty).Replace("-", string.Empty));
string query = "select d.id_diagnostico idDiagnostico " +
" , ppf.nm_razao_social nomeCliente " +
" , sx.nm_descricao sexo " +
" , CONVERT(VARCHAR, d.dt_fim, 103) dataAtendimento " +
" , r.nm_regiao regional " +
" , cem.nm_numero email " +
" , cel.nm_numero celular " +
" , p.nm_nome porte " +
" , u.nm_completo agente " +
" from tb_diagnostico d " +
" left join tb_parceiro ppf on ppf.id_parceiro = d.id_parceiropf " +
" left join tb_parceiro ppj on ppj.id_parceiro = d.id_parceiropj " +
" left join tb_pessoa_fisica pf on pf.id_parceiro = ppf.id_parceiro " +
" left join tb_pessoa_juridica pj on pj.id_parceiro = ppj.id_parceiro " +
" left join tb_sexo sx on pf.id_sexo = sx.id_sexo " +
" left join tb_acao_regiao acr on d.id_acao = acr.id_acao " +
" left join tb_regiao r on acr.id_regiao = r.id_regiao " +
" left join tb_comunicacao cem on ppf.id_parceiro = cem.id_parceiro " +
" left join tb_comunicacao cel on ppf.id_parceiro = cel.id_parceiro " +
" left join tb_porte p on pj.id_porte = p.id_porte " +
" left join tb_usuario u on d.id_usuario = u.id_usuario " +
" where " +
" exists (select 1 " +
" from tb_historico_envio_sms_sse " +
" where id_diagnostico = d.id_diagnostico " +
" and id_tipo_mensagem_envio = 4)" +
" and d.dt_fim is not null " +
" and d.id_sistema = " + DatabaseIDs.IdSistemaSSE + " " +
" and cem.id_tipo_comunicacao = " + DatabaseIDs.IdTipoComunicacaoEmail + " " +
" and cel.id_tipo_comunicacao = " + DatabaseIDs.IdTipoComunicacaoTelefoneCelular + " ";
if (model.DataInicio != DateTime.MinValue)
query = query + " and d.dt_fim >= CONVERT(DATETIME, '" + model.DataInicio.ToString("yyyy-MM-ddT00:00:00", new CultureInfo("pt-BR")) + "', 126)";
if (model.DataFinal != DateTime.MinValue)
query = query + " and d.dt_fim <= CONVERT(DATETIME, '" + model.DataFinal.ToString("yyyy-MM-ddT23:59:59", new CultureInfo("pt-BR")) + "', 126)";
if (!string.IsNullOrWhiteSpace(model.Nome))
query = query + " and ppf.nm_razao_social like '%" + model.Nome.Replace("'", string.Empty) + "%' ";
if (!string.IsNullOrWhiteSpace(model.CPF))
query = query + " and ppf.nu_CGCCPF = " + cpfDecimal + " ";
if (model.Sexo.HasValue)
query = query + " and pf.id_sexo = " + model.Sexo.Value + " ";
if (!string.IsNullOrWhiteSpace(model.RazaoSocial))
query = query + " and ppj.nm_razao_social like '%" + model.RazaoSocial.Replace("'", string.Empty) + "%' ";
if (!string.IsNullOrWhiteSpace(model.CNPJ))
query = query + " and ppj.nu_CGCCPF = " + cnpjDecimal + " ";
if (model.Porte != null && model.Porte.Any())
query = query + " and pj.id_porte in (" + String.Join(",", model.Porte.Select(idporte => idporte.ToString())) + ") ";
if (model.Perfil != null && model.Perfil.Any())
query = query + " and d.id_perfil in (" + String.Join(",", model.Perfil.Select(idperfil => idperfil.ToString())) + ") ";
if (model.Regional != null && model.Regional.Any())
query = query + " and r.id_regiao in (" + String.Join(",", model.Regional.Select(idregiao => idregiao.ToString())) + ") ";
if (model.CNAE != null && model.CNAE.Any())
query = query + " and exists (select 1 " +
" from (select DISTINCT " +
" REPLICATE('0', 2 - LEN(cd_class)) + CONVERT(VARCHAR, cd_class) " +
" + REPLICATE('0', 5 - LEN(cd_atividade)) + cd_atividade " +
" + REPLICATE('0', 2 - LEN(id_cnaefiscal)) + id_cnaefiscal cnae " +
" from tb_diagnosticoCNAE " +
" where id_diagnostico = d.id_diagnostico) dc " +
" where dc.cnae in ('" + String.Join("', '", model.CNAE.Select(cnae => cnae)) + "'))";
if (model.Setor != null && model.Setor.Any())
query = query + " and exists (select 1 " +
" from tb_diagnosticoCNAE dc " +
" join tb_atividade_economica atv on dc.cd_atividade = atv.ds_codAtivEcon and dc.cd_class = atv.cd_class " +
" where dc.id_diagnostico = d.id_diagnostico " +
" and atv.id_setor_economico in (" + String.Join(",", model.Setor.Select(idsetor => idsetor.ToString())) + "))";
if (model.Tematica != null && model.Tematica.Any())
query = query + " and exists (select 1 " +
" from tb_diagnosticoperfiltema dpt " +
" join tb_perfiltema pt on dpt.id_perfiltema = pt.id_perfiltema " +
" join tb_tema t on pt.id_tema = t.id_tema " +
" where dpt.id_diagnostico = d.id_diagnostico " +
" and t.id_tema in (" + String.Join(",", model.Tematica.Select(idtema => idtema.ToString())) + "))";
if (model.Nivel != null && model.Nivel.Any())
query = query + " and exists (select 1 " +
" from tb_diagnosticoperfiltema " +
" where id_diagnostico = d.id_diagnostico " +
" and id_nivel in (" + String.Join(",", model.Nivel.Select(idnivel => idnivel.ToString())) + "))";
if (model.Agente != null && model.Agente.Any())
query = query + " and exists (select 1 " +
" from tb_usuario_sse " +
" where id_usuario = d.id_usuario " +
" and id_agente in (" + String.Join(",", model.Agente.Select(idagente => idagente.ToString())) + "))";
ctx.Database.CommandTimeout = 60;
IEnumerable<RetornaRelatorioEnvioSmsModel> ret = ctx.Database.SqlQuery<RetornaRelatorioEnvioSmsModel>(query).ToList();
if (ret.Any())
{
foreach (RetornaRelatorioEnvioSmsModel item in ret)
{
item.formasContato = (from d in ctx.tb_diagnostico.AsNoTracking()
where d.id_diagnostico == item.idDiagnostico
from fc in d.tb_parceiro.tb_tipo_forma_contato
select new RetornaRelatorioEnvioSmsFormaContatoModel
{
formaContato = fc.nm_tipo_forma_contato
}).ToList();
item.temas = (from d in ctx.tb_diagnostico.AsNoTracking()
where d.id_diagnostico == item.idDiagnostico
from dpt in d.tb_diagnosticoperfiltema
select new RetornaRelatorioEnvioSmsTemaModel
{
tema = dpt.tb_perfiltema.tb_tema.nm_tema,
nivel = dpt.tb_nivelmaturidade.nm_nivel
}).ToList();
item.temaPrioritario = (from d in ctx.tb_diagnostico.AsNoTracking()
where d.id_diagnostico == item.idDiagnostico
from dpt in d.tb_diagnosticoperfiltema
orderby dpt.nu_pontuacao descending, dpt.tb_perfiltema.nu_prioridade ascending
select new RetornaRelatorioEnvioSmsTemaModel
{
tema = dpt.tb_perfiltema.tb_tema.nm_tema,
nivel = dpt.tb_nivelmaturidade.nm_nivel
}).FirstOrDefault();
}
}
return ret;
}
}
catch (Exception)
{
throw;
}
}
【问题讨论】:
-
慢到底是什么?您是否在 SQL Server Management Studio 上运行查询以确定查询是否需要时间或您的代码?
-
1.您的代码对 SQL 注入开放,请改用参数 2. 为什么要将 Linq 与 SQL 混合使用? 3.
ctx.Database.SqlQuery<RetornaRelatorioEnvioSmsModel>(query).ToList();正在具体化(返回)来自query的所有数据。之后的所有内容都经过客户端评估。您可能想使用Skip和Take。 -
执行的
query的值是多少?在 Management Studio 中运行需要多长时间?在 C# 中需要多长时间(到达if (ret.Any())行)? -
您正在执行一个查询,然后,对于每个结果,您再执行三个查询。这是很多个人查询。加快速度的一个选项是,在第一个查询之后,获取一个列表 ID,然后使用它总共执行三个查询,以将所有相关数据放在一起而不是分开。这将意味着访问数据库的次数大大减少,从而减少开销。然后,您仍然需要一个循环来将相关数据附加到初始实体,但这会更快,而不必为每个实体访问数据库三次。
-
错误的工作工具。 EF 是一个 ORM。如果您想在代码中使用嵌入式查询(另一个话题),那么请使用经典的非 ORM 框架
标签: c# performance entity-framework linq entity-framework-6