Wybierz jedną wartość z grupy na podstawie kolejności z innych kolumn

Problem

Załóżmy, że mam tę tabelętab (skrzypce dostępny).

| g | a | b |     v |
---------------------
| 1 | 3 | 5 |   foo |
| 1 | 4 | 7 |   bar |
| 1 | 2 | 9 |   baz |
| 2 | 1 | 1 |   dog |
| 2 | 5 | 2 |   cat |
| 2 | 5 | 3 | horse |
| 2 | 3 | 8 |   pig |

Grupuję wiersze wedługgi dla każdej grupy chcę jedną wartość z kolumnyv. Jednak nie chcękażdy wartość, ale chcę wartość z wiersza z maksymalnąai ze wszystkich tych, z maksymalnymb. Innymi słowy, mój wynik powinien być

| 1 |   bar |
| 2 | horse |
Aktualne rozwiązanie

Znam zapytanie, aby to osiągnąć:

SELECT grps.g,
(SELECT v FROM tab
 WHERE g = grps.g
 ORDER BY a DESC, b DESC
 LIMIT 1) AS r
FROM (SELECT DISTINCT g FROM tab) grps
Pytanie

Ale rozważam to zapytaniebrzydki. Głównie dlatego, że używazależne podzapytanie, który wydaje się prawdziwym zabójcą wydajności. Zastanawiam się więc, czy istnieje łatwiejsze rozwiązanie tego problemu.

Oczekiwane odpowiedzi

Najbardziej prawdopodobną odpowiedzią na to pytanie będzie jakiś dodatek lub łatka dla MySQL (lub MariaDB), która zapewnia taką funkcję. Ale z zadowoleniem przyjmuję również inne przydatne inspiracje. Wszystko, co działa bez zależnego podzapytania, kwalifikuje się jako odpowiedź.

Jeśli Twoje rozwiązanie działa tylko dla pojedynczej kolumny zamówienia, tj. Nie można odróżnićcat ihorse, nie wahaj się zasugerować tej odpowiedzi, a także oczekuję, że nadal będzie przydatna w większości przypadków użycia. Na przykład,100*a+b byłby prawdopodobny sposób na uporządkowanie powyższych danych według obu kolumn przy jednoczesnym użyciu tylko jednego wyrażenia.

Mam na myśli kilka ładnych, hackerskich rozwiązań i mogę je dodać po chwili, ale najpierw zobaczę i zobaczę, czy jakieś nowe fajne rzeczy się pojawią.

Wyniki testu porównawczego

Ponieważ trudno jest porównać różne odpowiedzi tylko patrząc na nie, uruchomiłem na nich kilka testów porównawczych. Zostało to uruchomione na moim własnym komputerze przy użyciu MySQL 5.1. Liczby nie będą porównywać się do żadnego innego systemu, tylko do siebie nawzajem. Prawdopodobnie powinieneś wykonywać własne testy z prawdziwymi danymi, jeśli wydajność jest kluczowa dla twojej aplikacji. Kiedy pojawią się nowe odpowiedzi, mogę dodać je do mojego skryptu i ponownie uruchomić wszystkie testy.

100 000 pozycji, 1000 grup do wyboru, InnoDb:0,166 dlaMvG (z pytania)0,520s zaRichardTheKiwi2,199s zaxdazz19,24s zaDems (sekwencyjne zapytania podrzędne)48,72s zaacatt100 000 pozycji, 50 000 grup do wyboru, InnoDb:0,356 zaxdazz0,640s zaRichardTheKiwi0,764s zaMvG (z pytania)51,50 zaacattza długo dlaDems (sekwencyjne zapytania podrzędne)100 000 pozycji, 100 grup do wyboru, InnoDb:0,163 zaMvG (z pytania)0,523s zaRichardTheKiwi2,072s zaDems (sekwencyjne zapytania podrzędne)17,78s zaxdazz49,85s zaacatt

Wydaje się więc, że moje własne rozwiązanie do tej pory nie jest aż tak złe, nawet z zależnym podzapytaniem. Zaskakujące jest, że rozwiązanie acatta, które używa również zależnego podzapytania i które w związku z tym uważałbym za takie samo, działa znacznie gorzej. Prawdopodobnie coś, z czym optymalizator MySQL nie może sobie poradzić. Rozwiązanie, które zaproponował Richard TheKiwi, wydaje się również mieć dobrą ogólną wydajność. Pozostałe dwa rozwiązania w dużym stopniu zależą od struktury danych. W wielu grupach małe grupy, podejście xdazz, przewyższa wszystkie inne, podczas gdy rozwiązanie Demsa sprawdza się najlepiej (choć nadal nie jest wyjątkowo dobre) dla kilku dużych grup.

questionAnswers(4)

yourAnswerToTheQuestion