20/03/2024

Warunek “IS NULL” i “OR” i mogą Cię hamować

Tam, gdzie warunek „IS NULL” albo „OR” szaleje bez kontroli, zapytania często wpadają w króliczą norę wydajności – miejsce, w którym cykle procesora spalają się szybciej niż ogon komety, a operacje I/O mnożą się z zapałem królików na wiosnę.

Cel tego tekstu jest jasny – poprowadzić profesjonalistów baz danych w kierunku szybszego i bardziej wydajnego wykonywania zapytań. Zakasujemy rękawy, aby zagłębić się w powody, dla których te konkretne wzorce obniżają wydajność i nakreślić strategie działania, które pozwolą złagodzić te wyboje na drodze.

„OR” == BAD, dlaczego?

Warunek „OR”, gdy jest nadmiernie używany w zapytaniach, może prowadzić do kilku nieefektywności. Jednym z głównych problemów jest to, że może powodować wielokrotną ocenę zapytania przez Oracle, raz dla każdego warunku oddzielonego przez „OR”. Dzieje się tak, ponieważ „OR” skutecznie rozszerza kryteria wyszukiwania. Może to uniemożliwić bazie danych efektywne wykorzystanie indeksów. W rezultacie, zamiast jednej, wydajnej ścieżki do pobrania wymaganych danych, Oracle może skanować większe części tabeli lub indeksu. Prowadzi to do zwiększonego użycia I/O i CPU, a w konsekwencji do wolniejszej wydajności zapytań.

Co więcej, zapytania „wzbogacone” o wiele warunków „OR” mogą stać się trudniejsze do odczytania i utrzymania. Wraz z dodawaniem kolejnych warunków tracona jest przejrzystość, co utrudnia zrozumienie intencji zapytania na pierwszy rzut oka.

Optymalizacja zapytań: Odchodźmy od „OR”

Warunek „IN” zapewnia zwięzły i wydajny sposób wyszukiwania wielu wartości w kolumnie. W porównaniu do łączenia kilku warunków „OR” razem, „IN” może znacznie zmniejszyć złożoność zapytania i poprawić jego plan wykonania. Na przykład, rozważ różnicę między tymi dwoma podejściami:

Użycie „OR”:
SELECT * FROM employees
WHERE department_id = 10
OR department_id = 20
OR department_id = 30;

Użycie „IN”:
SELECT * FROM employees
WHERE department_id IN (10, 20, 30);

Oba zapytania mają na celu pozyskanie danych pracowników z działów 10, 20 i 30. Jednak wersja „IN” jest nie tylko bardziej czytelna, ale także pozwala optymalizatorowi zapytań Oracle na bardziej efektywne wykorzystanie indeksów i potencjalne zmniejszenie liczby skanów wymaganych do pobrania żądanych danych.

Problemy z „IS NULL”

wartości Null

Warunek „IS NULL” stanowi inny zestaw wyzwań. Jest to problematyczne przede wszystkim ze względu na sposób, w jaki wartości NULL są traktowane przez mechanizmy indeksowania Oracle, w szczególności indeksy B-TREE. W Oracle wartość NULL oznacza brak jakichkolwiek danych. Chociaż może to być semantycznie odpowiednie dla niektórych scenariuszy, wprowadza to nieefektywności w przetwarzaniu zapytań.

Indeksy B-TREE nie przechowują wpisów dla kluczy przedstawione jako NULL, co oznacza, że warunek zapytania sprawdzający IS NULL nie będzie w stanie efektywnie wykorzystać tych indeksów. W rezultacie Oracle może uciec się do pełnego skanowania tabeli, aby spełnić takie zapytania, co prowadzi do spadku wydajności, szczególnie w przypadku dużych zbiorów danych.

Odejdźmy więc od wartości „Null” i „IS NULL” – Jak?

Podstawy wydają się proste. Jeśli znasz wartość, pozwól ją wprowadzić. Jeśli nie znasz wartości, określ, że jest ona nieznana.

  • Wartości domyślne: Przypisując wartość domyślną, zapewniasz, że każdy rekord ma przewidywalną wartość, którą można skutecznie indeksować i przeszukiwać. Na przykład, jeśli kolumna rejestruje datę wykonania akcji, a akcja ma zawsze wystąpić, ustawienie domyślnej daty (takiej jak data utworzenia wiersza) zamiast zezwalania na wartości NULL może poprawić wydajność indeksu.
  • Wartości zastępcze dla nieznanych danych: W przypadkach, gdy kolumna może nie mieć znaczącej wartości domyślnej – na przykład opcjonalne informacje o użytkowniku – warto użyć wartości zastępczej do reprezentowania nieznanych lub nie mających zastosowania danych. Pozwala to uniknąć wartości NULL i zapewnia, że kolumna pozostaje przyjazna dla indeksu. Na przykład użycie określonej daty daleko w przeszłości lub wyznaczonej wartości ciągu, takiej jak „UNKNOWN” lub „N/A”, może być bardziej wydajne niż NULL.
  • Indeksy oparte na funkcjach: Jak podkreśla Babette Turner, wykorzystanie indeksów opartych na funkcjach może być efektywną strategią optymalizacji zapytań zawierających wartości NULL. Tworząc indeks na funkcji, która przekształca wartości NULL w przeszukiwalny klucz, można zachować wydajność indeksu. Weźmy na ten przykład indeks utworzony na NVL(mycolumn, 'ISNULL’). Przekształca on wartości NULL w stałą wartość 'ISNULL’, która może być efektywnie indeksowana i przeszukiwana.