Praca z danymi JSON w PostgreSQL to potężne narzędzie, ale – jak każde narzędzie – wymaga ostrożności. Nawet drobne błędy mogą zamienić twoje zapytanie w niezłą łamigłówkę. Dzisiaj znowu skupimy się na typowych błędach, które pojawiają się przy pracy z JSON i JSONB w PostgreSQL, oraz na sposobach ich unikania.
Problem 1: używanie JSON zamiast JSONB
Wielu początkujących błędnie używa typu danych JSON, myśląc, że to najlepszy wybór do przechowywania danych w formacie JSON. Jednak JSON w PostgreSQL trzyma dane jako tekst, co może spowolnić wyszukiwanie lub filtrowanie.
Przykład błędu:
CREATE TABLE products (
id SERIAL PRIMARY KEY,
details JSON
);
INSERT INTO products (details) VALUES ('{"name": "Laptop", "price": 1000}');
INSERT INTO products (details) VALUES ('{"name": "Laptop", "price": 1000}');
Przy próbie filtrowania po kluczu (price) zapytanie będzie działać znacznie wolniej niż przy JSONB.
Jak to naprawić: używaj JSONB, jeśli planujesz aktywnie filtrować lub odwoływać się do danych.
CREATE TABLE products (
id SERIAL PRIMARY KEY,
details JSONB
);
Problem 2: brak indeksów dla JSONB
JSONB to mega mocne narzędzie, ale bez indeksów jego wydajność przy złożonych zapytaniach może mocno spaść.
Przykład błędu: załóżmy, że mamy tabelę z kolumną details, gdzie trzymamy dużo obiektów JSON:
SELECT * FROM products WHERE details->>'name' = 'Laptop';
Jeśli dane nie są zindeksowane, serwer zrobi pełne skanowanie tabeli (full table scan), co zajmie dużo więcej czasu.
Jak to naprawić: stwórz indeks GIN, żeby przyspieszyć wyszukiwanie po kluczach:
CREATE INDEX idx_details_name ON products USING gin (details jsonb_path_ops);
Problem 3: błędy przy wyciąganiu zagnieżdżonych danych
Wyciąganie danych z obiektów zagnieżdżonych lub tablic może być mylące, zwłaszcza jeśli nie znasz różnicy między operatorami -> i ->>.
Przykład błędu:
SELECT details->'price' FROM products;
To zapytanie zwróci wartość w formacie JSON, a nie jako string ("1000" zamiast 1000). Jeśli potrzebujesz samej wartości, użyj ->>:
SELECT details->>'price' FROM products;
Problem 4: Nieprawidłowe użycie operatorów
Możesz natknąć się na operator @> i pomyśleć: "Brzmi fajnie, używajmy go zawsze!" Ale jeśli nie wiesz, jak działa, możesz dostać nieoczekiwane wyniki.
Przykład błędu:
SELECT * FROM products WHERE details @> '{"price": 1000}';
To zapytanie działa tylko jeśli price jest liczbą w JSON. Jeśli wartość jest zapisana jako string "1000", zapytanie nic nie zwróci.
Jak to naprawić: uważaj na typy danych w JSON:
SELECT * FROM products WHERE details->>'price' = '1000';
Problem 5: Duże obiekty JSON
Przechowywanie dużych obiektów JSON bez optymalizacji może mocno spowolnić zapytania. Co więcej, odczyt lub zmiana nawet małego fragmentu danych w JSONB wymaga przetworzenia całego obiektu.
Jak to naprawić: jeśli pewne klucze są używane często, wydziel je do osobnych kolumn w tabeli. Na przykład:
ALTER TABLE products ADD COLUMN price NUMERIC;
UPDATE products SET price = (details->>'price')::NUMERIC;
Teraz możesz efektywnie filtrować i sortować dane bez konieczności parsowania JSONB.
Problem 6: pełna przebudowa obiektów przy zmianach
Przy użyciu funkcji takich jak jsonb_set() czy jsonb_insert(), PostgreSQL tworzy zupełnie nowy obiekt JSONB, co może być kosztowne wydajnościowo.
Jak to naprawić: minimalizuj liczbę aktualizacji JSONB. Na przykład, zamiast często aktualizować jeden obiekt, połącz wszystkie zmiany w jedno zapytanie:
UPDATE products
SET details = jsonb_set(details, '{price}', '1500'::jsonb);
Problem 7: niezrozumienie struktury tablicy
W JSONB tablice też wymagają uwagi. Załóżmy, że masz tablicę:
{
"tags": ["electronics", "laptop", "sale"]
}
Chcesz sprawdzić, czy jest tag "laptop". Jeśli błędnie użyjesz operatora @>, możesz nie dostać wyniku, bo on oczekuje tablicy, a nie stringa.
Przykład błędu:
SELECT * FROM products WHERE details->'tags' @> '"laptop"';
Jak to naprawić: Użyj poprawnego formatu w operatorze @>:
SELECT * FROM products WHERE details->'tags' @> '["laptop"]';
Wskazówki jak unikać błędów
Żeby uniknąć wielu problemów przy pracy z JSONB, stosuj się do tych rad:
Wybieraj właściwy typ danych. Jeśli pracujesz z dużą ilością danych i często filtrujesz, zawsze używaj JSONB zamiast JSON.
Indeksuj dane. Jeśli zapytania często odwołują się do konkretnych kluczy, stwórz odpowiedni indeks (np. GIN).
Sprawdzaj dane przed wstawieniem. Używaj funkcji walidujących do sprawdzania struktury danych:
DO $$
BEGIN
IF jsonb_typeof('{"price": 1000}'::jsonb->'price') IS DISTINCT FROM 'number' THEN
RAISE EXCEPTION 'Cena musi być liczbą';
END IF;
END $$;
Optymalizuj strukturę danych. Jeśli pewne klucze są używane częściej niż inne, wyciągnij je do osobnych kolumn tabeli.
Poznaj operatory i funkcje. Czytaj uważnie oficjalną dokumentację PostgreSQL, żeby lepiej rozumieć różnice między ->, ->>, @>, ?| i innymi funkcjami.
JSON i JSONB mogą być twoim sprzymierzeńcem w pracy z elastycznymi i złożonymi danymi. Najważniejsze – podchodź do wyboru narzędzi z głową i unikaj typowych błędów, żeby twój kod był wydajny i łatwy w utrzymaniu.
GO TO FULL VERSION