0Pricing
SQL Academy · Lekcja

Tabele faktów i wymiarów

Elementy składowe hurtowni danych

Tabele faktów i wymiarów to bezpłatna lekcja SQL Academy na CoddyKit. To lekcja 2 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej SQL Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs SQL Academy zawiera 4 lekcji w sumie.

Czym jest hurtownia danych?

Hurtownia danych to centralne repozytorium przeznaczone do raportowania i wykonywania zapytań analitycznych. W przeciwieństwie do bazy transakcyjnej, zoptymalizowanej pod kątem szybkich zapisów, hurtownia jest dostrojona do szybkiego odczytu dużych ilości danych historycznych.

Najczęstszym sposobem organizowania hurtowni jest użycie schematu gwiazdy, który dzieli dane na dwa typy tabel: tabele faktów i tabele wymiarów.

Definicja tabel faktów

Tabela faktów przechowuje mierzalne, ilościowe zdarzenia — informacje, które chcą Państwo analizować. Każdy wiersz reprezentuje jedno wystąpienie zdarzenia biznesowego, takiego jak sprzedaż, wyświetlenie strony internetowej lub zgłoszenie do pomocy technicznej.

Tabele faktów są zazwyczaj długie (wiele wierszy) i wąskie (niewiele kolumn), przy czym większość kolumn to klucze obce wskazujące tabele wymiarów albo miary liczbowe, takie jak quantity lub revenue.

CREATE TABLE fact_sales (
  sale_id      SERIAL PRIMARY KEY,
  date_key     INT NOT NULL,
  product_key  INT NOT NULL,
  customer_key INT NOT NULL,
  store_key    INT NOT NULL,
  quantity     INT NOT NULL,
  unit_price   NUMERIC(10, 2) NOT NULL,
  total_amount NUMERIC(12, 2) NOT NULL
);

Definicja tabel wymiarów

Tabela wymiarów przechowuje atrybuty opisowe, które nadają kontekst poszczególnym faktom. Przykładami są wymiar produktu (nazwa, kategoria, marka) oraz wymiar daty (dzień, miesiąc, kwartał, rok).

Tabele wymiarów są zwykle krótkie (mają mniej wierszy), ale szerokie (zawierają wiele kolumn opisowych). Są łączone z tabelą faktów za pomocą całkowitoliczbowych kluczy zastępczych.

CREATE TABLE dim_product (
  product_key  SERIAL PRIMARY KEY,
  product_name VARCHAR(200) NOT NULL,
  category     VARCHAR(100),
  brand        VARCHAR(100),
  unit_cost    NUMERIC(10, 2)
);

CREATE TABLE dim_customer (
  customer_key SERIAL PRIMARY KEY,
  full_name    VARCHAR(200) NOT NULL,
  email        VARCHAR(200),
  country      VARCHAR(100),
  segment      VARCHAR(50)
);

Wymiar daty

Wymiar daty jest najczęściej używanym wymiarem w każdej hurtowni danych. Zamiast przechowywać surową wartość TIMESTAMP w tabeli faktów, przechowuje się klucz całkowitoliczbowy wskazujący wstępnie utworzoną tabelę kalendarza.

Dzięki temu zapytania mogą filtrować dane lub grupować je według kwartału fiskalnego, dnia tygodnia, oznaczenia święta i innych atrybutów kalendarza bez wykonywania operacji na datach w czasie zapytania.

CREATE TABLE dim_date (
  date_key       INT PRIMARY KEY,  -- e.g. 20240315
  full_date      DATE NOT NULL,
  day_of_week    VARCHAR(10),
  day_of_month   INT,
  month_num      INT,
  month_name     VARCHAR(20),
  quarter        INT,
  year           INT,
  is_holiday     BOOLEAN DEFAULT FALSE,
  fiscal_quarter INT
);

-- Sample row
INSERT INTO dim_date VALUES
  (20240315, '2024-03-15', 'Friday', 15, 3, 'March', 1, 2024, FALSE, 2);

Wzorzec schematu gwiazdy

Gdy na diagramie narysują Państwo jedną tabelę faktów w centrum oraz tabele wymiarów rozchodzące się na zewnątrz, całość przypomina gwiazdę — stąd nazwa schemat gwiazdy.

Klucze obce w tabeli faktów wskazują klucze główne poszczególnych wymiarów. Zapytania zwykle łączą tabelę faktów z jednym lub większą liczbą wymiarów, aby dodać opisowy kontekst do surowych wartości liczbowych.

-- Join fact to two dimensions to enrich a sales report
SELECT
  dp.product_name,
  dp.category,
  SUM(fs.quantity)     AS total_units_sold,
  SUM(fs.total_amount) AS total_revenue
FROM fact_sales fs
JOIN dim_product  dp ON dp.product_key  = fs.product_key
JOIN dim_date     dd ON dd.date_key     = fs.date_key
WHERE dd.year = 2024
GROUP BY dp.product_name, dp.category
ORDER BY total_revenue DESC;

Klucze zastępcze a klucze naturalne

Tabele wymiarów używają kluczy zastępczych — sztucznych liczb całkowitych generowanych przez bazę danych, niezależnych od jakiegokolwiek znaczenia biznesowego. Klucze naturalne (takie jak SKU produktu lub adres e-mail klienta) mogą z czasem ulegać zmianie, ale klucze zastępcze pozostają niezmienne.

Użycie kluczy zastępczych izoluje tabelę faktów od zmian w systemach źródłowych i przyspiesza złączenia, ponieważ porównywanie liczb całkowitych jest tańsze niż porównywanie ciągów znaków.

-- Surrogate key approach: integer join is fast
SELECT fs.sale_id, dc.full_name, fs.total_amount
FROM fact_sales fs
JOIN dim_customer dc ON dc.customer_key = fs.customer_key
WHERE dc.country = 'Germany'
LIMIT 10;

-- Natural key approach (avoid in warehouses): slower string join
-- JOIN dim_customer dc ON dc.email = fs.customer_email

Ziarno: poziom szczegółowości w tabeli faktów

Ziarno tabeli faktów dokładnie określa, co reprezentuje jeden wiersz. Przed zbudowaniem hurtowni należy określić ziarno — na przykład jeden wiersz na pojedynczą pozycję produktu w zamówieniu sprzedaży.

Dobrze zdefiniowane ziarno zapobiega niejednoznacznym agregacjom. Jeśli różne wiersze reprezentują różne zdarzenia, wyniki funkcji SUM i COUNT będą pozbawione znaczenia.

-- Grain: one row per product per order line
-- Each row = one line item sold in one transaction
SELECT
  sale_id,
  date_key,
  product_key,
  quantity,
  unit_price,
  total_amount
FROM fact_sales
WHERE date_key = 20240315
ORDER BY sale_id;

Miary addytywne, częściowo addytywne i nieaddytywne

Fakty dzielą się na trzy kategorie w zależności od sposobu ich agregowania:

  • Addytywne — można je sumować we wszystkich wymiarach (np. revenue, quantity).
  • Częściowo addytywne — można je sumować w niektórych wymiarach, ale nie we wszystkich (np. balance konta można sumować według klientów, ale nie według czasu).
  • Nieaddytywne — nie można ich sensownie sumować (np. unit_price, ratio). Zamiast tego należy użyć funkcji AVG lub innych agregacji.
SELECT
  dd.month_name,
  SUM(fs.total_amount)         AS total_revenue,   -- additive
  AVG(fs.unit_price)           AS avg_unit_price,   -- non-additive: use AVG
  SUM(fs.quantity)             AS total_units       -- additive
FROM fact_sales fs
JOIN dim_date dd ON dd.date_key = fs.date_key
WHERE dd.year = 2024
GROUP BY dd.month_name, dd.month_num
ORDER BY dd.month_num;

Wolno zmieniające się wymiary (SCD typu 1 i 2)

Atrybuty wymiarów zmieniają się z czasem — klient zmienia kraj, a produkt kategorię. Wolno zmieniające się wymiary (SCD) obsługują te zmiany:

  • Typ 1 — nadpisanie starej wartości. To proste rozwiązanie, ale historia zostaje utracona.
  • Typ 2 — dodanie nowego wiersza z nowym kluczem zastępczym i datami obowiązywania. Zachowuje pełną historię, dzięki czemu fakty historyczne nadal wskazują właściwą wersję wymiaru.
-- SCD Type 2: add a new version of the row
ALTER TABLE dim_customer ADD COLUMN valid_from DATE;
ALTER TABLE dim_customer ADD COLUMN valid_to   DATE;
ALTER TABLE dim_customer ADD COLUMN is_current BOOLEAN DEFAULT TRUE;

-- Expire the old row
UPDATE dim_customer
SET is_current = FALSE,
    valid_to   = CURRENT_DATE - INTERVAL '1 day'
WHERE email = 'anna@example.com' AND is_current = TRUE;

-- Insert the updated version
INSERT INTO dim_customer (full_name, email, country, segment, valid_from, valid_to, is_current)
VALUES ('Anna Muller', 'anna@example.com', 'Austria', 'Premium', CURRENT_DATE, '9999-12-31', TRUE);

Wymiary zdegenerowane

Czasami atrybut wymiaru nie wymaga własnej tabeli. Wymiar zdegenerowany to klucz wymiaru znajdujący się bezpośrednio w tabeli faktów, bez odpowiadającej mu tabeli wymiaru.

Klasycznymi przykładami są numery zamówień, numery faktur lub identyfikatory zgłoszeń. Zapewniają one kontekst podczas drążenia danych, ale nie mają innych opisowych kolumn, które warto byłoby przechowywać w oddzielnej tabeli.

-- order_number is a degenerate dimension:
-- it lives in the fact table, no dim_order table needed
CREATE TABLE fact_order_lines (
  line_id      SERIAL PRIMARY KEY,
  order_number VARCHAR(20) NOT NULL,  -- degenerate dimension
  date_key     INT NOT NULL,
  product_key  INT NOT NULL,
  customer_key INT NOT NULL,
  quantity     INT NOT NULL,
  line_total   NUMERIC(12, 2) NOT NULL
);

SELECT order_number, SUM(line_total) AS order_total
FROM fact_order_lines
GROUP BY order_number
ORDER BY order_total DESC
LIMIT 5;

Zapytania w pełnym schemacie gwiazdy

Podsumowując: typowe zapytanie do hurtowni łączy tabelę faktów z kilkoma wymiarami, stosuje filtry dotyczące atrybutów wymiarów i agreguje miary z tabeli faktów.

Optymalizator może wydajnie obsługiwać te złączenia wielostronne, ponieważ klucze obce tabeli faktów są indeksowane, a tabele wymiarów są stosunkowo małe.

SELECT
  dd.year,
  dd.quarter,
  dp.category,
  dc.country,
  SUM(fs.quantity)     AS units_sold,
  SUM(fs.total_amount) AS revenue
FROM fact_sales fs
JOIN dim_date     dd ON dd.date_key     = fs.date_key
JOIN dim_product  dp ON dp.product_key  = fs.product_key
JOIN dim_customer dc ON dc.customer_key = fs.customer_key
WHERE dd.year IN (2023, 2024)
  AND dp.category = 'Electronics'
GROUP BY dd.year, dd.quarter, dp.category, dc.country
ORDER BY dd.year, dd.quarter, revenue DESC;

Szybkie sprawdzenie: fakt czy wymiar

Proszę sprawdzić swoją wiedzę na temat różnic między tabelami faktów i tabelami wymiarów w schemacie gwiazdy.

Podsumowanie lekcji

W tej lekcji poznali Państwo podstawowe elementy schematu gwiazdy w hurtowni danych:

  • Tabele faktów przechowują mierzalne zdarzenia (sprzedaż, kliknięcia, transakcje) wraz z miarami liczbowymi i kluczami obcymi.
  • Tabele wymiarów dostarczają opisowego kontekstu (kto, co, gdzie, kiedy) i korzystają z kluczy zastępczych.
  • Ziarno dokładnie określa, co reprezentuje jeden wiersz faktów — należy je określić przed rozpoczęciem budowy.
  • Miary mogą być addytywne, częściowo addytywne lub nieaddytywne, co decyduje o sposobie ich agregowania.
  • SCD typu 2 zachowuje historyczne wartości wymiarów, dodając nowe wiersze z datami obowiązywania.
  • Wymiary zdegenerowane znajdują się w tabeli faktów, gdy nie mają dodatkowych atrybutów opisowych.

Zrozumienie tabel faktów i tabel wymiarów stanowi podstawę budowania szybkich, skalowalnych i wydajnych analitycznie hurtowni danych.

Często zadawane pytania

Czy lekcja „Tabele faktów i wymiarów” jest bezpłatna?

Tak — pełny tekst „Tabele faktów i wymiarów” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu SQL Academy, przejdź na CoddyKit PRO. Kurs SQL Academy zawiera 4 lekcji w sumie.

Co nauczysz się w „Tabele faktów i wymiarów”?

Elementy składowe hurtowni danych Ćwiczysz SQL Academy z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.

Czy potrzebuję doświadczenia, aby zacząć SQL Academy?

Nie wymagamy żadnego doświadczenia. SQL Academy w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 2 z 4.

Ile czasu zajmuje lekcja „Tabele faktów i wymiarów”?

Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.

Czy mogę pisać i uruchamiać kod w tej lekcji SQL Academy?

Tak. Każda lekcja SQL Academy zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.

Wszystkie lekcje w tym kursie

  1. OLTP a OLAP
  2. Tabele faktów i wymiarów
  3. Schematy gwiazdy i płatka śniegu
  4. Pisanie zapytań analitycznych
← Powrót do SQL Academy