![]() |
![]() |
![]() ![]()
Post
#1
|
|
Grupa: Zarejestrowani Postów: 105 Pomógł: 3 Dołączył: 12.07.2010 Ostrzeżenie: (0%) ![]() ![]() |
cześć,
potrzebuję pomocy z grupowaniem tj. mam tabelę
i chciałbym pobrać wszystkie wiersze, w których status_id jest najnowszy (max(date)) w ramach jednego object_id. Mówiąc krótko, dla każdego okiektu potrzebny mi najnowszy status. Działa (ale za wolno, bo ok. 200 ms)
Samo zrobienie:
nie działa, ponieważ zwraca pierwszy napotkany status, a nie ten pasujący do maksymalnej daty (nie najnowszy, a pierwszy insertowany). Jak powinno wyglądać najprostsze zapytanie, żeby zwrócić najnowszy status dla każdego obiektu ? |
|
|
![]() |
![]()
Post
#2
|
|
Grupa: Zarejestrowani Postów: 6 806 Pomógł: 1828 Dołączył: 11.03.2014 Ostrzeżenie: (0%) ![]() ![]() |
|
|
|
![]()
Post
#3
|
|
Grupa: Zarejestrowani Postów: 105 Pomógł: 3 Dołączył: 12.07.2010 Ostrzeżenie: (0%) ![]() ![]() |
Problem polega na tym, żę taka wersja nie wchodzi w grę. status_id może być w różnej kolejności np. Usunięty = 1, Nowy = 2 - czyli, jeśli status będzie maxem, to nie będzie usuniętych. Dlatego potrzebuję użyć daty (IMG:style_emoticons/default/smile.gif) |
|
|
![]()
Post
#4
|
|
Grupa: Zarejestrowani Postów: 1 421 Pomógł: 310 Dołączył: 18.04.2012 Ostrzeżenie: (0%) ![]() ![]() |
Twoje pierwsze zapytanie jest jedynym (oprócz takiego samego JOINa), które jest prawidłowe i szybkie. 200 ms to nie tragedia.
Drugie (to z HAVING) to tylko na MySQL się wykona. Każda inna baza zasygnalizuje błąd. Jeśli jednak to rozwiązanie cię nie satysfakcjonuje to pomyśl nad zmianą architektury - tak, bys przechwowywał (w tej lub innej tabeli) tylko najnowsze statusy |
|
|
![]()
Post
#5
|
|
Grupa: Zarejestrowani Postów: 6 806 Pomógł: 1828 Dołączył: 11.03.2014 Ostrzeżenie: (0%) ![]() ![]() |
Źle przecyzytałem problem.
Czy większa data oznacza większe id, czy też dla mniejszego id może być większa data (oczywiście w ramach tego samego object_id)? |
|
|
![]()
Post
#6
|
|
Grupa: Zarejestrowani Postów: 105 Pomógł: 3 Dołączył: 12.07.2010 Ostrzeżenie: (0%) ![]() ![]() |
Źle przecyzytałem problem. Czy większa data oznacza większe id, czy też dla mniejszego id może być większa data (oczywiście w ramach tego samego object_id)? Większa data może oznaczać mniejsze ID. Dlatego właśnie potrzebuje wybrać to id, które należy do rekordu z największą datą, mysql zwraca mi niestety pierwsze napotkane. |
|
|
![]()
Post
#7
|
|
Grupa: Zarejestrowani Postów: 6 806 Pomógł: 1828 Dołączył: 11.03.2014 Ostrzeżenie: (0%) ![]() ![]() |
A jak to działa w ten sposób?
Na dacie przydałby się indeks. |
|
|
![]()
Post
#8
|
|
Grupa: Zarejestrowani Postów: 105 Pomógł: 3 Dołączył: 12.07.2010 Ostrzeżenie: (0%) ![]() ![]() |
Twoje pierwsze zapytanie jest jedynym (oprócz takiego samego JOINa), które jest prawidłowe i szybkie. 200 ms to nie tragedia. Drugie (to z HAVING) to tylko na MySQL się wykona. Każda inna baza zasygnalizuje błąd. Jeśli jednak to rozwiązanie cię nie satysfakcjonuje to pomyśl nad zmianą architektury - tak, bys przechwowywał (w tej lub innej tabeli) tylko najnowsze statusy 200 to tragedia, bo ta sama konstrukcja z self-joinem w postaci:
wykonuje sie 4x szybciej (czasem nawet 5), ale tworzy tabelę tymczasową w myisamie i większość czasu zabiera przerzucanie danych między innodb i myisamem. To jest serwer współdzielony, więc nie ma szans na zmianę tabel tymczasowych z myisam na innodb, żeby nie tracić na to czasu, bo wtedy to (i pozostałe) zapytanie wykonywałoby się w okolicach 10 ms (tak wynika z profilera). Dlatego najlepiej by było zmieścić to w jednym zapytaniu, bez widoków, bez sub-queries, bez unionów. Ten post edytował MadMark 12.12.2016, 12:43:58 |
|
|
![]()
Post
#9
|
|
Grupa: Zarejestrowani Postów: 1 421 Pomógł: 310 Dołączył: 18.04.2012 Ostrzeżenie: (0%) ![]() ![]() |
Sorry, ale ja nie widze różnic pomiędzy tymi zapytaniami. Tym z (x,y) IN (..,..) a JOIN. Zresztą już wcześniej napisałem o JOIN. Optymalizator kosztowy powinien je na taki sam algorytm przerobić.
|
|
|
![]()
Post
#10
|
|
Grupa: Zarejestrowani Postów: 105 Pomógł: 3 Dołączył: 12.07.2010 Ostrzeżenie: (0%) ![]() ![]() |
Sorry, ale ja nie widze różnic pomiędzy tymi zapytaniami. Tym z (x,y) IN (..,..) a JOIN. Zresztą już wcześniej napisałem o JOIN. Optymalizator kosztowy powinien je na taki sam algorytm przerobić. Niestety, nie przerabia. mysql 5.5, ok 10k rekordów - jeśli to coś zmienia. Tak jak pisałem wcześniej zapytanie wykonuje się zbyt długo w pierwszej wersji, w drugiej krócej, ale też wiem, że można lepiej - tylko technicznie z wiedzą nie domagam. |
|
|
![]()
Post
#11
|
|
Grupa: Zarejestrowani Postów: 1 421 Pomógł: 310 Dołączył: 18.04.2012 Ostrzeżenie: (0%) ![]() ![]() |
Załóż indeks na parę (obiect_id,date) i wklej tu trzy explainy:
1. SELECT g.* FROM (SELECT obiect_id, max(date) AS date FROM modifications GROUP BY obiect_id) f LEFT JOIN modifications g ON (f.obiect_id=g.obiect_id AND f.date=g.date) 2. SELECT f.* FROM modifications f WHERE (f.obiect_id, f.date) IN (SELECT g.obiect_id AS obiect_id, max(g.date) AS date FROM modifications g GROUP BY g.obiect_id) 3. SELECT g.* FROM (SELECT obiect_id, max(date) AS date FROM modifications GROUP BY obiect_id) f LEFT JOIN modifications g using (obiect_id,date) 3 to jest to samo, co 1, ale dla pewności. |
|
|
![]() ![]() |
![]() |
Aktualny czas: 22.08.2025 - 20:36 |