Egyszerű csoportosítós példa.
A legkézenfekvőbb megoldás egy sima group by és min:
select E.Nev, Telefon = min(E.Telefon) from Ember E group by E.Nev
Ezt egy covering nc indexszel szépen fel lehet gyorsítani:
CREATE NONCLUSTERED INDEX [IX_1] ON [dbo].[Ember] ( [Nev] ASC ) INCLUDE ([Telefon])
Egy másik megoldás már költségesebb, de helyes eredményt ad (a komment szerzője szerintem ismerte az elsőt, csak valami trükkösebb megoldást akart adni):
select * from Ember e1 where not exists ( select * from Ember e2 where e1.Nev = e2.Nev and e1.Telefon > e2.Telefon )
Ennek logikája már körülményesebb, kérem azokat a sorokat, amelyekhez nem létezik olyan sor, aminek ugyanaz a neve, de kisebb a telefonszáma. Ezt csak joinnal tudja megoldani a szerver, jelentősen nagyobb költséggel.
Egy jelentősen más logikájú megoldás is érkezett:
;WITH Data AS ( SELECT Nev, Telefon, ROW_NUMBER() OVER (PARTITION BY Nev ORDER BY Telefon) AS RowNumber FROM Ember ) SELECT Nev, Telefon FROM Data WHERE RowNumber = 1
Felsorszámozzuk a sorokat a Telefon szerint rendezve, partícionálva a Nev alapján, majd ebből a halmazból kiszedjük azokat a sorokat, amelyek sorszáma 1. Minden Nev-hez 1 ilyen lesz, értelemszerűen.
Ez a megoldás nem szereti az előbbi indexünket. Ahhoz, hogy ez is gyors legyen, a Telefon oszlopot is bele kell rakni az index kulcsai közé:
CREATE NONCLUSTERED INDEX [IX_1] ON [dbo].[Ember] ( [Nev] ASC, [Telefon] ASC )
Így a group by-os és ezen megoldás költsége már azonos lesz, bár a tervük nem. Ez esetben sok sor esetén lehetne eldönteni, van-e perf különbség a két megoldás között, akinek van erre ideje, érdekelne az eredménye. Mondjuk 10 millió sorra. Érzésre nem lesz, de cáfoljatok meg, konkrét terveket mutatva.
Köszönöm mindenkinek a megoldásokat, és külön köszönöm Molnár Csabának, hogy a nem nyilvánvaló megoldást is megmutatta.
Could you hire me? Contact me if you like what I’ve done in this article and think I can create value for your company with my skills.