Jako uproszczony przykład, załóżmy, że mam taką tabelę:
seq | value
----+------
102 | 11954
211 | 43292
278 | 19222
499 | 3843
Tabela może zawierać setki milionów rekordów i muszę często zadawać takie zapytania:
SELECT sum(value) WHERE seq > $a and seq < $b
Nawet jeśli seq
jest indeksowane, typowa implementacja bazy danych zapętla każdy wiersz, aby w najlepszym przypadku obliczyć sumę O(n)
, gdzie n
jest wielkość zakresu.
Czy istnieje baza danych, która może to zrobić skutecznie, tak jak w O(log(n))
zapytaniu?
Natknąłem się na strukturę danych o nazwie Drzewo segmentów, jak opisano tutaj . Czasami nazywany także drzewem zakresu lub drzewem interwałów, chociaż wszystkie te nazwy są często opisywane jako nieco inna odmiana struktury danych.
Jednak nie spotkałem żadnej bazy danych, która implementowałaby taką strukturę danych. Wdrożenie go od zera jest łatwe dla struktury w pamięci, ale staje się trudne, jeśli trzeba ją utrwalić lub jest zbyt duża, aby zmieściła się w pamięci. Jeśli istnieje skuteczny wzorzec implementacji tego na istniejącej bazie danych, może to również pomóc.
Uwaga dodatkowa: nie jest to tabela tylko do dołączania, więc rozwiązanie takie jak utrzymanie sumy łącznej nie będzie działać w tym przypadku.
Odpowiedzi:
Korzystanie z indeksów SQL Server ColumnStore
No dobra, tylko jeden - klastrowany indeks CS.
Jeśli chcesz przeczytać o sprzęcie, na którym to zrobiłem, zajrzyj tutaj . Pełne ujawnienie, napisałem ten post na blogu na stronie internetowej firmy, dla której pracuję.
Do testu!
Oto ogólny kod do zbudowania całkiem dużego stołu. Takie samo ostrzeżenie jak Evan, kompilacja i indeksowanie może trochę potrwać.
Cóż, Evan wygrywa dla uproszczenia, ale mówiłem o tym wcześniej.
Oto definicja indeksu. La i dee i dah.
Patrząc na liczbę, każdy identyfikator ma dość równomierny rozkład:
Wyniki:
...
Z każdym Id o ~ 5,005,005 wierszy, możemy spojrzeć na dość mały zakres identyfikatorów, aby uzyskać sumę 10 milionów wierszy.
Wynik:
Profil zapytania:
Dla zabawy większa agregacja:
Wyniki:
Profil zapytania:
Mam nadzieję że to pomoże!
źródło
PostgreSQL z indeksem BRIN
To nieprawda. Przynajmniej żadna przyzwoita baza danych tego nie zrobi. PostgreSQL obsługuje tworzenie indeksów BRIN na tego rodzaju tabelach. Indeksy BRIN są bardzo małe i mogą zmieścić się w pamięci ram nawet na tak dużych stołach. Setki milionów rzędów to nic.
Tutaj zdefiniowano 300 milionów wierszy dokładnie tak, jak je zamówiłeś. Ostrzeżenie: utworzenie go może zająć dużo czasu (czas: 336057.807 ms + 95121,809 ms dla indeksu).
I teraz...
1,4 sekundy na agregację / zsumowanie 5 889 135 wierszy w danym zakresie.
Mimo że tabela wynosi 10 GB, indeks BRIN wynosi 304 kB.
Nawet szybciej
Jeśli nadal nie jest to wystarczająco szybkie, możesz buforować agregaty o 100 000 wierszy.
Teraz będziesz potrzebować tylko
2(1e5-1)
wiersza solanki i agregacji zamiast 300 milionów lub cokolwiek innego.Sprzęt komputerowy
Lenovo x230, i5-3230M, 16 GB pamięci RAM, 1 TB Samsung 840 SSD.
źródło
O(n)
Być może zmaterializowany pogląd może być lepszy niżO(sqrt(n))
. Zależy od tego, jak zdefiniujesz przedziały, które będą używane w materializacji.