Optymalizacja zapytań z GROUP BY w MySQL (i nie tylko)

Przyznam, że do wczoraj sposób działania planera w przypadku zapytań agregujących (z klauzulą GROUP BY) był dla mnie nie do końca jasny.

Akurat trafiłem w mojej aplikacji na zapytanie na tyle proste, a jednocześnie wolne (operujące na dużej tabeli), że łatwo było je analizować. Szukając przyczyny i sposobów optymalizacji, trafiłem na znakomitą odpowiedź na stackoverflow. Pozwolę sobie wkleić jej sedno:

For covering index you add:
1. columns used in where clauses first, then
2. columns used in group by, then
3. columns used in order by, and then
4. columns used in select.

Ze swoim zapytaniem miałem nieco większy problem, ponieważ łączyło ono dwie tabele poprzez JOIN. Jak się okazuje, kolumny z warunków JOIN-owania należy przypisać do pierwszego punktu, co potwierdziło się w moim dzisiejszym pytaniu.

Sprawdziłem działanie tego schematu również na zapytaniach z GROUP BY na dużych tabelach w PostgreSQL i również działało (skutkowało wykonywaniem zapytania w pełni na indeksach), więc można przyjąć, że podobnie działa to dla większości popularnych DBMS.

YouTube – access forbidden, the request may not be properly authorized

Jeżeli ostatnio trafiłeś na tytułowy błąd, a dokładniej:

HTTP 403: youtube.common, Access forbidden. The request may not be properly authorized.

w swojej aplikacji sprzężonej z YouTube poprzez API, to wiedz, że aplikacja działa w pełni poprawnie. Nie szukaj też przyczyny w tokenach autoryzacyjnych.

Przyczyna jest zupełnie inna – Google wprowadził w API YouTube’a zabezpieczenie przed spamem (a raczej floodem). W związku z tym w ciągu jednej doby można przesłać bez ograniczeń do 50 nagrań, potem API będzie blokowało przesyłanie większej liczby nagrań niż jedno na 15 minut. Każdy nadmiarowe będzie wyrzucało właśnie zacytowany wyżej błąd.

Zmiany zostały podobno wprowadzone 24 lutego 2017. Sam trafiłem na to ograniczenie następnego dnia. Podobnych wzmianek jest już w sieci jednak sporo, np. #1, #2, #3, #4, #5, #6, #7, #8. Trochę współczuję ludziom, którzy oparli w swoich aplikacjach magazynowanie dużej ilości multimediów na YouTube.

PostgreSQL – losowe wartości z podzapytania

W PostgreSQL, korzystając z podzapytania używającego funkcji RANDOM() tak, jak np. w MySQL, otrzymamy te same wyniki dla każdego wiersza.

Przykład:

SELECT
    t1.id,
    (SELECT name FROM table2 ORDER BY RANDOM() LIMIT 1) AS random_name
FROM table1 t1

W tym DBMS podzapytanie tego typu wykonuje się raz, więc przy każdym wierszu z tabeli table1 będzie widniała ta sama wartość random_name.

Aby to zmienić, wystarczy sztucznie skorelować podzapytanie z zapytaniem nadrzędnym, np. tak:

SELECT
    t1.id,
    (SELECT name FROM table2 WHERE t1.id = t1.id ORDER BY RANDOM() LIMIT 1) AS random_name
FROM table1 t1

Niby proste, ale jakiś czas temu straciliśmy w pracy na tym trochę czasu (zwłaszcza nie wiedząc, że problem jest związany z podzapytaniami, bo samo zapytanie było bardziej złożone).

Eclipse – ponowne wywołanie informacji kontekstowej

Gdy w Eclipsie wywołujemy metodę/funkcję, pojawia się informacja kontekstowa z listą jej parametrów wraz z wyróżnieniem właśnie wpisywanego:

Gdy jednak wciśniemy escape lub utracimy focus na metodzie, informacja ta nie pojawia się ponownie, co zawsze było dla mnie problemem (trzeba było najechać na nazwę metody/funkcji, aby uzyskać informację o parametrach). Okazuje się jednak, że aby ponownie wywołać tę podpowiedź wystarczy wcisnąć CTRL+SHIFT+spacja.

Źródła: [1], [2]

Automatyczne generowanie opisu commita przy git merge

Krótko, lecz treściwie: odkryłem przełącznik --log=n  przy git merge.

Będąc na feature branchu opisuję dokładnie zmiany wraz ze znacznikami zagadnienia, co potem jest przetwarzane Redmine’a. Niestety, przy wykonywaniu merge’a do mastera sugerowana jest domyślna treść, którą nadpisywałem skopiowanym opisem któregoś z ostatnich commitów w branchu.

Aż do wczoraj. Kolejny raz przeczytałem manual i doszukałem się w nim ww. przełącznika. W moim przypadku wystarczy więc wykonać merge’a poprzez:

git merge --log=n redmine-XXXXX

Dzięki temu do domyślnej treści merge’owego commita dopisywana jest lista opisów ostatnich n commitów z tego brancha.

3-way merge przy aplikowaniu patcha w git

Nigdy nie rozumiałem sensu używania git apply. Kiedyś zastanawiałem się, czy ma jakieś zalety w stosunku do sprawdzonego patcha. Przejrzałem wtedy nawet pobieżnie manuala stwierdzając, że jest tam przecież tylko to, co ma sam patch. W swojej pracy używałem więc sprawdzonego i dobrze znanego patcha.

Dopiero niedawno uświadomiłem sobie, że pominąłem chyba najistotniejszy przełącznik: -3 . Jego użycie powoduje (w przypadku, gdy diff nie aplikuje się wprost) wykonanie 3-way merge’a. W wielu przypadkach samoczynnie rozwiązuje to problem z aplikowaniem diffów, których nie dałoby się zastosować przy użyciu samego patcha.

Firefox – narzędzia dla programistów zamiast Firebuga

Dopiero niedawno dowiedziałem się, że popularny dodatek do Firefoksa – Firebug – jest już od jakiegoś czasu martwy. Autorzy zalecają używanie narzędzi dla programistów wbudowanych w Firefoksa.

Mając świadomość, że z czasem pojawią się problemy (a jeden wystąpił już kilka miesięcy temu, gdy chciałem podejrzeć ruch generowany przez websockety), usunąłem Firebuga i zacząłem korzystać z wbudowanych narzędzi. Jak na przesiadkę z narzędzia, którego używam co najmniej od 5 lat, proces przebiegł zaskakująco łatwo.

Wbudowane narzędzia dla programistów na pierwszy rzut oka są według mnie nieco ładniejsze od Firebuga. Inspektor oraz wyróżnianie nim elementów jest czytelniejsze. Edycja drzewa DOM jest łatwiejsza, zaś zdarzenia JS (które w Firebugu były dość mocno zakamuflowane)  są teraz oznaczone tagiem „ev” przy elemencie, pod który są podpięte.

Na uwagę zasługuje też narzędzie do badania wydajności oraz przebudowany panel „Sieć”, który wyświetla szczegóły żądań w wygodniejszy sposób. Prezentuje on też dane przesyłane przez websockety, czego brakowało Firebugowi.

Narzędzia dla programistów z Firefoksa posiadają też kilka nowych funkcji. Mnie w oczy rzucił się „Brudnopis” otwierany w osobnym oknie (a nie jako część panelu konsoli) oraz wygodny „Próbnik koloru”, automatycznie kopiujący do schowka kod koloru wskazanego piksela. Nie może tu zabraknąć też narzędzia: „Widok trybu responsywnego”, który ułatwia rozwijanie aplikacji z responsywnym layoutem.

Podsumowując – polecam. Przesiadka jest praktycznie bezbolesna, a warto choćby ze względu na wymienione wyżej nowości i usprawnienia.

 

They write the right stuff

Niedawno znalazłem w sieci tytułowy artykuł: They Write the Right Stuff. W dużym skrócie opowiada o rozwoju szeroko rozumianego oprogramowania wykorzystywanego w misjach promów kosmicznych.

Przydługi wstęp opisujący automatyczny proces wznoszenia statku kosmicznego, następnie mające wywoływać wrażenie statystyki dotyczące odpowiedzialnego za to oprogramowania oraz krótki opis tła.

Właściwy początek artykułu również nieco nudny – przedstawienie kilku osób zaangażowanych w kod, którzy zapewniają o perfekcjonizmie kodu, za który są odpowiedzialni. Dla kontrastu następuje porównanie z wszechobecnym oprogramowaniem, z którym stykamy się w niemal każdej dziedzinie życia oraz stwierdzenie, że wszystko to jest tworzone szybko i niechlujnie. Nic nowego, do tego momentu prawie zrezygnowałem z dalszego czytania. Ale to właśnie odtąd zaczyna się sedno artykułu – proces tworzenia oprogramowania dla NASA.

Sprawa jest opisana bardzo dokładnie: od szczebla finansowego, po zarządzanie, projektowanie, zapewnianie jakości oraz samo programowanie.

Najwyższa warstwa to opis żywcem wyjęty z dowolnego, dużego korpo – przeładowane informacjami prezentacje dla przedstawicieli sponsorów projektu, narzekanie na ilość czasu, składanie pisemnych zapewnień. Z tego wszystkiego wyróżniają się zdecydowanie spotkania menedżerów odpowiedzialnych za oprogramowanie z uczestnikami misji, którą ono obsługuje – tak, aby poznać osobiście ludzi, którzy mogą zginąć, jeżeli soft będzie posiadał błędy. O tym, jak dużą presję musi to wywoływać najlepiej mówi fakt, że wszyscy menedżerowie wymienieni w artykule zmienili branże.

Projektowanie opisuje klasyczny model waterfall. Wszystko musi być przedyskutowane, ustalone i opisane w najdrobniejszych szczegółach. Osoby wypowiadają się z dumą o tym, że każda najmniejsza zmiana wymaga ponownego uruchomienia machiny projektowej. Trochę mnie to zdziwiło, podobnie jak chwalenie się używaniem bugtrackera.

Zapewnienie jakości odbywa się w dziale weryfikacji, odseparowanym w strukturze firmy od działu programistycznego. Wspomniana jest też praktyka weryfikacji już w trakcie pisania kodu, przez dodatkową osobę. Każdy znaleziony błąd jest zapisywany w bugtrackerze wraz z wszystkimi podstawowymi informacjami.

Dział programistyczny składa się z normalnych, „nudnych” ludzi: dorosłych programistów z rodzinami, dziećmi, posiadających zrównoważony stosunek pracy do życia prywatnego. Nie ma nadgodzin i niespodziewanego pośpiechu, zaś indywidualiści są stąd natychmiast eliminowani.

Z każdego znalezionego błędu wyciągane są wnioski, czasem aż do przesady. Wnioski nie oznaczają w tym przypadku osobistych konsekwencji – w przeciwieństwie do typowych korporacji, tutaj nie szuka się dupochronów i winnych. Winny jest zawsze proces i to proces, który dopuścił do powstania błędu musi zostać zmieniony tak, aby sam z siebie mógł tego typu sytuacje wykluczać. Brzmi strasznie skrupulatnie, ale jest to zrozumiałe – błędy w przypadku misji kosmicznych mogą kosztować ludzkie życie i miliardy dolarów, więc obarczanie winą pojedynczych osób przy takiej skali nie ma sensu.

Opisany proces wygląda naprawdę dobrze, chociaż oprogramowanie dla NASA to jednak skrajny przypadek rynku software’owego. Pieniądze nie są tu problemem, deadline’y nie są narzucane, lecz ustalane praktycznie przez samych developerów, oraz tylko jeden projekt naraz. Problemy te same, lecz warunki w porównaniu z resztą rynku (krytykowanego na początku) nieco utopijne.

Co jest najciekawsze w artykule? To, o czym dowiedziałem się mniej więcej w połowie jego czytania, gdy z ciekawości spojrzałem na datę opracowania. Miało to miejsce w 1996, 20 lat temu. Na kilka lat przed rozpoczęciem się mojej własnej przygody z komputerami i na kilkanaście przed tym, gdy zacząłem zawodowo zajmować się programowaniem i zderzać z identycznymi problemami. Niewiele się zmieniło, prawda?

Korzystanie z stdout jest wolne

Całe życie byłem przekonany, że wypluwanie danych do stdout jest najszybszym sposobem prezentowania postępu działania aplikacji działającej w CLI. I dopiero parę dni temu, przez przypadek, dowiedziałem się, że grubo się myliłem.

Weźmy na warsztat prosty skrypt:

$start = microtime(true);

for($i = 0; $i < 1000000; $i++) {
    echo 'New line' . PHP_EOL;
}

$stop = microtime(true);

$totalTime = $stop - $start;

echo 'Execution time: ' . $totalTime . PHP_EOL;

Wykonanie w moim przypadku zajmuje ~6,5 s.

Podobny skrypt uruchomiłem niedawno przez przypadek w pracy, jednak zapomniałem odkomentować wyświetlania linii tekstu. Skrypt wykonał się… praktycznie od razu.

Zakomentujmy więc linię zawierającą echo 'New line' . PHP_EOL; . Po tym zabiegu wykonanie skryptu trwa ok. 0,16 s. Różnica jest więc ogromna.

Po chwilowym szukaniu informacji na ten temat, pomocny okazuje się jak zwykle wątek na stackoverflow. W skrócie: stdout nie jest przystosowany do przetwarzania dużej ilości informacji, natomiast „fenomen” zauważony przez pytającego (zapis na dysk jest szybszy od wyplucia danych do stdout) wynika z buforowania. Dodatkowo, są duże różnice pomiędzy poszczególnymi emulatorami terminala.

Na przyszłość będę więc oszczędniejszy w korzystaniu z stdout, zwłaszcza, gdy zależy na czasie.

Eclipse – utrata możliwości debugowania w trakcie używania Xdebug

Po poznaniu rozwiązania problem wydaje się być głupi, ale powstrzymał mnie skutecznie przez bardzo długi czas przed debugowaniem aplikacji w PHP z użyciem Xdebug.

Do sedna: jeżeli w trakcie debugowania nagle tracisz możliwość sterowania debuggerem (dezaktywują się przyciski od nawigowania po kodzie, itp.), ale sama aplikacja i sesja debuggera nadal działa (jesteś w stanie ją pomyślnie zakończyć), to prawdopodobnie Eclipse stracił focus na debugowanym przez Ciebie wątku. Stan taki pokazuje poniższy zrzut ekranu:

eclipse-xdebug-lost-focus

Co w takiej sytuacji? Wystarczy kliknąć na „Remote launch” w karcie „Debug” (u mnie jest to lewa górna część ekranu):

eclipse-xdebug-recovered-focus

Jak widać, przyciski do sterowania debuggerem są znów aktywne i można kontynuować tę sesję Xdebug.