2011-10-24 10 views
5

secondo tutti i campioni, la conversione di SQL LINQ per HAVING come in questo esempio:LINQ PER GRUPPO SQL avendo generato solo come sottoquery

SELECT NAME 
FROM TABLES 
GROUP BY NAME 
HAVING COUNT(*) > 1 

è: (vb.net)

from t in tables 
group t by t.NAME into g = Group 
where g.count > 1 
select g 

ma la dichiarazione LINQ sopra è tradotto al seguente SQL:


SELECT [t1].[NAME] AS [Key] 
FROM (
    SELECT COUNT(*) AS [value], [t0].[NAME] 
    FROM [tables] AS [t0] 
    WHERE [t0].[NAME] <> @p0 
    GROUP BY [t0].[NAME] 
    ) AS [t1] 
WHERE [t1].[value] > @p1 

Non riesco mai a generare la clausola HAV nella forma LINQ. Diciamo che il gruppo HAVING e sottoquery per WHERE sono equivalenti nei risultati, ma c'è una differenza nelle prestazioni? che dire mantenere le mie query SQL originali almeno SIMILI a quelle che LINQ genera?

risposta

4

È possibile dimostrare se le due query in questione sono eseguite nello stesso modo da SQL Server visualizzando i piani di esecuzione. Prendere il seguente codice di prova (io ho usato SQL Server 2008):

CREATE TABLE #TABLES ([ID] INT IDENTITY, [Name] VARCHAR(30)) 
INSERT INTO #TABLES VALUES('A') 
INSERT INTO #TABLES VALUES('A') 
INSERT INTO #TABLES VALUES('B') 
INSERT INTO #TABLES VALUES('C') 
INSERT INTO #TABLES VALUES('D') 

SELECT NAME 
FROM #TABLES 
WHERE [Name] <> 'D' 
GROUP BY NAME 
HAVING COUNT(*) > 1 

SELECT [t1].[NAME] 
FROM (
    SELECT COUNT(*) AS [value], [t0].[NAME] 
    FROM [#TABLES] AS [t0] 
    WHERE [t0].[NAME] <> 'D' 
    GROUP BY [t0].[NAME] 
    ) AS [t1] 
WHERE [t1].[value] > 1 

DROP TABLE #TABLES 

L'esecuzione di queste query da SQL Query Analyzer con "Includi effettivo piano di esecuzione" selezionato nel menu "Query" produrrà il seguente risultato:

execution plans

In questo caso, dal momento che i piani di query generati sono esattamente gli stessi, sembra certamente che non ci dovrebbe essere alcuna differenza di prestazioni tra SQL e SQL generato dalla sua dichiarazione LINQ.

Come nota a margine, sfortunatamente, non sono riuscito a trovare alcuna documentazione sul motivo per cui LinqToSql non fa uso di HAVING, o se l'utilizzo di HAVING e di una sub-selezione consente di ottenere un guadagno in un modo o nell'altro. Se dovessi indovinare, direi che il Query Optimizer in SQL Server trasforma internamente queste istruzioni nella stessa query prima che vengano eseguite, motivo per cui i piani di esecuzione sono identici per entrambe le istruzioni. Indipendentemente dal fatto che la mia affermazione precedente sia vera, direi che, se sei in dubbio, dai un'occhiata ai Piani di esecuzione per la tua versione di SQL rispetto alla versione di LinqToSql. Se sono uguali, non hai nulla di cui preoccuparti in termini di prestazioni. Se la tua versione SQL è molto più efficiente, puoi sempre scrivere una stored procedure e chiamare semplicemente la stored procedure usando LinqToSql.