Co pewien czas natykam się na slowlogi z zapytaniami typu:

DESCRIBE tabela;
SHOW COLUMNS FROM tabela;
# administrator command: Ping;

Skąd się one pojawiają, skoro twórca aplikacji nie przypomina sobie, aby tego typu zapytania generował?

Co cóż, one po prostu są. Niektóre biblioteki, które wykorzystuje się do połączenia się z bazą danych dodają od siebie pewne zapytania. Często też jest tak, że frameworki w ramach ułatwiania pracy programistom starają się być „inteligentne”, a do tego potrzebują informacji o stanie tabeli.

Co z nimi jest nie tak? No cóż, złe jest to, że są. Każde zapytanie zajmuje zasoby. Czasami jest to więcej, czasami mniej. Skomplikowany JOIN to  kilka sekund i więcej, szybki SELECT po kluczu głównym to tysięczne (albo i jeszcze mniej) części sekundy. Problem w tym, że tego typu zapytania także zajmują czas procesora:

mysql> show profiles;
+----------+------------+------------------------+
| Query_ID | Duration   | Query                  |
+----------+------------+------------------------+
|        1 | 0.00203800 | DESCRIBE user          |
|        2 | 0.00192050 | SHOW COLUMNS FROM user |
+----------+------------+------------------------+
2 rows in set (0.00 sec)

Jak widać, każde z tych zapytań to ok. 0,002 sekundy. Każde z nich to dodatkowy ruch na dysku, otwieranie tabeli, sprawdzanie uprawnień, tworzenie LOCKa, zamykanie tabeli. Z resztą, popatrzmy:

mysql> SHOW PROFILE FOR QUERY 1;
+----------------------+----------+
| Status               | Duration |
+----------------------+----------+
| starting             | 0.000051 |
| checking permissions | 0.000007 |
| Opening tables       | 0.000315 |
| System lock          | 0.000003 |
| Table lock           | 0.000014 |
| init                 | 0.000012 |
| optimizing           | 0.000004 |
| statistics           | 0.000012 |
| preparing            | 0.000010 |
| executing            | 0.000005 |
| Opening tables       | 0.000009 |
| checking permissions | 0.000043 |
| checking permissions | 0.000025 |
| checking permissions | 0.000023 |
| checking permissions | 0.000066 |
| checking permissions | 0.000023 |
| checking permissions | 0.000022 |
| checking permissions | 0.000021 |
| checking permissions | 0.000022 |
| checking permissions | 0.000021 |
| checking permissions | 0.000013 |
| checking permissions | 0.000020 |
| checking permissions | 0.000022 |
| checking permissions | 0.000021 |
| checking permissions | 0.000030 |
| checking permissions | 0.000023 |
| checking permissions | 0.000022 |
| checking permissions | 0.000027 |
| checking permissions | 0.000032 |
| checking permissions | 0.000022 |
| checking permissions | 0.000012 |
| checking permissions | 0.000022 |
| checking permissions | 0.000021 |
| checking permissions | 0.000020 |
| checking permissions | 0.000024 |
| checking permissions | 0.000022 |
| checking permissions | 0.000023 |
| checking permissions | 0.000021 |
| checking permissions | 0.000023 |
| checking permissions | 0.000024 |
| checking permissions | 0.000013 |
| checking permissions | 0.000022 |
| checking permissions | 0.000023 |
| checking permissions | 0.000022 |
| checking permissions | 0.000020 |
| checking permissions | 0.000021 |
| checking permissions | 0.000024 |
| checking permissions | 0.000024 |
| checking permissions | 0.000023 |
| checking permissions | 0.000028 |
| Sending data         | 0.000215 |
| end                  | 0.000003 |
| query end            | 0.000002 |
| freeing items        | 0.000028 |
| removing tmp table   | 0.000198 |
| closing tables       | 0.000003 |
| logging slow query   | 0.000001 |
| logging slow query   | 0.000161 |
| Opening table        | 0.000006 |
| System lock          | 0.000002 |
| Table lock           | 0.000052 |
| cleaning up          | 0.000003 |
+----------------------+----------+
62 rows in set (0.00 sec)

Trochę roboty przy takiej „głupotce” się nazbierało.

Drugi problem z tego typu zapytaniami jest taki, że zazwyczaj są kompletnie niepotrzebne. Będę wdzięczny za komentarze jeśli znacie, drodzy czytelnicy, jakiś framework czy inny CMS w przypadku którego struktura bazy danych jest tak płynna, że trzeba przed każdym zapytaniem upewniać się co do struktury tabeli? Chętnie się dowiem, czy takie cudo gdziekolwiek istnieje. Dobrze wiedzieć co odradzać.

Podobnie ping. Można go wykorzystywać do różnych celów – np. podtrzymywanie połączenia. W takim układzie ma to pewien sens. Problem w tym, że często jest on wykorzystywany do sprawdzania, czy serwer MySQL odpowiada. Schemat prosty – najpierw ping, jeśli jest odpowiedź to lecimy z zapytaniami. Jaki to ma sens? Przecież, to że w danym momencie serwer odpowie na ping nie znaczy że ułamek sekundy później, zanim pójdzie zapytanie, serwer MySQL nie przestanie odpowiadać. To samo w drugą stronę. To, że teraz nie odpowie nie znaczy że za ułamek sekundy nie zacznie funkcjonować poprawnie. Jaki jest więc sens to sprawdzać? Zasada powinna być kompletnie inna. Wykonujemy zapytanie i sprawdzamy co z nim. Jeśli się wykonało, to dobrze. Jeśli nie, aplikacja uznaje że serwer MySQL nie działa i wykonuje zdefiniowane operacje.

Wbrew pozorom tego typu drobiazgi potrafią zaalokować sporą część zasobów serwera MySQL. Dobrze jest sprawdzać (choćby ustawiając long_query_time na 0 i przeglądając slowlogi) czy to, co się nam wydaje że idzie do bazy danych faktycznie jest tym, co musi obsłużyć serwer bazodanowy. Może się okazać, że programista będzie bardzo zdziwiony.