Korzystanie z widoków indeksowanych dla agregatów - zbyt piękne, aby mogło być prawdziwe?

28

Posiadamy hurtownię danych z dość dużą liczbą rekordów (10-20 milionów wierszy) i często uruchamiamy zapytania, które zliczają rekordy między określonymi datami lub liczą rekordy z określonymi flagami, np.

SELECT
    f.IsFoo,
    COUNT(*) AS WidgetCount
FROM Widgets AS w
JOIN Flags AS f
    ON f.FlagId = w.FlagId
WHERE w.Date >= @startDate
GROUP BY f.IsFoo

Wydajność nie jest okropna, ale może być stosunkowo powolna (może 10 sekund na zimnej pamięci podręcznej).

Ostatnio odkryłem, że mogę używać GROUP BYw widokach indeksowanych, więc wypróbowałem coś podobnego do następującego

CREATE VIEW TestView
WITH SCHEMABINDING
AS
    SELECT
        Date,
        FlagId,
        COUNT_BIG(*) AS WidgetCount
    FROM Widgets
    GROUP BY Date, FlagId;
GO

CREATE UNIQUE CLUSTERED INDEX PK_TestView ON TestView
(
    Date,
    FlagId
);

W rezultacie wydajność mojego pierwszego zapytania wynosi teraz <100ms, a wynikowy widok i indeks <100k (chociaż nasza liczba wierszy jest duża, zakres dat i identyfikatorów flag oznacza, że ​​ten widok zawiera tylko 1000-2000 wierszy).

Pomyślałem, że może to spowolni wydajność zapisu w tabeli widżetów, ale nie - wydajność wstawiania i aktualizacji w tej tabeli jest praktycznie niezmieniona, o ile mogłem powiedzieć (a ponadto, jako hurtownia danych, ta tabela jest rzadko aktualizowana tak czy inaczej)

Wydaje mi się to zbyt piękne, aby mogło być prawdziwe - prawda? Na co muszę uważać, korzystając z indeksowanych widoków w ten sposób?

Justin
źródło
2
Czy możesz przepisać swoje skrypty, aby faktycznie były poprawnymi kodami SQL? Twoje SELECTi CREATE VIEWskrypty są błędne, ponieważ uważam, że to twój CREATE INDEXskrypt.
Mark Sinkinson
2
@MarkSinkinson Apologies, okazuje się, że próba napisania poprawnego SQL dla wyimaginowanych tabel jest trudna
Justin
Część „zbyt piękna, aby mogła być prawdziwa” pojawiła się, gdy chciałem bardziej zaawansowanych widoków, takich jak MAX, sprzężenia zewnętrzne lub zewnętrzne lub indeksowanie widoku, który sam odwołuje się do innego widoku - z których wszystkie przynajmniej w SQL Server nie są dozwolone docs.microsoft.com/en-us/sql/relational-databases/views/… . Dlatego zawsze kończę na zbyt ambitnym, a potem narzucaniu skali. Ale w przypadku prostszych agregacji są one naprawdę świetne - nawet SUM jest obsługiwany.
Simon_Weaver,

Odpowiedzi:

29

Jak zauważyłeś, sam widok zmaterializuje tylko niewielką liczbę wierszy - więc nawet jeśli zaktualizujesz całą tabelę, dodatkowe operacje we / wy związane z aktualizacją widoku są znikome. Prawdopodobnie już poczułeś największy ból, który poczujesz, kiedy stworzysz widok. Następnym najbliższym będzie, jeśli dodasz do tabeli podstawowej rzędy gazillionów z garstką nowych identyfikatorów, które wymagają nowych wierszy w widoku.

To nie jest zbyt piękne, aby mogło być prawdziwe. Używasz widoków indeksowanych dokładnie tak, jak powinny być używane - lub przynajmniej jednego z najbardziej efektywnych sposobów: płacenia za przyszłe agregacje zapytań w czasie pisania. Działa to najlepiej, gdy wynik jest znacznie mniejszy niż źródło i oczywiście, gdy agregacje są żądane częściej niż aktualizowane są dane bazowe (ogólnie bardziej powszechne w DW niż OLTP).

Niestety wiele osób uważa, że ​​indeksowanie widoku jest magiczne - indeks nie sprawi, że wszystkie widoki będą bardziej wydajne, szczególnie widoki, które po prostu łączą tabele i / lub generują taką samą liczbę wierszy jak źródło (lub nawet mnożenie). W takich przypadkach operacje we / wy z widoku są takie same lub nawet gorsze niż pierwotne zapytanie, nie tylko dlatego, że są takie same lub więcej wierszy, ale często przechowują i materializują także więcej kolumn. Zatem zmaterializowanie tych z wyprzedzeniem nie przynosi żadnych korzyści, ponieważ - nawet w przypadku dysków SSD - operacje we / wy, przetwarzanie i renderowanie sieci i klientów nadal pozostają głównymi wąskimi gardłami w zwracaniu dużych zestawów wyników do klienta. Oszczędności wynikające z unikania łączenia w czasie wykonywania nie są mierzalne w porównaniu do wszystkich innych zasobów, których nadal używasz.

Podobnie jak w przypadku indeksów nieklastrowanych, uważaj, aby nie przesadzić. Jeśli dodasz 10 różnych widoków indeksowanych do jednej tabeli, zobaczysz większy wpływ na część zapisu obciążenia, zwłaszcza jeśli kolumny grupujące nie są kluczem do grupowania.

Rany, zamierzałem blogować na ten temat.

Aaron Bertrand
źródło
19

Odpowiedzi Aaronsa dobrze ujęły to pytanie. Dwie rzeczy do dodania:

  1. Widoki indeksowane agregacji mogą prowadzić do rywalizacji między wierszami i impasu. Zwykle dwie wstawki nie blokują się (z wyjątkiem dość rzadkich warunków, takich jak eskalacja blokady lub kolizja skrótu blokady). Ale jeśli obie wstawki zaadresują tę samą grupę w widoku, będą walczyć. Ten sam punkt dotyczy wszystkiego, co wymaga blokad (DML, wskazówki blokujące).
  2. Przydatne mogą być również widoki indeksowane, które nie agregują się. Pozwalają indeksować kolumny z wielu tabel. W ten sposób możesz efektywnie filtrować według jednej tabeli i porządkować według kolumny z połączonej tabeli. Ten wzór może przekształcić łączenie przy pełnym stole w małe zapytania w czasie stałym.

Użyłem zarówno agregacji, jak i łączenia widoków z ogromną korzyścią.

Podsumowując, Twój przypadek użycia wydaje się idealnym przypadkiem. Widoki indeksowane są techniką znacznie niewykorzystaną.

usr
źródło