Krzysztof Czajkowski - Zliczać każdy może ...

5 pkt
Jolanta Mieszczyk napisał/a o
5 lat temu

Jedną z bardziej powszechnych operacji w bazach danych są operacje zliczania. Im większe bazy, tym ważniejsza staje się odpowiedź na pytanie: "ile?": ile transakcji, ilu klientów, ilu pracowników, ile produktów, … . W sytuacji, gdy rekordów są tysiące, problem jest pomijalnie mały a odpowiedzi uzyskać można w czasie krótkim czasie. Typowe wdrożenia serwerów Oracle dotycząc jednak zbiorów o rozmiarach setek GB, TB i większych. Przy takich woluminach zawsze pojawia się wątpliwość: "a może da się to zrobić szybciej?".


Wśród osób zajmujących się bazami Oracle krąży wiele opinii na temat wyższości różnych form zapisu polecenia zliczającego. W Internecie, który niczym papier, przyjmie wszystko, pełno jest wypowiedzi, a na forach internetowych toczone są poważne spory :) Sytuacji nie ułatwia producent, podając w dokumentacjach i na stronach Metalinku różne informacje. Tak więc po kolei:


Załóżmy, że dysponujemy tabelą, jak poniżej, w której istnieje powiedzmy 1 mln rekordów. Tabela posiada klucz główny (a więc również indeks unikalny) na kolumnie id. Do tej tabeli skierowane zostaną cztery zapytania (ponumerowane dla ułatwienia):
CREATE TABLE transactions (
id NUMBER(10),
text VARCHAR2(100)
);


1) SELECT count(*) FROM transactions;
2) SELECT count(1) FROM transactions;
3) SELECT count(id) FROM transactions;
4) SELECT count(text) FROM transactions;


Na wspomnianych formach znaleźć można łatwo posty udowadniające wyższość (a jakże) rozwiązania 2 nad 1, a czasem 3 nad oboma powyższymi. Sam Oracle w tej materii wypowiadał się wielokrotnie (i co ciekawe niekonsekwentnie), np.: "If the intention is only to count the number of Records matching the criteria then you could as well use: count(1) .. This is the fastest as the numerical literal is the fastest to be summed up", lub też: "Do not use count(*) to determine the number of rows in a table. Use count(1) or count(ROWID) instead. These options are faster because they bypass some unnecessary operations in Oracle's SQL processing mechanism.". Dodatkową zmienną jest kwestia zmian w poszczególnych wersjach serwera.


Aby rozwiązać te dylematy najłatwiej wykonać eksperyment - sprawdzić plany wykonania wszystkich zapytań oraz czasy ich realizacji. Wynik może dla niektórych być zaskoczeniem. Otóż plany dla zapytań 1, 2 i 3 są identyczne. Wszystkie trzy zapytania wykorzystują indeks! Bez względu na to, czy wybieramy "*" wszystkie kolumny, czy fikcyjną wartość "1", czy też konkretnie kolumnę klucza głównego (czyli de facto jej indeks), plany są identyczne:

Id Operation Name Rowa Cost (%CPU)| Time
0 SELECT STATEMENT 1 571 (1) 00:00:07
1 SORT AGGREGATE 1
2 INDEX FAST FULL SCAN TRANS_ID_PK 1000K 571 (1) 00:00:07


Jak widać Oracle wykazuje się "inteligencją", podmieniając właściwe zapytanie na takie, które obejmuje swoim zakresem tylko i wyłącznie indeksy - nie dotykając nawet tabeli. Tylko zapytanie nr 4 wymaga od Oracle bezpośredniego dostępu do tabeli, a więc skrót w postaci indeksu nie może przynieść nam korzyści. Dodatkowo nie mamy pewności, czy kolumna text nie ma przypadkiem pustych wartości - nie zostaną one zliczone i wynik będzie inny. Najbezpieczniej więc wybrać count(*), nie każdy sprawdza, na których kolumnach są indeksy, a count(1) może komuś wydać się nieco wydumany.


Jaki z tego morał? Otóż czasem nie warto być zanadto sprytnym. W aktualnych wersjach serwera (11g i 12c) nie opłaca się przepisywać ręcznie zapytań, zamieniając np. count(*) na count(1). Oracle robi to za na. W końcu za coś mu płacimy.

Polecane szkolenie z tego zakresu: Strojenie wydajnościowe Oracle SQL

Na szkoleniu uczestnik zdobędzie wiedzę na temat tych aspektów języka SQL na serwerze Oracle, które mają wpływ na wydajność funkcjonowania środowiska. Kluczową wiedzą wyniesioną ze szkolenia będzie świadomość różnorodnych aspektów projektu i implementacji baz danych związanych z szybkością realizacji operacji. Umiejętności obejmą pozyskiwanie planów wykonania zapytań i ich interpretacja, gromadzenie statystyk, ich weryfikacja i przenoszenie, tworzenie i edycja właściwie dobranych struktur indeksujących i ich przebudowa, a także wykorzystanie wskazówek optymalizatora do wpływania na plany wykonania zapytań.

Informacja o autorze

Krzysztof Czajkowski jest absolwentem Inżynierii Komputerowej na Politechnice Krakowskiej. Od kilkunastu lat zajmuje się systemami bazodanowymi, ich optymalizacją, programowaniem i narzędziami do przetwarzania danych. Specjalizuje się w środowisku i technologiach firmy Oracle. Od 10 lat pracuje jako instruktor, a od 8 lat prowadzi szkolenia dotyczące systemów i narzędzi bazodanowych firmy Oracle. Posiada liczne certyfikaty (w tym 10 certyfikatów firmy Oracle, m.in. na poziomach Professional i Expert). W prowadzonych przez niego szkoleniach wzięło dotychczas udział ponad 3300 uczestników.

Masz pytanie?

zadaj pytanie

Masz pomysł?

zgłoś pomysł