简体   繁体   English

Npgsql中的重复联接具有相同的导航属性

[英]Duplicated joins in Npgsql for the same navigation property

This question already exists here , but for Entity Framework to TSQL 这个问题已经存在在这里 ,但对于实体框架TSQL

When using the same navigation property multiple times on a select, Npgsql query results in multiple joins, one for every use of the navigation property. 当对一个选择多次使用相同的导航属性时,Npgsql查询会导致多个联接,每次使用导航属性都会产生一个联接。 This result in an awful performance hit (tested) 这会导致性能下降(经过测试)

I've read that this is a problem with EF 4, but this problem also occurs on EF 6. 我已经读到这是EF 4的问题,但是在EF 6上也会发生此问题。

I think that this is an issue with the Npgsql LINQ to SQL translator 我认为这是Npgsql LINQ to SQL转换器的问题

This is the code that Npgsql generate for the same navigation property used mutliple times, obviously, only one join is needed (copied from the other questions because is exactly the same case) 这是Npgsql为使用多个时间的相同导航属性生成的代码,显然,只需要一个联接(从其他问题复制,因为情况完全相同)

LEFT OUTER JOIN [dbo].[Versions] AS [Extent4] ON [Extent1].[IDVersionReported] = [Extent4].[ID]
LEFT OUTER JOIN [dbo].[Versions] AS [Extent5] ON [Extent1].[IDVersionReported] = [Extent5].[ID]
LEFT OUTER JOIN [dbo].[Versions] AS [Extent6] ON [Extent1].[IDVersionReported] = [Extent6].[ID]
LEFT OUTER JOIN [dbo].[Versions] AS [Extent7] ON [Extent1].[IDVersionReported] = [Extent7].[ID]

Is it posible to tune PostgreSql to optimize repeated joins? 是否可以调整PostgreSql以优化重复连接?

If not, which option is the best for solving this problem? 如果没有,哪个选项最适合解决此问题?

  • Wait until Npgsql gets fixed 等待Npgsql修复
  • Download Npgsql code and find the way to fix it 下载Npgsql代码并找到解决方法
  • Intercept generated SQL before reaching the database, parse it, and remove duplicated joins. 在到达数据库之前拦截生成的SQL,对其进行解析,然后删除重复的联接。 (Read here ) 在这里阅读)
  • Do not use navigation properties, use LINQ joins instead 不要使用导航属性,而是使用LINQ联接

Indeed, this is a problem of Entity Framework, but I found a workaround, hope that this helps someone. 确实,这是Entity Framework的问题,但是我找到了一种解决方法,希望这对某人有所帮助。

This was the original where part of the LINQ query: 这是原来where的LINQ查询的一部分:

 from cr in Creditos
 where cr.validado == 1 &&
 cr.fecharegistro >= Desde &&
 cr.fecharegistro <= Hasta &&
 !ProductosExcluidos.Contains(cr.idproducto.Value) &&
 cr.amortizaciones.Sum(am => am.importecapital - am.pagoscap - am.capcancel) > 1

 //All references to the navigation property cr.numcliente
 //results on a separated LEFT OUTTER JOIN between this the 'creditos' and 'clientes' tables
 select new ArchivoCliente
 {
    RFC = cr.numcliente.rfc,
    Nombres = cr.numcliente.nombres,
    ApellidoPaterno = cr.numcliente.apellidopaterno,
    ApellidoMaterno = cr.numcliente.apellidomaterno,
 }

Note the last condition of the where, that condition does a sum of all child entities of cr , if we take out that last condition, all the duplicated LEFT OUTTER JOIN are replaced by one single JOIN , for some reason, Entity Framework doesn't like subqueries or aggregates on the where part of the query 请注意where的最后一个条件,该条件对cr的所有子实体求和,如果我们取出该最后一个条件,则所有重复的LEFT OUTTER JOIN都将被一个JOIN替换,出于某种原因,Entity Framework不会如查询的where部分的子查询或聚合

If instead we replace the original query with this other equivalent query only a single LEFT OUTTER JOIN is generated. 如果相反,我们用其他等效查询替换了原始查询,则仅生成一个LEFT OUTTER JOIN

 (from cr in Creditos
 where cr.validado == 1 &&
 cr.fecharegistro >= Desde &&
 cr.fecharegistro <= Hasta &&
 !ProductosExcluidos.Contains(cr.idproducto.Value) &&
 //Excluded aggregate function condition from the first where
 //the value is now on the select and used for posterior filtering

 select new ArchivoCliente
 {
    RFC = cr.numcliente.rfc,
    Nombres = cr.numcliente.nombres,
    ApellidoPaterno = cr.numcliente.apellidopaterno,
    ApellidoMaterno = cr.numcliente.apellidomaterno,
    SumaAmort = cr.amortizaciones.Sum(am => am.importecapital - am.pagoscap - am.capcancel)
 }).Where (x => x.SumaAmort > 1);

Now instead of directly filtering on the first where statement, the aggregate result is stored as part of the projection, and then, a second where is applied to the resulting query. 现在,不是直接对第一个where语句进行过滤,而是将汇总结果存储为投影的一部分,然后将第二个where应用于结果查询。

This results in a much faster query, with only the necessary joins on the translated SQL statement. 这将导致查询速度大大提高,只对翻译后的SQL语句进行必要的联接。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM