Raport z bazy danych: jak go zrobić i komu go oddać
Raport to jedna powtarzalna odpowiedź na jedno pytanie, wydana o umówionej porze i w umówionym formacie; dashboard to ekran do przeglądania i klikania. Żeby raport generował się sam, potrzebujesz trzech rzeczy: źródła, którym nie jest baza produkcyjna pod ciężkim zapytaniem, obiektu w bazie, czyli widoku, widoku materializowanego albo procedury, oraz harmonogramu, czyli SQL Server Agent, elastic jobs w Azure SQL Database albo pg_cron w PostgreSQL. Na każdym wydaniu musi być data i godzina danych, bo inaczej nikt nie odróżni raportu z wczoraj od dzisiejszego. Raport ma chodzić na osobnym koncie z prawem odczytu, nigdy na koncie administratora bazy. Harmonogram w narzędziu BI bywa limitowany: Power BI na współdzielonej pojemności dopuszcza osiem zaplanowanych odświeżeń dziennie, a na pojemności Premium, PPU lub Fabric do 48; stan na 21 września 2026 r.
Raport a dashboard: rozstrzygnij to, zanim wybierzesz narzędzie
To jest rozróżnienie, którego zwykle nie ma człowiek szukający „raportu z bazy danych”, a decyduje o całej reszcie: o narzędziu, o kosztach i o tym, kto będzie to utrzymywał.
Raport jest dokumentem. Ma ustaloną treść, ustalony moment powstania i odbiorcę, który go czyta, a nie klika. Raport da się wydrukować, wysłać księgowej, dołączyć do wniosku kredytowego i odłożyć do folderu, żeby za rok sprawdzić, co wtedy pokazywał. Jego wartość bierze się z tego, że jest zawsze taki sam i zawsze przychodzi.
Dashboard, po polsku pulpit, jest ekranem do zadawania pytań. Zmieniasz zakres dat, filtrujesz po oddziale, klikasz w słupek i schodzisz poziom niżej. Pulpit ma sens, gdy ktoś siada do niego regularnie i szuka, a nie wtedy, gdy raz na miesiąc potrzebuje jednej liczby.
Najprostszy test jest taki: czy tę odpowiedź ktoś musi komuś przekazać poza systemem? Jeśli tak, czyli jeśli liczba idzie do maila, do banku, do zarządu albo do arkusza, w którym ktoś liczy dalej, zamawiasz raport. Jeśli odpowiedź żyje tylko w głowie osoby, która na nią patrzy, i za pięć minut zada kolejne pytanie, zamawiasz pulpit.
Ta pomyłka kosztuje najwięcej na początku. Firma pisze „potrzebujemy raportów z bazy”, dostaje ofertę na narzędzie BI z licencjami dla wszystkich, a naprawdę potrzebuje jednego pliku w każdy poniedziałek o siódmej. Odwrotnie bywa równie drogo: ktoś zamawia „ten jeden raport”, a po pół roku ma czternaście wariantów tego samego pliku i nikt nie wie, który jest aktualny.
- Zamawiasz raport, gdyOdbiorca ma stałą listę pytań, czyta o stałej porze, potrzebuje pliku albo maila i musi móc wrócić do wersji sprzed miesiąca.
- Zamawiasz pulpit, gdyOdbiorca sam drąży dane, zmienia filtry, porównuje okresy i patrzy na to częściej niż raz dziennie.
- Zamawiasz jedno i drugie, gdyZarząd chce pliku, a operacje chcą ekranu. Wtedy oba mają czytać z tego samego obiektu w bazie, inaczej za kwartał pokażą różne liczby.
Skąd brać dane: baza produkcyjna, replika czy kopia
Ciężkie zapytanie raportowe skanuje szerokie zakresy dat i łączy kilka dużych tabel. Na bazie produkcyjnej rywalizuje o procesor, pamięć i dysk z tym, co robi klient w koszyku.
Raport konkuruje o zasoby z aplikacją, bo uderza w tę samą maszynę. Weź hipotetyczne zapytanie, które na spokojnej bazie liczy się kilka sekund: w szczycie ten sam plan wykonania walczy o procesor, pamięć i dysk z tym, co robi klient w koszyku, więc trwa dłużej i wydłuża czas odpowiedzi aplikacji. Nie podam tu, o ile, bo to zależy od planu zapytania, wolumenu i sprzętu, a każda liczba bez Twojej bazy byłaby zgadywaniem. Dlatego pierwsza decyzja projektowa dotyczy nie SQL-a, tylko tego, w którą maszynę uderza zapytanie.
Replika to druga kopia bazy, która sama nadąża za pierwszą i przyjmuje wyłącznie odczyty. W PostgreSQL odpowiada za to hot standby: dokumentacja mówi wprost, że po włączeniu tego trybu serwer przyjmuje połączenia, ale wszystkie są ściśle tylko do odczytu, bo nie zapiszesz na nim nawet tabeli tymczasowej. Polecenia INSERT, UPDATE, DELETE i cała warstwa DDL kończą się na replice błędem.
Replika ma jednak swoją cenę i warto ją znać przed wdrożeniem. Dane na standby są, jak to nazywa dokumentacja PostgreSQL, ostatecznie spójne z bazą główną, więc czytasz stan sprzed pewnej chwili. Do tego dochodzą konflikty zapytań: gdy na bazie głównej ktoś wykona operację wymagającą wyłącznego zamka, replika musi albo wstrzymać odtwarzanie dziennika, albo przerwać Twoje zapytanie. Sterują tym parametry max_standby_streaming_delay i max_standby_archive_delay, a wartość -1 oznacza czekanie w nieskończoność na zakończenie zapytania, kosztem rosnącego opóźnienia repliki.
W Azure SQL Database mechanizm nazywa się read scale-out i działa inaczej, niż wielu ludzi zakłada. Repliki tylko do odczytu są w warstwach Premium, Business Critical i Hyperscale; w Basic, Standard i General Purpose ich nie ma, więc tam nie masz na czym odciążyć produkcji. Połączenie kierujesz na replikę, dopisując do parametrów połączenia ApplicationIntent=ReadOnly, a sprawdzisz to zapytaniem SELECT DATABASEPROPERTYEX(DB_NAME(), 'Updateability'), które na replice zwróci READ_ONLY. Typowe opóźnienie propagacji Microsoft opisuje jako zakres od dziesiątek milisekund do pojedynczych sekund, ale zaznacza, że nie ma stałej górnej granicy.
Kopia to trzecia droga i najczęściej najtańsza, gdy raport ma być dzienny albo rzadszy. Zrzucasz bazę raz na dobę i liczysz raport na zrzucie, na osobnej maszynie, gdzie nikomu nie zaszkodzisz. Sprawdziłem w dokumentacji PostgreSQL, jak zachowuje się pg_dump: nie blokuje innych użytkowników, ani czytających, ani piszących, i robi spójny eksport nawet wtedy, gdy baza jest w tym czasie używana. Warto pamiętać o pułapce zrzutu równoległego, bo przy opcji -j proces pomocniczy, który nie dostanie współdzielonego zamka, przerywa cały zrzut, żeby nie doszło do zakleszczenia.
Jeśli mimo wszystko musisz uderzyć w produkcję, załóż raportowi bezpiecznik. W PostgreSQL służy do tego statement_timeout, czyli przerwanie polecenia trwającego dłużej niż zadany czas; domyślna wartość zero oznacza brak limitu. Dokumentacja odradza ustawianie tego parametru globalnie w postgresql.conf, bo dotknąłby wszystkich sesji, więc ustaw go osobno dla roli raportowej albo dla samej sesji raportu.
| Źródło | Wpływ na sprzedaż | Świeżość danych | Kiedy wybrać |
|---|---|---|---|
| Baza produkcyjna | Największy: raport konkuruje z aplikacją o te same zasoby. | Stan bieżący, co do sekundy. | Tylko dla lekkich zapytań, z ustawionym limitem czasu i poza godzinami szczytu. |
| Replika tylko do odczytu | Żaden przy odczycie, ale długie zapytanie może opóźnić nadążanie repliki. | Opóźniona o zmienną, niegwarantowaną wartość. | Raporty w ciągu dnia i pulpity, gdy warstwa usługi w ogóle daje repliki. |
| Kopia lub zrzut | Żaden po zakończeniu zrzutu; sam zrzut nie blokuje czytających ani piszących. | Stan z momentu zrzutu, zwykle nocny. | Raporty dzienne, tygodniowe i miesięczne, czyli większość tego, co zamawiają firmy. |
Widok, zapisane zapytanie, procedura i widok materializowany
Te cztery rzeczy mylą się nawet programistom, a różnica między nimi sprowadza się do jednego pytania: czy coś trzyma wynik, i jeśli tak, to kto go odświeża.
Zapisane zapytanie to po prostu plik z SQL-em w repozytorium. Nie istnieje w bazie, więc nikt go przypadkiem nie skasuje ani nie podmieni, i masz historię zmian razem z resztą kodu. Wadą jest to, że każdy, kto chce z niego skorzystać, musi mieć ten plik i klienta bazy.
Widok to nazwana definicja zapytania wewnątrz bazy. Najważniejsza rzecz, której ludzie po nim oczekują, a której on nie robi: widok nie przechowuje danych. Dokumentacja PostgreSQL stwierdza to jednym zdaniem, czyli że zapytanie jest uruchamiane za każdym razem, gdy widok zostanie użyty. Widok porządkuje i ukrywa złożoność, ale sam z siebie nie przyspiesza niczego.
Widok materializowany trzyma wynik w postaci podobnej do tabeli i dlatego czyta się go znacznie szybciej niż tabele źródłowe. Cena jest taka, że nie odświeża się sam. Polecenie REFRESH MATERIALIZED VIEW całkowicie zastępuje zawartość widoku, a bez klauzuli CONCURRENTLY potrafi zablokować połączenia, które właśnie próbują z tego widoku czytać. Klauzula CONCURRENTLY zdejmuje tę blokadę, ale wymaga co najmniej jednego unikalnego indeksu zbudowanego wyłącznie z nazw kolumn i obejmującego wszystkie wiersze, a widok musi być już wypełniony. Do tego tylko jedno odświeżanie naraz może chodzić na danym widoku. Sama dokumentacja PostgreSQL podpowiada przy okazji wzorzec, o który chodzi w tym przewodniku: zadanie zaplanowane na noc, które wykonuje REFRESH MATERIALIZED VIEW na widoku z podsumowaniem sprzedaży.
W SQL Server najbliższym odpowiednikiem jest widok indeksowany, ale zasada działania jest inna i trzeba to rozumieć przed decyzją. Pierwszy indeks założony na widoku musi być unikalnym indeksem klastrowym, widok trzeba utworzyć z opcją WITH SCHEMABINDING, a jego definicja musi być deterministyczna. Taki widok jest utrzymywany na bieżąco, więc każdy INSERT, UPDATE i DELETE na tabelach źródłowych musi zaktualizować także widoki indeksowane. Microsoft ostrzega wprost, że przy dużej liczbie takich widoków wydajność operacji zapisu może się znacząco pogorszyć, a czasem plan zapytania w ogóle nie powstanie. Drobiazg, który zaskakuje przy wdrożeniu: w edycji Standard, żeby czytać wprost z widoku indeksowanego, trzeba dopisać podpowiedź NOEXPAND, podczas gdy Azure SQL Database i Azure SQL Managed Instance używają go automatycznie.
Procedura jest miejscem na kroki, a nie na jedno zapytanie. Wywołujesz ją poleceniem CALL i w PostgreSQL może, w odróżnieniu od funkcji, sterować transakcją, czyli wykonywać COMMIT i ROLLBACK. Warto znać wyjątek: procedura zadeklarowana jako SECURITY DEFINER nie może wykonywać poleceń sterowania transakcją. Procedurę wybierasz wtedy, gdy raport to sekwencja: wyczyść tabelę wyników, policz, zapisz, oznacz datę i godzinę, zapisz wpis do dziennika.
Moja zasada jest prosta. Zaczynaj od widoku, bo jest najtańszy w utrzymaniu i niczego nie duplikuje. Przejdź na widok materializowany dopiero wtedy, gdy zmierzysz, że zapytanie trwa za długo, i gdy jesteś w stanie powiedzieć, o ile stare dane są jeszcze akceptowalne. Po procedurę sięgaj, gdy pojawia się więcej niż jeden krok albo trzeba zapisać ślad wykonania.
Harmonogram: jak sprawić, żeby raport generował się sam
Raport, który ktoś musi uruchomić ręcznie, prędzej czy później przestaje przychodzić. Harmonogram jest tą częścią, którą najczęściej pomija się w wycenie, a która decyduje o tym, czy rozwiązanie przeżyje rok.
Wybór narzędzia do harmonogramu zależy głównie od tego, gdzie stoi baza, a nie od tego, co lubi wykonawca. Niżej cztery drogi, które realnie występują w polskich firmach, wraz z ich ograniczeniami wziętymi z dokumentacji.
Niezależnie od wybranego narzędzia trzy rzeczy muszą być w zakresie od początku. Po pierwsze dziennik uruchomień, żeby dało się odpowiedzieć na pytanie, czy raport w ogóle się wykonał. Po drugie powiadomienie o błędzie kierowane do człowieka, a nie do skrzynki, której nikt nie czyta. Po trzecie skrypt odporny na powtórzenie: dokumentacja elastic jobs mówi wprost, że skrypty mają być idempotentne, bo zadanie samo ponawia wykonanie po błędzie sieci, a raport policzony dwa razy nie może wygenerować dwóch kompletów danych.
- SQL Server AgentUsługa Windows, która wykonuje zaplanowane zadania w SQL Server i w Azure SQL Managed Instance. Zadanie składa się z kroków, może chodzić według harmonogramu, w reakcji na zdarzenie albo na żądanie przez sp_start_job, a o niepowodzeniu poinformuje operatora. Pułapka instalacyjna: usługa Agenta jest domyślnie wyłączona po instalacji SQL Server, chyba że ktoś świadomie włączył jej automatyczny start.
- Elastic jobs w Azure SQL DatabaseW Azure SQL Database nie ma Agenta i to zaskakuje przy migracji. Zastępują go elastic jobs: uruchamiają skrypty T-SQL cyklicznie na jednej albo wielu bazach, logują status, same ponawiają operacje po błędzie, a historię wykonań czyści zadanie porządkowe po 45 dniach. Uwaga na strefę: wszystkie daty i godziny w elastic jobs są w czasie UTC.
- pg_cron w PostgreSQLRozszerzenie, które uruchamia zadania wewnątrz samej bazy, ze składnią znaną z crona. Wymaga wpisania pg_cron do shared_preload_libraries i restartu, a instaluje się tylko w jednej bazie w klastrze. Bardzo ważne dla tego tematu: pg_cron nie uruchamia żadnych zadań, dopóki serwer jest w trybie hot standby, więc nie zaplanujesz odświeżania na replice.
- Zadanie w systemie operacyjnymCron na Linuksie albo Harmonogram zadań w Windows, uruchamiający skrypt. Najprostsze do postawienia i najłatwiejsze do zgubienia, bo żyje na konkretnej maszynie i trzyma gdzieś dane logowania do bazy. Jeśli wybierasz tę drogę, zapisz w dokumentacji, na którym serwerze to stoi.
- Harmonogram w narzędziu BIWygodny, ale limitowany. Power BI ogranicza modele na współdzielonej pojemności do ośmiu zaplanowanych odświeżeń dziennie, a pula ta zeruje się codziennie o 00:01 czasu lokalnego ustawionego w modelu. Na pojemności Premium, PPU lub Fabric zaplanujesz do 48 odświeżeń dziennie.
Format wyjścia: Excel, PDF, mail czy link do panelu
Format wybiera się pod odbiorcę i pod to, co on zrobi z liczbą w następnym kroku. To jedna decyzja, a przesądza o połowie pracy.
Excel wybierasz, gdy odbiorca będzie liczył dalej: doklei kolumnę, zrobi tabelę przestawną, wklei do własnego modelu. Wtedy raport ma być płaską tabelą z nagłówkami, bez scalonych komórek i bez ozdób, bo każda ozdoba psuje filtrowanie. PDF wybierasz wtedy, gdy dokument ma być niezmienny: idzie do archiwum, do banku, do akt sprawy albo pod podpis.
Mail wybierasz, gdy wiesz, że odbiorca nie wejdzie do żadnego panelu. To nie jest złośliwość wobec odbiorcy, tylko realia: właściciel firmy czyta w telefonie między spotkaniami i chce mieć trzy liczby w treści wiadomości, a szczegóły w załączniku. Link do panelu wybierasz, gdy dane zmieniają się w ciągu dnia albo gdy odbiorców jest wielu i każdy ma widzieć swój wycinek.
Po stronie SQL Server gotowym mechanizmem jest subskrypcja w Reporting Services. Dokumentacja opisuje ją jako konfigurację, która dostarcza raport o określonej porze albo w reakcji na zdarzenie i w formacie, który wskażesz. Dostępne drogi dostarczania to udział plikowy Windows, poczta elektroniczna i biblioteka SharePoint, a dla odbiorcy wskazanego w subskrypcji do wyboru są między innymi XML, CSV, PDF, MHTML, Excel, TIFF i Word.
Dwie rzeczy w subskrypcjach zaskakują przy wdrożeniu, więc sprawdziłem je w dokumentacji. Pierwsza: raport, do którego tworzysz subskrypcję, musi korzystać z zapisanych poświadczeń albo z żadnych, bo nie zasubskrybujesz raportu, który łączy się do źródła jako bieżący użytkownik. Druga: subskrypcje nie są dostępne w każdej edycji SQL Server, więc przed obietnicą „będzie przychodzić mailem” warto sprawdzić, jaką edycję ma firma.
Jeśli odbiorców jest wielu i każdy ma dostać własną wersję tego samego raportu, służy do tego subskrypcja sterowana danymi. Zapytanie zwraca listę odbiorców razem z parametrami i formatem, a serwer tworzy po jednej przesyłce na każdy wiersz wyniku. To rozwiązuje przypadek „każdy kierownik oddziału ma dostać swój oddział” bez budowania czternastu osobnych raportów.
Definicje wskaźników: dlaczego dwa działy mają różne liczby
Prawie nigdy nie jest tak, że jedna strona się myli. Zwykle obie liczą poprawnie, tylko liczą coś innego, bo nikt nigdy nie zapisał, co dokładnie znaczy słowo używane w pytaniu.
Weź jedno słowo: sprzedaż. Czy liczy się datą zamówienia, czy datą faktury? Z podatkiem czy bez? Czy odejmujesz zwroty, a jeśli tak, to w miesiącu zamówienia czy w miesiącu zwrotu? Czy wliczasz koszt dostawy? Czy zamówienia anulowane w tym samym dniu w ogóle się pojawiają? Każda z tych odpowiedzi jest sensowna, a każda daje inną liczbę. Dopóki sprzedaż i księgowość odpowiadają inaczej, spór o raport jest sporem o definicję, a nie o SQL.
Rozwiązuje się to raz i w jednym miejscu, nie na każdym raporcie osobno. Definicję zapisujesz zdaniem po polsku, razem z listą wykluczeń, a potem implementujesz ją dokładnie raz: jako widok, procedurę albo miarę w modelu danych. Wszystko inne ma czytać z tego obiektu, zamiast kopiować sobie zapytanie. Kopiowane zapytanie żyje własnym życiem i po pierwszej poprawce zaczyna się rozjeżdżać.
Zapisz definicję tam, gdzie jest kod, a nie tylko w notatce. Komentarz przy obiekcie w bazie i akapit w repozytorium przeżyją zmianę osoby na stanowisku, a ustalenie ze spotkania nie przeżyje. Gdy definicja się zmienia, zmieniasz ją w jednym miejscu i dopisujesz na raporcie krótką notkę, od kiedy obowiązuje nowa; bez tej notki ktoś porówna dwa okresy liczone różnie i wyciągnie fałszywy wniosek.
- Zapisz pytanie jednym zdaniemNa przykład: ile przychodu bez podatku wygenerowały zamówienia opłacone w danym miesiącu. Jedno zdanie, bez „i jeszcze”.
- Wypisz wykluczeniaZwroty, anulowane, testowe, zamówienia pracowników, zamówienia z kuponem stuprocentowym. To one różnicują wyniki działów.
- Wskaż osobę rozstrzygającąJedna osoba w firmie ma prawo powiedzieć, jak brzmi definicja. Bez tego spór wraca przy każdym raporcie.
- Zaimplementuj razJeden obiekt w bazie albo jedna miara w modelu. Każdy nowy raport czyta z niego, zamiast pisać własną wersję.
- Oznaczaj zmiany definicjiData zmiany widoczna na raporcie i wpis w repozytorium. Porównywanie okresów liczonych różnymi definicjami to najczęstszy sposób na złą decyzję.
Świeżość danych i dlaczego na raporcie musi być data z godziną
Raport bez znacznika czasu jest bezużyteczny w chwili, gdy ktoś go prześle dalej. Za tydzień nikt nie odróżni pliku z poniedziałku od pliku ze środy.
Na raporcie powinny być dwa czasy, nie jeden, i to jest rozróżnienie, które oszczędza najwięcej nieporozumień. Pierwszy to moment wygenerowania dokumentu. Drugi to moment, do którego dane są kompletne. Gdy raport liczy się na nocnym zrzucie, a wysyła o ósmej rano, te dwie wartości dzieli kilka godzin i wszystko, co wydarzyło się rano, nie jest w środku.
Ta różnica ma pokrycie w mechanice źródeł. Czytając z repliki, czytasz stan sprzed pewnej chwili, a Microsoft w dokumentacji read scale-out zaznacza, że typowe opóźnienie mieści się między dziesiątkami milisekund a pojedynczymi sekundami, lecz stałej górnej granicy nie ma. Czytając z widoku materializowanego, czytasz stan z ostatniego odświeżenia, bo ten obiekt nie aktualizuje się sam. W obu przypadkach liczba na ekranie jest prawdziwa, tylko dotyczy innego momentu, niż zakłada czytający.
Praktyczne minimum w stopce każdego wydania wygląda tak: dane do dnia i godziny, moment wygenerowania, źródło i wersja definicji. Cztery linijki, które zamykają większość sporów, zanim się zaczną.
Strefa czasowa to osobna pułapka i warto ją sprawdzić na samym początku. Elastic jobs w Azure SQL Database operują wyłącznie w czasie UTC, więc raport ustawiony na północ wyląduje w Polsce o pierwszej albo drugiej w nocy, zależnie od pory roku, i obetnie dobę w innym miejscu, niż spodziewa się odbiorca. Harmonogram odświeżania w Power BI działa z kolei w strefie wybranej w ustawieniach modelu, a pula ośmiu odświeżeń na wspólnej pojemności zeruje się o 00:01 czasu lokalnego. Jeśli raport ma zamykać dobę zgodnie z polskim kalendarzem, sprawdź to zawczasu, bo pierwszym objawem błędu jest wynik niezgodny z systemem sprzedażowym o kilka punktów obrotu.
Uprawnienia: kto widzi co i dlaczego nie konto administratora
Raport chodzący na koncie administratora jest najkrótszą drogą do tego, żeby przypadkowy błąd w zapytaniu albo wyciek jednego pliku kosztował całą bazę.
Konto raportowe ma robić dokładnie jedną rzecz: czytać dane, których raport potrzebuje. Nie ma prawa zapisu, nie ma prawa do zmiany schematu, nie ma prawa do kasowania. To nie jest przesada, tylko ograniczenie szkody. Konto administratora, które siedzi w harmonogramie i ma zapisane hasło, prędzej czy później trafi w ręce, dla których nie było przeznaczone.
W PostgreSQL najprostszym punktem wyjścia jest predefiniowana rola pg_read_all_data. Dokumentacja opisuje ją jako prawo do odczytu wszystkich danych, czyli tabel, widoków i sekwencji, tak jakby rola miała uprawnienie SELECT na tych obiektach i USAGE na wszystkich schematach. Trzeba przy tym wiedzieć, że ta rola nie omija zabezpieczeń na poziomie wiersza.
Zabezpieczenie na poziomie wiersza, czyli RLS, jest tym, czego potrzebujesz, gdy jeden raport ma pokazywać każdemu tylko jego wycinek. Włącza się je poleceniem ALTER TABLE ... ENABLE ROW LEVEL SECURITY, a gdy dla tabeli nie ma żadnej polityki, działa domyślna odmowa i nie widać ani jednego wiersza. Tu kryje się pułapka, która potrafi wywrócić całą konfigurację: superużytkownicy i role z atrybutem BYPASSRLS zawsze omijają ten mechanizm, a właściciel tabeli również go normalnie omija, chyba że świadomie włączysz ALTER TABLE ... FORCE ROW LEVEL SECURITY. Raport uruchamiany jako właściciel tabeli zobaczy więc wszystko, mimo poprawnie napisanych polityk.
W SQL Server odpowiednikiem konta do odczytu jest członkostwo w roli db_datareader, która pozwala czytać wszystkie dane ze wszystkich tabel i widoków użytkownika. Po przeciwnej stronie stoi db_owner, która ma uprawnienie CONTROL DATABASE, czyli komplet uprawnień w bazie, a w SQL Server pozwala nawet usunąć bazę danych. Jeżeli konto raportowe ma db_owner, to nie jest konto raportowe.
W samym harmonogramie kontekst bezpieczeństwa też jest osobną decyzją. W SQL Server Agent kroki typu Transact-SQL ustawiają kontekst poleceniem EXECUTE AS, a pozostałe rodzaje kroków korzystają z konta pośredniczącego, czyli proxy, które ma dostęp tylko do wskazanych podsystemów. Dostęp do samego Agenta dla osób spoza roli serwerowej sysadmin nadaje się przez role w bazie msdb, takie jak SQLAgentUserRole, SQLAgentReaderRole i SQLAgentOperatorRole.
Na koniec rzecz, o której zapomina się najczęściej, bo leży poza bazą. Plik wygenerowany przez raport dziedziczy uprawnienia folderu, w którym wylądował, a nie uprawnienia bazy. Świetnie zabezpieczony raport zapisany na otwartym dysku sieciowym jest otwartym raportem. To samo dotyczy załącznika w mailu, który ktoś przekaże dalej jednym kliknięciem.
Cztery drogi do tego samego raportu i czym się różnią
Zanim wybierzesz, sprawdź nie to, jak szybko coś powstanie, tylko co się stanie, gdy za trzy miesiące odbiorca zmieni pytanie. To ten koszt zjada budżety.
Czytaj tę tabelę od prawej strony. Kolumna o zmianie pytania mówi więcej o rzeczywistym koszcie niż kolumna o czasie powstania, bo pytania w firmie zmieniają się zawsze, a pierwsze uruchomienie jest tylko raz.
| Droga | Kto to utrzymuje | Jak szybko powstaje | Zmiana pytania | Kto może to czytać |
|---|---|---|---|---|
| Zapytanie ad hoc | Osoba, która je napisała; poza jej głową nie istnieje nic. | Najszybciej, zwykle w ramach jednej rozmowy. | Trzeba poprosić tę samą osobę i czekać; przy jej nieobecności raportu nie ma. | Tylko ktoś z dostępem do bazy i klienta SQL. |
| Widok albo procedura z harmonogramem | Firma, bo definicja leży w bazie i w repozytorium, a nie w czyichś notatkach. | Szybko, gdy dane są w jednym miejscu i definicja jest uzgodniona. | Poprawka w jednym obiekcie; nowy przekrój bywa nowym obiektem. | Każdy odbiorca pliku albo maila, bez dostępu do bazy. |
| Narzędzie BI | Firma, ale wymaga osoby, która zna to konkretne narzędzie i pilnuje odświeżania. | Średnio; najwięcej czasu zajmuje model danych, nie wykresy. | Odbiorca często zmienia sam, filtrami; głębsza zmiana wymaga poprawki modelu. | Zależy od licencji i uprawnień w narzędziu; przy wielu odbiorcach to bywa główny koszt. |
| Własny panel | Wykonawca albo zespół; to jest oprogramowanie, z utrzymaniem i aktualizacjami. | Najdłużej ze wszystkich czterech dróg. | Zmiana to praca programisty, ale można ją dowolnie dopasować. | Dowolna osoba, także klient z zewnątrz, z uprawnieniami ustawionymi przez Ciebie. |
Kiedy to jest praca na godziny, a kiedy osobny projekt
Granica nie biegnie tam, gdzie zwykle się ją zakłada. Nie chodzi o trudność zapytania, tylko o to, ile rzeczy trzeba uzgodnić, zanim ktokolwiek napisze pierwszą linijkę.
Na godziny robi się raport, który ma jedno pytanie, jedno źródło i gotową definicję. Odbiorca wie, co chce zobaczyć, ktoś w firmie potrafi rozstrzygnąć wątpliwość w pół godziny, format jest plikiem, a częstotliwość nie przekracza raz na dobę. Wtedy praca to napisanie zapytania, obudowanie go widokiem, ustawienie harmonogramu i dodanie stopki z datą. To zamyka się w krótkim, przewidywalnym zleceniu.
Osobnego projektu wymaga sytuacja, w której dane leżą w kilku systemach, definicje są sporne, odbiorcy są zewnętrzni albo każdy ma widzieć wyłącznie swój wycinek. Wtedy prawdziwa praca nie polega na pisaniu SQL-a, lecz na zbudowaniu miejsca, z którego wszystkie raporty czytają: jednej bazy raportowej, jednego słownika definicji i jednego zestawu uprawnień. Bez tego każdy kolejny raport zaczyna się od nowa i sprzeczności rosną wykładniczo.
Kilka sygnałów rozstrzyga sprawę szybciej niż długa analiza. Zdanie „potrzebujemy tego dla naszych klientów” oznacza, że budujesz produkt, a nie raport, bo dochodzą uprawnienia, wygląd i odpowiedzialność za treść. Zdanie „ktoś codziennie klika eksport i skleja w Excelu” oznacza, że kupujesz automat i zwrot policzysz w godzinach pracy ludzi. Zdanie „mamy to w trzech systemach i nigdy się nie zgadza” oznacza, że najpierw potrzebujesz wspólnego miejsca na dane, a dopiero potem raportu.
Jest też sytuacja odwrotna, w której najuczciwiej powiedzieć, że projekt nie jest potrzebny. Gdy pytanie jest jedno, pada raz na kwartał, a odpowiedź ma dwie liczby, automatyzacja kosztuje więcej, niż oszczędza. Wtedy lepszym rozwiązaniem jest zapisane zapytanie i krótka instrukcja niż harmonogram, który przez trzy miesiące nie robi nic, a po trzech miesiącach przestaje działać, bo zmienił się schemat i nikt tego nie zauważył.
Co przygotować, zanim zamówisz raport
Sześć rzeczy, które skracają rozmowę o połowę i zdejmują z wyceny największą część niepewności.
- Pytanie w jednym zdaniuNapisz, na co raport ma odpowiadać, bez spójnika „oraz”. Jeśli nie mieści się w jednym zdaniu, to są dwa raporty i warto je rozdzielić od razu.
- Ręcznie policzona odpowiedź za jeden okresJedna liczba za jeden miesiąc, policzona tak, jak robisz to dziś. To jedyny sposób, żeby sprawdzić, czy automat liczy to samo, co człowiek, zanim raport pójdzie do obiegu.
- Dostęp do repliki albo kopii, nie do produkcjiJeśli nie ma repliki, ustalcie zawczasu, czy powstanie, czy raport ma liczyć się na nocnym zrzucie. Ta decyzja zmienia wszystko, co dzieje się dalej.
- Lista odbiorców i formatKto dostaje, o której godzinie, czym to otworzy i co zrobi z liczbą w następnym kroku. Arkusz, PDF i link to trzy różne zakresy prac.
- Osoba rozstrzygająca definicjeJedno nazwisko, nie dział. Ta osoba decyduje, czy zwroty odejmujemy w miesiącu zamówienia, czy w miesiącu zwrotu.
- Adres na powiadomienia o awariiSkrzynka, którą ktoś naprawdę czyta. Raport, który przestał przychodzić, zauważa się zwykle dopiero wtedy, gdy jest potrzebny, a to zawsze najgorszy moment.
Pytania i odpowiedzi
Czy raport można liczyć prosto z bazy produkcyjnej?
Można, ale tylko dla lekkich zapytań, z limitem czasu wykonania i poza godzinami szczytu. Ciężki raport konkuruje z aplikacją o te same zasoby i potrafi wydłużyć czas odpowiedzi sklepu albo systemu sprzedaży. W PostgreSQL ustaw dla roli raportowej statement_timeout, bo domyślna wartość zero oznacza brak jakiegokolwiek limitu; dokumentacja odradza przy tym ustawianie tego parametru globalnie w postgresql.conf, bo dotknąłby wszystkich sesji. Bezpieczniejszy wzorzec to replika tylko do odczytu albo nocna kopia.
Widok czy widok materializowany?
Widok nie przechowuje danych: zapytanie uruchamia się za każdym razem, gdy ktoś z widoku korzysta, więc widok porządkuje kod, ale niczego nie przyspiesza. Widok materializowany trzyma wynik i czyta się go szybciej, lecz nie odświeża się sam, a polecenie REFRESH MATERIALIZED VIEW zastępuje całą jego zawartość. Bez klauzuli CONCURRENTLY odświeżanie potrafi zablokować tych, którzy właśnie z widoku czytają, a sama klauzula CONCURRENTLY wymaga unikalnego indeksu zbudowanego z nazw kolumn i obejmującego wszystkie wiersze. Zaczynaj od widoku, przechodź na materializowany dopiero po zmierzeniu czasu zapytania.
Mamy Azure SQL Database. Gdzie jest SQL Server Agent?
Nie ma go tam i to regularnie zaskakuje po migracji. SQL Server Agent obsługuje SQL Server oraz Azure SQL Managed Instance, natomiast w Azure SQL Database jego rolę pełnią elastic jobs, które uruchamiają skrypty T-SQL cyklicznie na jednej lub wielu bazach, logują status i same ponawiają nieudane operacje. Zwróć uwagę na dwie rzeczy: wszystkie harmonogramy działają w czasie UTC, a historia wykonań jest automatycznie czyszczona po 45 dniach. Skrypty muszą być idempotentne, bo zadanie może zostać powtórzone po błędzie sieci.
Excel czy PDF?
Excel wtedy, gdy odbiorca będzie liczył dalej, a PDF wtedy, gdy dokument ma pozostać niezmienny, bo idzie do archiwum, do banku albo pod podpis. Jeśli raport ma po prostu przychodzić o umówionej porze, po stronie SQL Server zrobi to subskrypcja w Reporting Services, która dostarcza raport we wskazanym formacie na udział plikowy Windows, pocztą albo do biblioteki SharePoint; do wyboru są między innymi CSV, PDF, Excel i Word. Pamiętaj tylko, że raport musi używać zapisanych poświadczeń, a subskrypcje nie są dostępne w każdej edycji SQL Server.
Dlaczego dwa działy mają różne liczby dla tego samego pytania?
Prawie zawsze dlatego, że liczą różne rzeczy, a nie dlatego, że któraś strona się myli. Sprzedaż liczona datą zamówienia i datą faktury to dwie różne liczby, tak samo jak sprzedaż ze zwrotami odjętymi w miesiącu zamówienia i w miesiącu zwrotu. Rozwiązuje się to raz: definicja zapisana zdaniem po polsku, lista wykluczeń, jedna osoba rozstrzygająca i dokładnie jedna implementacja w bazie albo w modelu danych, z której czytają wszystkie raporty.
Jak często raport może się odświeżać w Power BI?
Modele na współdzielonej pojemności mają limit ośmiu zaplanowanych odświeżeń dziennie, a pula zeruje się codziennie o 00:01 czasu lokalnego wybranego w ustawieniach modelu. Na pojemności Premium, pojemności użytkownika PPU albo Fabric zaplanujesz do 48 odświeżeń dziennie. Jeśli potrzebujesz danych świeższych, niż pozwala harmonogram, zamiast walczyć z limitem odświeżeń rozważ połączenie na żywo do źródła albo osobny panel czytający wprost z repliki; stan na 21 września 2026 r.
Źródła
Liczby i terminy w tym przewodniku sprawdziłem w oficjalnych źródłach. Ceny i przepisy się zmieniają, więc przy decyzji warto zajrzeć do nich ponownie.
- PostgreSQL: CREATE VIEW · sprawdzono 2026-09-21
- PostgreSQL: widoki materializowane · sprawdzono 2026-09-21
- PostgreSQL: REFRESH MATERIALIZED VIEW · sprawdzono 2026-09-21
- PostgreSQL: CREATE PROCEDURE · sprawdzono 2026-09-21
- PostgreSQL: Hot Standby · sprawdzono 2026-09-21
- PostgreSQL: parametry sesji klienta (statement_timeout) · sprawdzono 2026-09-21
- PostgreSQL: pg_dump · sprawdzono 2026-09-21
- PostgreSQL: role predefiniowane (pg_read_all_data) · sprawdzono 2026-09-21
- PostgreSQL: zabezpieczenia na poziomie wiersza · sprawdzono 2026-09-21
- pg_cron: harmonogram zadań w PostgreSQL · sprawdzono 2026-09-21
- Microsoft Learn: SQL Server Agent · sprawdzono 2026-09-21
- Microsoft Learn: elastic jobs w Azure SQL Database · sprawdzono 2026-09-21
- Microsoft Learn: widoki indeksowane w SQL Server · sprawdzono 2026-09-21
- Microsoft Learn: read scale-out w Azure SQL · sprawdzono 2026-09-21
- Microsoft Learn: role na poziomie bazy danych · sprawdzono 2026-09-21
- Microsoft Learn: subskrypcje i dostarczanie w Reporting Services · sprawdzono 2026-09-21
- Microsoft Learn: odświeżanie danych w Power BI · sprawdzono 2026-09-21
Masz pytanie do swojego projektu?
Opisz, co chcesz osiągnąć. Odpowiem konkretnie, także wtedy, gdy najlepszą odpowiedzią jest „nie rób tego”.
Jonasz Jankowski · Bezpośrednia współpraca · Mikołów (Śląsk), zdalnie w całej Polsce