2010-07-01 10 views
9

Diciamo che abbiamo due tabelle: "Auto" e "Parte", con una tabella di unione in "Car_Part". Diciamo che voglio vedere tutte le auto che hanno una parte 123 in loro. Ho potuto fare questo:Qual è più veloce: UNISCI con GROUP BY o una sottoquery?

SELECT Car.Col1, Car.Col2, Car.Col3 
FROM Car 
INNER JOIN Car_Part ON Car_Part.Car_Id = Car.Car_Id 
WHERE Car_Part.Part_Id = @part_to_look_for 
GROUP BY Car.Col1, Car.Col2, Car.Col3 

Oppure potrei fare questo

SELECT Car.Col1, Car.Col2, Car.Col3 
FROM Car 
WHERE Car.Car_Id IN (SELECT Car_Id FROM Car_Part WHERE Part_Id = @part_to_look_for) 

Ora, tutto in me vuole utilizzare il primo metodo perché sono stato allevato da buoni genitori che ha instillato in me un odio puritano di subquery e amore per la teoria degli insiemi, ma mi è stato suggerito che fare quel grosso GROUP BY è peggio di una subquery.

Devo sottolineare che siamo su SQL Server 2008. Devo anche dire che in realtà voglio selezionare basato su Id della parte, Tipo di parte e forse anche su altre cose. Quindi, la domanda che voglio fare oggi si presenta in questo modo:

SELECT Car.Col1, Car.Col2, Car.Col3 
FROM Car 
INNER JOIN Car_Part ON Car_Part.Car_Id = Car.Car_Id 
INNER JOIN Part ON Part.Part_Id = Car_Part.Part_Id 
WHERE (@part_Id IS NULL OR Car_Part.Part_Id = @part_Id) 
AND (@part_type IS NULL OR Part.Part_Type = @part_type) 
GROUP BY Car.Col1, Car.Col2, Car.Col3 

Oppure ...

SELECT Car.Col1, Car.Col2, Car.Col3 
FROM Car 
WHERE (@part_Id IS NULL OR Car.Car_Id IN (
    SELECT Car_Id 
    FROM Car_Part 
    WHERE Part_Id = @part_Id)) 
AND (@part_type IS NULL OR Car.Car_Id IN (
    SELECT Car_Id 
    FROM Car_Part 
    INNER JOIN Part ON Part.Part_Id = Car_Part.Part_Id 
    WHERE Part.Part_Type = @part_type)) 
+2

Avete eseguito entrambi? Hai visto i piani di query? Benchmarked esso? – Oded

+1

Dovrei generare un carico di dati, quindi non ci arriverò fino alla prossima settimana. E quando ho cercato su Google una risposta, non ne ho trovato uno, quindi vale la pena postare una domanda online per chiunque altro stia cercando. – d4nt

+0

Group By è laborioso, usato per calcolare cose come medie, somme, ecc. Sembra che tu lo stia usando per eliminare i duplicati. Prova DISTINCT senza il gruppo di ... – Alocyte

risposta

3

Ho dati simili, quindi ho controllato il piano di esecuzione per entrambi gli stili di query. Con mia sorpresa, Column In Subquery (CIS) ha prodotto un piano di esecuzione con il 25% di costi di I/O in meno rispetto alla query del join interno (IJ). Nel piano di esecuzione CIS ottengo due scansioni dell'indice della tabella intermedia (Car_Part) rispetto a una scansione dell'indice dell'intermedio e un hash relativamente più costoso nell'IJ. I miei indici sono sani ma non in cluster, quindi è ovvio che le scansioni dell'indice potrebbero essere rese un po 'più veloci raggruppandole. Dubito che ciò influirebbe sul costo dell'hash join che è il passo più costoso nella query IJ.

Come gli altri hanno sottolineato, dipende dai vostri dati. Se stai lavorando con molti gigabyte in questi 3 tavoli, poi sintonizzati. Se le tue righe sono numerate a centinaia o migliaia, potresti dividere i capelli su un guadagno di prestazioni molto piccolo. Direi che la query IJ è molto più leggibile, quindi finché è abbastanza buono, fai in modo che uno sviluppatore futuro tocchi il tuo codice e dia loro qualcosa di più facile da leggere. Il conteggio delle righe nelle mie tabelle è 188877, 283912, 13054 ed entrambe le query restituite in meno tempo necessario per sorseggiare un caffè.

PostScript piccolo: poiché non si aggregano valori numerici, sembra che si intenda selezionare distinti. A meno che tu non abbia intenzione di fare qualcosa con il gruppo, è più facile vedere la tua intenzione con selezionare distinto piuttosto che raggruppare alla fine.Il costo di IO è lo stesso, ma uno indica la tua intenzione meglio IMHO.

4

La cosa migliore che puoi fare è testare da soli, per i volumi di dati realistici. Ciò non gioverà solo a questa query, ma a tutte le domande future quando non sei sicuro di quale sia il modo migliore.

cose importanti da fare sono:
- prova su volumi di dati a livello di produzione
- prova abbastanza & costantemente (cache chiaro: http://www.adathedev.co.uk/2010/02/would-you-like-sql-cache-with-that.html)
- verificare il piano di esecuzione

Si potrebbe o monitor utilizzando SQL Profiler e controllare la durata/letture/scritture/CPU lì, o SET STATISTICS IO ON; SET STATISTICS TIME ON; per generare statistiche in SSMS. Quindi confronta le statistiche per ogni query.

Se non è possibile eseguire questo tipo di test, si sarà potenzialmente esposti a problemi di prestazioni lungo la linea che sarà necessario quindi ottimizzare/rettificare. Esistono strumenti che puoi utilizzare per generare dati per te.

2

Con SQL Server 2008 mi aspetto che In sia più veloce in quanto equivale a questo.

SELECT Car.Col1, Car.Col2, Car.Col3 
FROM Car 
WHERE EXISTS(SELECT * FROM Car_Part 
      WHERE Car_Part.Car_Id = Car.Car_Id 
      AND Car_Part.Part_Id = @part_to_look_for 
) 

ovvero deve solo verificare l'esistenza della riga non unirla, quindi rimuovere i duplicati. Questo è discussed here.