Database
 sql >> Baza danych >  >> RDS >> Database

3 najważniejsze wskazówki, które musisz znać, aby szybciej pisać widoki SQL

Przyjaciel czy wróg? Widoki SQL Server były przedmiotem gorących debat, kiedy pierwszy rok korzystałem z SQL Server. Powiedzieli, że jest źle, ponieważ jest powolny. Ale co powiesz na dzisiaj?

Czy jesteś na tej samej łodzi co ja wiele lat temu? Następnie dołącz do mnie w tej podróży, aby odkryć prawdziwą ofertę widoków SQL, abyś mógł napisać je najszybciej, jak to możliwe.

Widoki SQL to wirtualne tabele. Rekordy w widoku są wynikiem zapytania w nim zawartego. Za każdym razem, gdy aktualizowane są tabele bazowe używane w widoku, aktualizowany jest również widok. W niektórych przypadkach można również INSERT, UPDATE i DELETE w widoku jako tabelę. Chociaż sam tego nie próbowałem.

Podobnie jak w przypadku tabeli, możesz TWORZYĆ, ZMIENIAĆ lub UPUŚĆ widok. Możesz nawet utworzyć indeks, z pewnymi ograniczeniami.

Zauważ, że w przykładowych kodach użyłem SQL Server 2019.

1. Poznaj właściwe i niewłaściwe użycie widoków SQL

Najpierw podstawy.

Do czego służą widoki SQL?

To jest ważne. Jeśli używasz go jako młotka do śrubokręta, zapomnij o szybszych widokach SQL. Najpierw przypomnijmy sobie właściwe użycie:

  • Aby skoncentrować się, uprościć i dostosować sposób postrzegania bazy danych przez każdego użytkownika.
  • Aby umożliwić użytkownikom dostęp do jedynych informacji, które muszą widzieć ze względów bezpieczeństwa.
  • Aby zapewnić zgodność wsteczną ze starą tabelą lub starym schematem, aby nie zakłócać zależnych aplikacji. Jest to tymczasowe, dopóki wszystkie potrzebne zmiany nie zostaną zakończone.
  • Do partycjonowania danych pochodzących z różnych serwerów. Dlatego wyglądają tak, jakby były jedną tabelą z jednego serwera lub instancji.

Jak NIE używać widoków SQL Server?

  • Ponownie użyj widoku w innym widoku, który zostanie ponownie wykorzystany w jeszcze innym widoku. Krótko mówiąc, głęboko zagnieżdżone poglądy. Ponowne użycie kodu ma w tym przypadku kilka wad.
  • Oszczędzaj na naciśnięciach klawiszy. Odnosi się do pierwszego, który zmniejsza nacisk palca i wydaje się przyspieszać kodowanie.

Niewłaściwe użycie widoków, jeśli jest dozwolone, przesłoni prawdziwy powód, dla którego tworzysz widoki. Jak zobaczysz później, rzeczywiste korzyści przeważają nad postrzeganymi korzyściami wynikającymi z niewłaściwego użytkowania.

Przykład

Przyjrzyjmy się przykładowi firmy Microsoft. Pracownik widok z AdventureWorks . Oto kod:

-- Employee names and basic contact information
CREATE VIEW [HumanResources].[vEmployee] 
AS 
SELECT 
    e.[BusinessEntityID]
    ,p.[Title]
    ,p.[FirstName]
    ,p.[MiddleName]
    ,p.[LastName]
    ,p.[Suffix]
    ,e.[JobTitle]  
    ,pp.[PhoneNumber]
    ,pnt.[Name] AS [PhoneNumberType]
    ,ea.[EmailAddress]
    ,p.[EmailPromotion]
    ,a.[AddressLine1]
    ,a.[AddressLine2]
    ,a.[City]
    ,sp.[Name] AS [StateProvinceName] 
    ,a.[PostalCode]
    ,cr.[Name] AS [CountryRegionName] 
    ,p.[AdditionalContactInfo]
FROM [HumanResources].[Employee] e
    INNER JOIN [Person].[Person] p
 ON p.[BusinessEntityID] = e.[BusinessEntityID]
    INNER JOIN [Person].[BusinessEntityAddress] bea 
        ON bea.[BusinessEntityID] = e.[BusinessEntityID] 
    INNER JOIN [Person].[Address] a 
        ON a.[AddressID] = bea.[AddressID]
    INNER JOIN [Person].[StateProvince] sp 
        ON sp.[StateProvinceID] = a.[StateProvinceID]
    INNER JOIN [Person].[CountryRegion] cr 
        ON cr.[CountryRegionCode] = sp.[CountryRegionCode]
    LEFT OUTER JOIN [Person].[PersonPhone] pp
        ON pp.BusinessEntityID = p.[BusinessEntityID]
    LEFT OUTER JOIN [Person].[PhoneNumberType] pnt
        ON pp.[PhoneNumberTypeID] = pnt.[PhoneNumberTypeID]
    LEFT OUTER JOIN [Person].[EmailAddress] ea
        ON p.[BusinessEntityID] = ea.[BusinessEntityID];
GO

Celem tego widoku jest skupienie się na podstawowych informacjach o pracownikach. W razie potrzeby personel działu kadr może wyświetlić go na stronie internetowej. Czy został ponownie wykorzystany w innych widokach?

Spróbuj tego:

  1. W SQL Server Management Studio , poszukaj AdventureWorks baza danych.
  2. Rozwiń folder Widoki i poszukaj [HumanResources].[vEmployee].
  3. Kliknij go prawym przyciskiem myszy i wybierz Wyświetl zależności .

Jeśli widzisz inny widok w zależności od tego widoku, który następnie zależy od innego widoku, Microsoft dał nam zły przykład. Ale wtedy nie ma innych zależności widoku.

Przejdźmy do następnego.

2. Obal mit o widokach SQL

Gdy SQL Server przetwarza SELECT z widoku , ocenia kod w widoku ZANIM zajmie się klauzulą ​​WHERE lub dowolnym złączeniem w zapytaniu zewnętrznym. Po dołączeniu większej liczby tabel będzie to wolniejsze w porównaniu z SELECT z tabel podstawowych z takimi samymi wynikami.

Przynajmniej tak mi powiedziano, kiedy zacząłem używać SQL. Niezależnie od tego, czy to mit, czy nie, jest tylko jeden sposób, aby się dowiedzieć. Przejdźmy do praktycznego przykładu.

Jak działają widoki SQL

Microsoft nie zostawił nas w ciemności, aby debatować bez końca. Mamy narzędzia do sprawdzania, jak działają zapytania, takie jak STATISTICS IO i Rzeczywisty plan wykonania . Użyjemy ich we wszystkich naszych przykładach. Zróbmy pierwszy.

USE AdventureWorks
GO

SELECT * FROM HumanResources.vEmployee e
WHERE e.BusinessEntityID = 105

Aby zobaczyć, co się dzieje, gdy SQL Server przetwarza widok, przyjrzyjmy się rzeczywistemu planowi wykonania na rysunku 1. Porównujemy to z kodem CREATE VIEW dla vEmployee w poprzedniej sekcji.

Jak widać, pierwsze węzły przetwarzane przez SQL Server to te, które używają INNER JOIN. Następnie przystępuje do przetwarzania LEWYCH ZŁĄCZEŃ ZEWNĘTRZNYCH.

Ponieważ nie widzimy nigdzie węzła filtra dla klauzuli WHERE, musi on znajdować się w jednym z tych węzłów. Jeśli sprawdzisz właściwości wszystkich węzłów, zobaczysz przetworzoną klauzulę WHERE w tabeli Employee. Umieściłem go w ramce na rysunku 1. Aby udowodnić, że tam jest, zobacz rysunek 2 dla właściwości tego węzła:

Analiza

Więc miał instrukcję SELECT w vEmployee widok został oceniony lub przetworzony PRZED klauzulą ​​GDZIE została zastosowana? Z Planu Wykonawczego wynika, że ​​tak się nie stało. Jeśli tak, powinno pojawić się najbliżej węzła SELECT.

To, co mi powiedziano, było mitem. Unikałem czegoś dobrego z powodu niezrozumienia prawidłowego użycia widoków SQL.

Teraz, gdy wiemy, jak SQL Server przetwarza SELECT z widoku , pozostaje pytanie:czy to wolniej niż nieużywanie widoku?

SELECT FROM Widok a SELECT FROM Tabele podstawowe – która będzie działać szybciej?

Najpierw musimy wyodrębnić instrukcję SELECT z vEmployee wyświetlić i uzyskać ten sam wynik, jaki uzyskaliśmy podczas korzystania z widoku. Poniższy kod pokazuje tę samą klauzulę WHERE:

USE AdventureWorks
GO

-- SELECT FROM a view
SELECT * FROM HumanResources.vEmployee e
WHERE e.BusinessEntityID = 105

-- SELECT FROM Base Tables
SELECT 
    e.[BusinessEntityID]
    ,p.[Title]
    ,p.[FirstName]
    ,p.[MiddleName]
    ,p.[LastName]
    ,p.[Suffix]
    ,e.[JobTitle]  
    ,pp.[PhoneNumber]
    ,pnt.[Name] AS [PhoneNumberType]
    ,ea.[EmailAddress]
    ,p.[EmailPromotion]
    ,a.[AddressLine1]
    ,a.[AddressLine2]
    ,a.[City]
    ,sp.[Name] AS [StateProvinceName] 
    ,a.[PostalCode]
    ,cr.[Name] AS [CountryRegionName] 
    ,p.[AdditionalContactInfo]
FROM [HumanResources].[Employee] e
    INNER JOIN [Person].[Person] p
	ON p.[BusinessEntityID] = e.[BusinessEntityID]
    INNER JOIN [Person].[BusinessEntityAddress] bea 
        ON bea.[BusinessEntityID] = e.[BusinessEntityID] 
    INNER JOIN [Person].[Address] a 
        ON a.[AddressID] = bea.[AddressID]
    INNER JOIN [Person].[StateProvince] sp 
        ON sp.[StateProvinceID] = a.[StateProvinceID]
    INNER JOIN [Person].[CountryRegion] cr 
        ON cr.[CountryRegionCode] = sp.[CountryRegionCode]
    LEFT OUTER JOIN [Person].[PersonPhone] pp
        ON pp.BusinessEntityID = p.[BusinessEntityID]
    LEFT OUTER JOIN [Person].[PhoneNumberType] pnt
        ON pp.[PhoneNumberTypeID] = pnt.[PhoneNumberTypeID]
    LEFT OUTER JOIN [Person].[EmailAddress] ea
        ON p.[BusinessEntityID] = ea.[BusinessEntityID]
WHERE e.BusinessEntityID = 105

Następnie sprawdzamy zamówienie reklamowe STATISTICS i wykonujemy Porównaj plan pokazowy . Ile zasobów będzie potrzebować zapytanie z widoku w porównaniu z zapytaniem z tabel podstawowych? Zobacz rysunek 3.

W tym przypadku wykonywanie zapytań z widoku lub tabel podstawowych będzie zużywać te same odczyty logiczne. Oba używały stron 19 * 8 KB. Na tej podstawie decyduje o tym, kto jest szybszy. Innymi słowy, użycie widoku nie zaszkodzi wydajności. Porównajmy rzeczywisty plan wykonania obu przy użyciu Porównaj plan pokazu :

Czy widzisz zacienioną część diagramu? Co powiesz na QueryPlanHash obu? Ponieważ oba zapytania mają równe QueryPlanHash i te same operacje, tabele widoku lub bazy będą przetwarzane tak samo przez SQL Server .

Te same odczyty logiczne i ten sam plan próbki mówią nam, że oba będą działać tak samo. W związku z tym posiadanie wysokich odczytów logicznych spowoduje spowolnienie działania zapytania, niezależnie od tego, czy używasz widoków, czy nie. Znajomość tego faktu pomoże Ci rozwiązać problem i przyspieszyć wyświetlanie.

Niestety są złe wieści.

Łączenie widoków SQL z tabelami

To, co widziałeś wcześniej, to SELECT z widoku bez złączeń. Co jednak, jeśli dołączysz do tabeli do widoku?

Przyjrzyjmy się kolejnemu przykładowi. Tym razem używamy vSalesPerson zobacz w AdventureWorks – lista sprzedawców z danymi kontaktowymi i limitem sprzedaży. Ponownie porównujemy instrukcję do SELECT z tabel podstawowych:

-- get the total sales orders for each salesperson
-- using the view joined with SalesOrderHeader
SELECT 
 sp.FirstName
,sp.MiddleName
,sp.LastName
,SUM(soh.TotalDue) AS TotalSalesOrders
FROM Sales.vSalesPerson sp
INNER JOIN Sales.SalesOrderHeader soh ON sp.BusinessEntityID = soh.SalesPersonID
GROUP BY sp.LastName, sp.MiddleName, sp.FirstName

-- using base tables
SELECT
 p.FirstName
,p.MiddleName
,p.LastName
,SUM(soh.TotalDue) AS TotalSalesOrders
FROM sales.SalesPerson sp
INNER JOIN Person.Person p ON sp.BusinessEntityID = P.BusinessEntityID
INNER JOIN Sales.SalesOrderHeader soh ON sp.BusinessEntityID = soh.SalesPersonID
GROUP BY p.LastName, p.MiddleName, p.FirstName 

Jeśli uważasz, że będzie tak samo, sprawdź IO STATYSTYKI:

Zaskoczony? Dołączanie do vSalesPerson widok z SalesOrderHeader tabela wymaga ogromnych zasobów (28 240 x 8 KB) w porównaniu do zwykłego korzystania z tabel podstawowych (774 x 8 KB). Zauważ również, że zawierał niektóre tabele, których nie potrzebowaliśmy (tabele w czerwonych polach). Nie mówiąc już o wyższych odczytach logicznych w SalesOrderHeader podczas korzystania z widoku.

Ale to nie koniec.

Rzeczywisty plan wykonania ujawnia więcej

Zwróć uwagę na rzeczywisty plan wykonania zapytania do tabel bazowych:

Ilustracja wydaje się przedstawiać całkiem normalny plan wykonania. Ale spójrz na ten z widokiem:

Plan wykonania na rysunku 7 pokrywa się z IO STATYSTYKI na rysunku 5. Z widoku widać tabele, których nie potrzebujemy. Istnieje również Wyszukiwanie klucza węzeł z szacunkową wartością wiersza, która jest o ponad tysiąc rekordów odbiegająca od rzeczywistych wierszy. Na koniec pojawia się również ostrzeżenie w węźle SELECT. Co to może być?

Co to jest nadmierny grant ostrzeżenie w węźle SELECT?

Nadmierne przyznanie ma miejsce, gdy maksymalna używana pamięć jest zbyt mała w porównaniu z przyznaną pamięcią. W tym przypadku przyznano 1024 KB, ale użyto tylko 16 KB.

Przyznanie pamięci to szacowana ilość pamięci w KB wymagana do uruchomienia planu.

Mogą to być błędne dane szacunkowe w Wyszukiwaniu kluczy węzeł i/lub włączenie tabel, których nie potrzebowaliśmy w planie, który to spowodował. Ponadto zbyt duża ilość przyznanej pamięci może powodować blokowanie. Pozostałe 1008 KB mogło być przydatne do innych operacji.

W końcu coś poszło nie tak po połączeniu widoku z tabelą. Nie musimy radzić sobie z tymi problemami, jeśli wykonujemy zapytania z tabel podstawowych.

Na wynos

To było długie wyjaśnienie. Wiemy jednak, że widoki nie są oceniane ani przetwarzane PRZED oceną klauzuli WHERE lub sprzężeń w zewnętrznym zapytaniu. Udowodniliśmy również, że oba będą działać tak samo.

Z drugiej strony zdarza się, że łączymy widok z tabelą. Wykorzystuje sprzężenia tabel, których nie potrzebujemy z widoku. Są dla nas niewidoczne, chyba że sprawdzimy IO STATYSTYKI i Rzeczywisty Plan Wykonawczy. To wszystko może pogorszyć wydajność, a problemy mogą pojawić się znikąd.

Dlatego:

  • Powinniśmy wiedzieć, jak zapytania, w tym widoki, działają od wewnątrz.
  • STATYSTYKI IO i rzeczywiste plany wykonania pokażą, jak będą działać zapytania i widoki.
  • Nie możemy po prostu dołączyć widoku do tabeli i beztrosko go ponownie wykorzystać. Zawsze sprawdzaj STATISTICS IO i rzeczywiste plany wykonania! Zamiast ponownie używać widoków i zagnieżdżać je w celu „ulepszenia” wydajności kodowania, używam IntelliSense i narzędzia do uzupełniania kodu, takiego jak SQL Complete.

Możemy wtedy być pewni, że nie napiszemy widoków, które będą miały poprawne wyniki, ale będą działały jak ślimak.

3. Wypróbuj widoki indeksowane

Zindeksowane widoki są tym, co sugeruje nazwa. Może zwiększyć wydajność instrukcji SELECT. Ale podobnie jak indeksy tabel, może mieć wpływ na wydajność, jeśli tabele podstawowe są duże i stale aktualizowane.

Aby zobaczyć, jak zindeksowane widoki mogą poprawić wydajność zapytań, przyjrzyjmy się vStateProvinceCountryRegion zobacz w AdventureWorks . Widok jest indeksowany na StateProvinceID i KrajRegionCode . Jest to zgrupowany, unikalny indeks.

Porównajmy IO STATYSTYKI widoku bez indeksu i posiadającego indeks. Dzięki temu dowiadujemy się, ile stron 8KB odczyta nasz SQL Server:

Rysunek pokazuje, że posiadanie indeksu w vStateProvinceCountryRegion widok zmniejsza odczyty logiczne o połowę. Jest to 50% poprawa w porównaniu z brakiem indeksu.

Dobrze to słyszeć.

Mimo to nie dodawaj niedbale indeksów do swoich widoków. Oprócz długiej listy ścisłych reguł, aby mieć jeden unikalny, klastrowy indeks, może to obniżyć wydajność, podobnie jak beztroskie dodawanie indeksów do tabel. Sprawdź również we STATISTICS IO, czy po dodaniu indeksu nastąpił spadek odczytów logicznych.

Na wynos

Jak widzieliśmy w naszym przykładzie, widoki indeksowane mogą poprawić wydajność widoków SQL.

WSKAZÓWKA BONUSOWA

Tak jak każde inne zapytanie, widoki SQL będą działać szybko, jeśli:

  • Statystyki są aktualizowane
  • Dodaje się brakujące indeksy
  • Indeksy są defragmentowane
  • Indeksy użyły właściwego FILLFACTORa

Wniosek

Czy widoki SQL są dobre czy złe?

Widoki SQL są dobre, jeśli napiszemy je poprawnie i sprawdzimy, jak będą przetwarzane. Mamy narzędzia takie jak STATISTICS IO i Actual Execution Plan – skorzystaj z nich! Zindeksowane widoki mogą również poprawić wydajność.

Polub ten post? Podziel się miłością na swojej ulubionej platformie mediów społecznościowych.


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Projektowanie bazy danych dla systemu rekrutacyjnego

  2. Sterownik HubSpot ODBC

  3. Automatyczne zarządzanie indeksami w bazie danych Azure SQL

  4. Minimalizowanie wpływu poszerzenia kolumny TOŻSAMOŚĆ – część 4

  5. Praca z danymi ODBC w DbVisualizer