Wyjaśnienie widoków SQL: Tworzenie, używanie i unikanie pułapek wraz z przykładami
Widok to zapisane zapytanie, którego możesz używać jak tabeli. Dowiedz się, jak go utworzyć, dlaczego widoki zapewniają spójność raportów, co robią, a czego nie wpływają na wydajność, a także pułapek, które je łamią.
- widok to nazwane, przechowywane zapytanie, z którego możesz wybierać jak z tabeli.
- Widok normalny nie przechowuje żadnych danych, więc zawsze pokazuje aktualne wyniki.
- Widoki upraszczają złożone zapytania, zapewniają spójność logiki biznesowej i mogą ograniczać dostęp do kolumn.
- Same w sobie nie przyspieszają zapytania, chociaż widoki zmaterializowane mogą to zrobić.
To samo dwudziestoliniowe zapytanie dotyczące raportu zostało skopiowane do pięciu pulpitów nawigacyjnych, a każda kopia uległa pewnemu przesunięciu. Jeden liczy anulowane zamówienia, a drugi nie. Widoki SQL rozwiązują ten problem, jednorazowo definiując tę logikę w bazie danych pod jasną nazwą.
Każdy poniższy przykład uruchomiliśmy w SQLite 3.50 i pokazane wyniki pochodzą z tego uruchomienia. Widoki to standardowy język SQL, ale szczegóły, takie jak aktualizacja poprzez widok, widoki zmaterializowane i obsługa zależności różnią się w zależności od bazy danych i na to zwracamy uwagę.
Co to jest widok?
Widok to SELECT instrukcja zapisana w bazie danych pod nazwą. Kiedy wysyłasz zapytanie do widoku, baza danych uruchamia zapisane zapytanie. Działa jak tabela do odczytu, ale normalny widok nie przechowuje własnej kopii danych.
Pomyśl o filtrze zapisanym w arkuszu kalkulacyjnym. Filtr nie jest drugą kopią arkusza. Jest to sposób patrzenia na te same dane, który zawsze odzwierciedla najnowsze wartości.
Przykładowe tabele
CREATE TABLE customers (
id INT PRIMARY KEY, name TEXT, city TEXT, email TEXT, credit_limit INT
);
CREATE TABLE orders (
id INT PRIMARY KEY, customer_id INT, total INT, status TEXT
);
INSERT INTO customers VALUES
(1,'Asha','Pune','asha@example.com',50000),
(2,'Ben','Delhi','ben@example.com',20000),
(3,'Chitra','Pune','chitra@example.com',80000);
INSERT INTO orders VALUES
(101,1,1200,'paid'), (102,1,800,'paid'),
(103,2,300,'pending'), (104,3,2500,'paid');
Utwórz widok
Ten widok podsumowuje zamówienia każdego klienta. Ukrywa łączenie, grupowanie i wyrażenie CASE za jedną prostą nazwą:
CREATE VIEW customer_sales AS
SELECT c.id, c.name, c.city,
COUNT(o.id) AS orders,
COALESCE(SUM(CASE WHEN o.status = 'paid' THEN o.total END), 0) AS paid_total
FROM customers c
LEFT JOIN orders o ON o.customer_id = c.id
GROUP BY c.id, c.name, c.city;
Teraz każdy może z niego korzystać, nie wiedząc, jak to działa:
SELECT * FROM customer_sales ORDER BY paid_total DESC;
-- 3 | Chitra | Pune | 1 | 2500
-- 1 | Asha | Pune | 2 | 2000
-- 2 | Ben | Delhi | 1 | 0
SELECT name, paid_total FROM customer_sales WHERE city = 'Pune';
-- Asha | 2000
-- Chitra | 2500
Ben pojawia się z zerem, ponieważ w widoku używane są LEFT JOIN i COALESCE. Takie decyzje, podejmowane raz w widoku, zapewniają spójność raportów. Aby odświeżyć wiedzę na temat obsługi wartości NULL, zobacz Wartości SQL NULL.
Wyświetlenia są zawsze aktualne
Ponieważ widok normalny uruchamia zapytanie za każdym razem, nowe dane pojawiają się natychmiast. Dodaliśmy płatne zamówienie dla Bena i ponownie zapytaliśmy o widok:
INSERT INTO orders VALUES (105, 2, 900, 'paid');
SELECT name, paid_total FROM customer_sales WHERE name = 'Ben';
-- Ben | 900
Nie było etapu odświeżania ani kopiowania, które umożliwiałyby synchronizację. Jest to kluczowa różnica w stosunku do zapisywania wyników zapytania w osobnej tabeli.
Ukrywanie kolumn
Widoki są często używane do udostępniania tylko tych kolumn, których potrzebuje dana osoba lub aplikacja. Tutaj pominięto adresy e-mail i limity kredytowe:
CREATE VIEW public_customers AS
SELECT id, name, city FROM customers;
-- columns: id, name, city
W bazach danych z uprawnieniami, takich jak PostgreSQL, SQL Server i MySQL, użytkownikowi raportującemu można przyznać dostęp do widoku, ale nie do tabeli źródłowej. SQLite nie ma kont użytkowników, więc mogliśmy pokazać tylko samo ograniczenie kolumny. Traktuj widok jako jedną warstwę ochrony. Wrażliwe dane nadal wymagają odpowiedniej kontroli dostępu, a niektóre bazy danych oferują zabezpieczenia na poziomie wierszy w celu filtrowania wierszy według użytkownika.
Wydajność: widoki nie zwiększają prędkości
Powszechnym mitem jest twierdzenie, że widoki przyspieszają wykonywanie zapytań. Kiedy wykonujesz zapytanie, widok normalny jest zastępowany jego definicją, więc baza danych działa tak samo, jakbyś sam napisał pełne zapytanie. Nasz plan wykonania pokazał, że w ramach zapytania uruchamiane jest łączenie i grupowanie widoku:
EXPLAIN QUERY PLAN SELECT * FROM customer_sales WHERE city = 'Pune';
-- CO-ROUTINE customer_sales
-- SCAN c ...
-- SEARCH o USING AUTOMATIC COVERING INDEX (customer_id=?) LEFT-JOIN
-- USE TEMP B-TREE FOR GROUP BY
-- SCAN customer_sales
Zatem widok wolnego zapytania jest nadal wolnym zapytaniem. Szybkość wynika z indeksów i dobrego projektu zapytań, jak opisano w Optymalizacja zapytań SQL i Wyjaśnienie indeksów SQL. Uważaj także na widoki zbudowane na innych widokach. Warstwy zagnieżdżeń ułatwiają wielokrotne łączenie tego samego dużego stołu bez zauważania.
Zmaterializowane poglądy
Zmaterializowany widok zapisuje swoje wyniki, podobnie jak tabela w pamięci podręcznej. Odczyty są szybkie, ale dane są tak świeże, jak ostatnie odświeżenie.
-- PostgreSQL
CREATE MATERIALIZED VIEW daily_sales AS
SELECT order_date, SUM(total) AS revenue FROM orders GROUP BY order_date;
REFRESH MATERIALIZED VIEW daily_sales;
| Funkcja | Normalny widok | Zmaterializowany pogląd |
|---|---|---|
| Przechowuje dane | Nie | Tak |
| Świeżość | Zawsze aktualne | Od ostatniego odświeżenia |
| Czytaj prędkość | To samo co zapytanie | Szybko |
| Koszt przechowywania | Żadne | Tak |
| Dobre dla | Uproszczenie, spójność | Ciężkie raporty i dashboardy |
Wsparcie jest zróżnicowane. PostgreSQL i Oracle mają widoki zmaterializowane, a SQL Server oferuje widoki indeksowane z własnymi regułami. Brakuje ich w SQLite i MySQL, dlatego ludzie korzystają z regularnej tabeli podsumowań odświeżanej zgodnie z harmonogramem. W tym artykule nie uruchomiliśmy przykładu PostgreSQL.
Wskazówka: przed utworzeniem widoku zmaterializowanego zdecyduj, jak bardzo nieaktualne mogą być dane. „Odświeżanie co godzinę” musi być akceptowalne dla osób czytających raport, więc powiedz im.
Czy możesz zaktualizować widok?
To zależy od bazy danych i widoku. Prosty widok pojedynczej tabeli, bez grupowania lub DISTINCT, często można zaktualizować w PostgreSQL, MySQL i SQL Server, a zmiana zostaje przeniesiona na tabelę. Widok ze złączeniami lub agregacjami zazwyczaj nie jest możliwy, ponieważ baza danych nie jest w stanie określić, który wiersz należy zmienić.
SQLite w ogóle nie pozwala na bezpośredni zapis do widoków. Nasza próba nie powiodła się:
INSERT INTO customer_sales (name) VALUES ('X');
-- cannot modify customer_sales because it is a view
Niektóre bazy danych obsługują INSTEAD OF wyzwalacze umożliwiające zapis widoku, a wiele oferuje WITH CHECK OPTION, które zatrzymują zapisy, które nie byłyby widoczne w widoku. W praktyce większość zespołów utrzymuje widoki tylko do odczytu i zapisuje je w tabelach.
Zależności i złamania
Widok zależy od tabel, z których czyta. Stworzyliśmy widok na stole, a następnie upuściliśmy tabelę:
CREATE TABLE ghost AS SELECT 1 AS x;
CREATE VIEW v_ghost AS SELECT x FROM ghost;
DROP TABLE ghost;
SELECT * FROM v_ghost;
-- no such table: main.ghost
SQLite pozwolił na upuszczenie i nie powiódł się dopiero później, gdy użyto widoku. Inne bazy danych, takie jak PostgreSQL, nie usuwają tabeli, od której zależy widok, chyba że dodasz CASCADE, co również usunie widok. Tak czy inaczej, zmiana nazwy lub usunięcie kolumny może spowodować uszkodzenie wyświetleń, więc sprawdź to w testach regresyjnych po zmianach schematu.
Istnieje również subtelna pułapka z SELECT * w widoku. Stworzyliśmy CREATE VIEW star AS SELECT * FROM customers, a następnie dodaliśmy kolumnę do tabeli. W SQLite widok pochwycił nową kolumnę. Inne bazy danych, w tym PostgreSQL, rozwijają listę kolumn podczas tworzenia widoku, więc nowe kolumny nie pojawiają się. Więc wymień kolumny jawnie. Dokumentuje widok i wszędzie zachowuje się tak samo.
Zarządzanie widokami
| Zadanie | Wspólna składnia |
|---|---|
| Utwórz | UTWÓRZ WIDOK nazwę JAKO WYBIERZ... |
| Wymień | CREATE OR REPLACE VIEW (PostgreSQL, MySQL, Oracle) |
| Zamień w SQL Server | UTWÓRZ LUB ZMIEŃ WIDOK |
| Usuń | Nazwa DROP VIEW |
| Usuń bezpiecznie | URUCHOM WIDOK JEŚLI ISTNIEJE nazwa |
Upuszczenie widoku powoduje usunięcie tylko zapisanego zapytania. W naszym teście tabela customers po upuszczeniu public_customers nadal zawierała wszystkie trzy wiersze. Zachowaj definicje widoków w kontroli wersji wraz z migracjami, aby zmiany były sprawdzane jak każdy inny kod.
Widok vs CTE vs tabela
| Opcja | Całe życie | Przechowuje dane | Najlepsze dla |
|---|---|---|---|
| Zobacz | Aż do upadku | Nie | Wspólna logika używana przez wiele zapytań |
| CTE | Jedno stwierdzenie | Nie | Organizowanie pojedynczego złożonego zapytania |
| Zmaterializowany pogląd | Aż do upadku | Tak | Szybki odczyt kosztownych wyników |
| Stół | Aż do upadku | Tak | Rzeczywiste dane |
Typowe błędy
- Oczekuję zwiększenia prędkości. Widok normalny uruchamia zapytanie za każdym razem.
- Używanie
SELECT *w widokach. Zachowanie różni się w przypadku różnych baz danych w przypadku zmiany tabel. - Głębokie zagnieżdżanie. Widoki zbudowane na widokach ukrywają kosztowne połączenia.
- Korzystanie z funkcji ORDER BY w widoku. Porządek nie jest gwarantowany, gdy wysyłasz zapytanie, więc sortuj w zapytaniu zewnętrznym.
- Niejasne nazwy. Pomocny jest przedrostek taki jak
v_lub wyraźny rzeczownik taki jakcustomer_sales. - Zapominanie widoków podczas migracji. Testuj je po każdej zmianie schematu.
Podsumowanie
Widoki to prosty sposób na umieszczenie ważnej logiki w bazie danych. Używaj ich, aby zachować spójność raportów i ukryć niepotrzebne kolumny, a nie jako trik zwiększający wydajność. Na początek znajdź zapytanie, które pojawia się w kilku miejscach Twojego kodu, zamień je w widok z wyraźnymi kolumnami i skieruj na nie każdego wywołującego.
Najczęstsze pytania
Co to jest widok w SQL?
Widok to zapisane zapytanie SELECT z nazwą. Wysyłasz zapytanie jak do tabeli, a baza danych za każdym razem uruchamia podstawowe zapytanie, więc wyniki są zawsze aktualne.
Czy widok SQL przechowuje dane?
Widok normalny nie przechowuje danych, tylko zapytanie. Zmaterializowany widok przechowuje wyniki i należy go odświeżać, aby być na bieżąco.
Czy widoki są szybsze niż tabele?
Nie. Widok normalny działa tak samo, jak zapytanie bazowe. Zmaterializowane widoki mogą przyspieszyć odczyt, kosztem przechowywania i świeżości.
Czy możesz wstawić do widoku?
Czasami. Proste widoki jednotabelowe można często aktualizować w PostgreSQL, MySQL i SQL Server. Widoki z połączeniami lub grupowaniem zwykle nie są takie, a SQLite na to nie pozwala.
Co stanie się z widokiem, jeśli tabela zostanie upuszczona?
To zależy od bazy danych. Niektórzy nie chcą porzucić tabeli, gdy widok od niej zależy, podczas gdy inni na to pozwalają, a zapytanie o widok kończy się niepowodzeniem.
Ucz się dalej
Potrzebujesz pomocy przy testowaniu, WordPressie lub SEO?
Pomagamy zespołom dostarczać lepsze oprogramowanie i rozwijać ich witryny. Powiedz nam, nad czym pracujesz, a my zaproponujemy jasny następny krok.
Więcej poradników na testowanie, sztuczna inteligencja i nowoczesny rozwój
Podobał Ci się ten artykuł? Wybierz temat i przejdź bezpośrednio do naszych najnowszych tutoriali.
Wyjaśnienie halucynacji AI: dlaczego modele językowe tworzą rzeczy i jak je zmniejszyć
Wyjaśniono halucynacje AI: czym są, dlaczego powstają w modelach językowych, typowe typy, jak je zredukować za pomocą uziemień i podpowiedzi oraz pr…
Przeczytaj artykuł →DevOpsWyjaśnienie zmiennych środowiskowych: pliki .env, sekrety i konfiguracja wykonana prawidłowo
Zmienne środowiskowe wyjaśnione na przykładach Pythona, które przeprowadziliśmy: ich odczytywanie i ustawianie, dlaczego każda wartość jest ciągiem …
Przeczytaj artykuł →Tworzenie oprogramowaniaWyjaśnienie ograniczenia szybkości interfejsu API: algorytmy, nagłówki i obsługa błędów 429
Ograniczanie szybkości API wyjaśnione za pomocą przeprowadzonej przez nas symulacji: zasobnik tokenów, stałe okno, przesuwane okno, 429 odpowiedzi, …
Przeczytaj artykuł →Automatyzacja testówWyśmiewanie w Pythonie: unittest.mock, patch i błędy, które sprawiają, że testy kłamią
Wyśmiewanie w Pythonie za pomocą unittest.mock, przetestowane: Mock i zwracana wartość, efekt uboczny, łatanie tam, gdzie używana jest nazwa, specyf…
Przeczytaj artykuł →Testowanie oprogramowaniaWyjaśnienie zasięgu kodu: pokrycie linii i oddziału oraz co naprawdę oznacza 100%
Wyjaśnienie pokrycia kodu za pomocą prawdziwego pliku cover.py: pokrycie linii, gałęzi i warunków, przeczytanie raportu, dlaczego 100% pokrycia może…
Przeczytaj artykuł →Bazy danych i SQLDELETE vs TRUNCATE vs DROP w SQL: różnice, wycofywanie i kiedy używać każdego z nich
DELETE vs TRUNCATE vs DROP wyjaśnione za pomocą przetestowanego SQL: co każdy usuwa, wycofywanie, wyzwalacze, resetowanie tożsamości, prędkość i czy…
Przeczytaj artykuł →Bazy danych i SQLWyjaśnienie widoków SQL: tworzenie, używanie i unikanie pułapek wraz z przykładami
Widoki SQL wyjaśnione za pomocą zapytań, które uruchomiliśmy: tworzenie widoku, wyniki na żywo, ukrywanie kolumn, wydajność, widoki z możliwością ak…
Przeczytaj artykuł →Tworzenie oprogramowaniaInterfejs TypeScript a typ: rzeczywiste różnice, testowane za pomocą kompilatora
Interfejs TypeScript a typ, sprawdzony z prawdziwym kompilatorem: co oba mogą zrobić, co tylko jeden, łączenie deklaracji, rozszerzenia a przecięcia…
Przeczytaj artykuł →Tworzenie oprogramowaniaPython *args i **kwargs wyjaśnione: elastyczne funkcje z przejrzystymi przykładami
Python *args i **kwargs wyjaśnione za pomocą uruchomionego przez nas kodu: pakowanie i rozpakowywanie, kolejność parametrów, argumenty zawierające t…
Przeczytaj artykuł →Tworzenie oprogramowaniaFunkcje Lambda w Pythonie: składnia, rzeczywiste zastosowania i kiedy ich nie używać
Funkcje lambda w Pythonie wyjaśnione za pomocą uruchomionego przez nas kodu: składnia, sortowanie za pomocą klucza, mapa i filtr, domknięcia, pułapk…
Przeczytaj artykuł →Sztuczna inteligencjaKim są agenci AI? Jak one działają, dzięki prostej pętli agenta, którą możesz uruchomić
Kim są agenci AI? Prosty przewodnik po pętli agenta, narzędziach, pamięci i poręczach, z małą pętlą w Pythonie, którą uruchomiliśmy, prawdziwymi zag…
Przeczytaj artykuł →DevOpsMonitorowanie a obserwowalność: prawdziwa różnica z logami, wskaźnikami i śladami
Wyjaśnienie monitorowania a obserwowalności: znane i nieznane awarie, dzienniki, metryki i ślady, opis incydentu przy kasie, złote sygnały, OpenTele…
Przeczytaj artykuł →DevOpsWoluminy platformy Docker a mocowania powiązań: utrwalanie danych kontenera we właściwy sposób
Wyjaśniono woluminy Dockera a montowanie powiązań: dlaczego dane kontenera znikają, nazwane woluminy, montowanie powiązań, tmpfs, przykłady tworzeni…
Przeczytaj artykuł →Automatyzacja testówTDD vs BDD: kluczowe różnice, jedna funkcja zbudowana w obie strony i kiedy używać każdej z nich
TDD vs BDD wyjaśnione za pomocą jednej funkcji rabatowej zbudowanej w obie strony: refaktoryzacja czerwono-zielona z uruchomionym przez nas kodem, s…
Przeczytaj artykuł →Tworzenie oprogramowaniaGit merge vs rebase: różnice, przykłady i kiedy czego używać
Git merge vs rebase wyjaśnione na prawdziwym wyniku logu, z tabelą porównawczą, złotą zasadą rebase i bezpiecznym procesem pracy zespołu.
Przeczytaj artykuł →Tworzenie oprogramowaniaPython list comprehension: składnia, przykłady i kiedy jej unikać
Python list comprehension wyjaśnione: składnia, filtrowanie, if-else, zagnieżdżone pętle, zmierzone czasy i sytuacje, w których zwykła pętla for jes…
Przeczytaj artykuł →Bazy danych i SQLSQL JOIN – wyjaśnienie z przykładami (Inner, Left, Right, Full)
Zrozum złączenia SQL krok po kroku na przykładowych tabelach i zapytaniach: INNER, LEFT, RIGHT, FULL, CROSS i SELF, plus typowe błędy i wskazówki wy…
Przeczytaj artykuł →