2012-12-28 10 views
5

Io corro in un problema con il seguente: pseudoquerydue simili query LINQ, completamente diverso SQL generato

var daily = from p in db.table1 
      group p by new 
      { 
       key1, 
       key2 
      } into g 
      join d in db.table2 
      on new { p.key1, p.key2 } equals { d.key1, d.key2 } 
      select new 
      { 
       col1 = g.Key.key1 
       col2 = g.Sum(a => a.column2) 
       col3 = d.column3 
      }; 

Si corre, ma l'istruzione SQL generata che LINQ invia a SQL Server è assurdo. L'implementazione effettiva segue una configurazione simile a quella precedente con 7 o più colonne che hanno ciascuna un calcolo .Sum(). L'SQL generato ha da qualche parte circa 10-11 istruzioni SELECT nidificate con nessun JOIN INNER e, ovviamente, impiega un'eternità per essere eseguito.

Ho provato un'altra implementazione della query:

var daily = from p in 
       (from p in db.table1 
       group p by new 
       { 
        key1, 
        key2 
       } into g 
       select new 
       { 
        col1 = g.Key.key1, 
        col2 = g.Sum(a => a.column2) 
       }) 
      join d in db.table2 
      on new { p.key1, p.key2 } equals new { d.key1, d.key2 } 
      select new 
      { 
       col1 = p.col1, 
       col2 = p.col2, 
       col3 = d.column3 
      }; 

Questa versione genera molto più ragionevole SQL con un singolo SUB-SELECT e un INNER JOIN (funziona anche dannatamente vicino all'istante). La cosa che odio di questo è che la prima query LINQ è, IMHO, molto più diretta e concisa mentre la seconda sembra piuttosto ridondante poiché finisco per dover definire tutte le colonne che voglio da table1 due volte.

Perché queste due query simili funzionano in maniera così diversa sul server e perché la query 2 risulta molto più efficiente anche se il codice è molto meno espressivo?

C'è un modo per riscrivere la prima query per essere efficiente come la seconda?

+0

È possibile pubblicare l'SQL di entrambe le versioni? – usr

+0

@usr Certo, provami a ripulirlo un po 'prima come ho fatto per le query LINQ. – Kittoes0124

+0

@Kittoes È possibile utilizzare [** LinqPad **] (http://www.linqpad.net/) per scrivere Linq e ottenere il codice Lambda e SQL – balexandre

risposta

6

LINQ 2 SQL ha un problema con il seguente schema:

from t in table 
group t by key into g 
from t in g //"ungroup" the grouping - this is causing a problem 
select ... 

Credo che la vostra join viene scatenante che perché "Separa" il raggruppamento. Si noti che un join LINQ è un GroupJoin che non è rappresentabile in SQL. Pensaci: come tradurrei la mia query di esempio? Devi unire table a una versione raggruppata di table causando ridondanza insana.

Ho visto questo problema alcune volte. Hai trovato la soluzione corretta: imponi una proiezione per evitare che questo modello si verifichi.

V'è una versione leggermente meno scomoda:

var daily = from p in db.table1 
      group p by new 
      { 
       key1, 
       key2 
      } into g 
      select new 
      { 
       col1 = g.Key.key1, 
       col2 = g.Sum(a => a.column2) 
      } into p 
      join d in db.table2 on new { p.key1, p.key2 } equals new { d.key1, d.key2 } 
      select new 
      { 
       col1 = p.col1, 
       col2 = p.col2, 
       col3 = d.column3 
      }; 

La nidificazione viene rimosso dal meno noto select x into y sintassi.

+0

Dannazione, speravo davvero che quella non fosse la risposta. Mi dispiace VERAMENTE dover definire tutte le mie colonne in table1 due volte solo per ottenere una colonna da table2. Ma suppongo che non sembri che io abbia altra scelta in merito. – Kittoes0124

+0

@Kittoes è anche la mia opinione su questo. D'altra parte LINQ risparmia così tanto lavoro che vale la pena tollerare questi brutti casi limite. Vorrei che il team EF fornisse un supporto LINQ competente o L2S non fosse abbandonato ... – usr

+1

Oh, certo. La quantità di altri lavori salvati da LINQ è assolutamente ridicola, quindi vale assolutamente la pena tollerare cose del genere quando accade.Mi fa diventare pazzo definendo 10 colonne + due volte senza una vera ragione. Grazie mille per aver spiegato PERCHÉ stava succedendo. – Kittoes0124