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 BY
w 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?
SELECT
iCREATE VIEW
skrypty są błędne, ponieważ uważam, że to twójCREATE INDEX
skrypt.Odpowiedzi:
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.
źródło
Odpowiedzi Aaronsa dobrze ujęły to pytanie. Dwie rzeczy do dodania:
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ą.
źródło