Natknąłem się na artykuły, które stwierdzą, że SELECT COUNT(*) FROM TABLE_NAME
będzie wolno, gdy tabela będzie miała wiele wierszy i kolumn.
Mam tabelę, która może zawierać nawet miliardy wierszy [zawiera około 15 kolumn]. Czy istnieje lepszy sposób na uzyskanie DOKŁADNEJ liczby wierszy tabeli?
Przed odpowiedzią rozważ następujące kwestie:
Szukam niezależnego dostawcy bazy danych. Jest OK, jeśli obejmuje MySQL , Oracle , MS SQL Server . Ale jeśli naprawdę nie ma rozwiązania niezależnego od dostawcy bazy danych, zadowolę się różnymi rozwiązaniami dla różnych dostawców baz danych.
Nie mogę użyć do tego żadnego innego narzędzia zewnętrznego. Głównie szukam rozwiązania opartego na SQL.
Nie mogę normalizować projektu bazy danych. Jest już w 3NF, a ponadto napisano wokół niego dużo kodu.
Odpowiedzi:
Prosta odpowiedź:
COUNT(*)
Uwagi:
COUNT (1) = COUNT (*) = COUNT (PrimaryKey) na wszelki wypadek
Edytować:
Przykład programu SQL Server (1,4 miliarda wierszy, 12 kolumn)
1 biegi, 5:46 minut, liczba = 1 401 659,700
2 przebiegi, oba poniżej 1 sekundy, liczą = 1 401 659 670
Drugi ma mniej wierszy = źle. Byłoby to samo lub więcej w zależności od zapisów (tutaj usuwa się poza godzinami)
źródło
COUNT(*) = COUNT(key)
. To jest po prostu złe. Jeśli nie ma żadnychNOT NULL
ograniczeń - nie mogą być one równe (zarówno w wynikach, jak i w planie wykonania).index_id < 2
?Jak dotąd najszybszym sposobem na MySQL jest:
Natychmiast otrzymasz wszystkie swoje tabele z liczbą wierszy (która jest sumą) wraz z mnóstwem dodatkowych informacji, jeśli chcesz.
źródło
To zależy od bazy danych. Niektóre przyspieszenie się liczy, na przykład śledząc, czy wiersze są aktywne, czy martwe w indeksie, pozwalając na skanowanie tylko indeksu w celu wyodrębnienia liczby wierszy. Inni tego nie wymagają, a zatem wymagają odwiedzenia całego stołu i zliczania wierszy na żywo jeden po drugim. Albo będzie wolny dla dużego stołu.
Zauważ, że ogólnie możesz wyodrębnić dobre oszacowanie za pomocą narzędzi do optymalizacji zapytań, statystyk tabel itp. Na przykład w przypadku PostgreSQL możesz przeanalizować dane wyjściowe
explain count(*) from yourtable
i uzyskać dość dobre oszacowanie liczby wierszy. Co prowadzi mnie do twojego drugiego pytania.Poważnie? :-) Naprawdę masz na myśli dokładną liczbę z tabeli z miliardami wierszy? Czy jesteś pewny? :-)
Jeśli tak naprawdę możesz, możesz śledzić sumę za pomocą wyzwalaczy, ale jeśli tak, pamiętaj o współzależności i impasach.
źródło
Aby odpowiedzieć na twoje pytanie, po prostu: Nie .
Jeśli potrzebujesz niezależnego sposobu DBMS, najszybszym sposobem będzie zawsze:
Niektórzy dostawcy DBMS mogą mieć szybsze sposoby, które będą działać tylko dla ich systemów. Niektóre z tych opcji są już opublikowane w innych odpowiedziach.
COUNT(*)
i tak powinny być zoptymalizowane przez DBMS (przynajmniej jakikolwiek PROD godny DB), więc nie próbuj ominąć ich optymalizacji.Na marginesie:
jestem pewien, że wiele innych twoich zapytań również zajmuje dużo czasu ze względu na rozmiar twojego stołu. Wszelkie problemy z wydajnością należy rozwiązać, biorąc pod uwagę szybkość projektowania. Zdaję sobie sprawę, że powiedziałeś, że nie można tego zmienić, ale może się okazać, że ponad 10-minutowe zapytania również nie są możliwe. 3. NF nie zawsze jest najlepszym podejściem, gdy potrzebujesz prędkości, a czasem dane można podzielić na kilka tabel, jeśli rekordy nie muszą być przechowywane razem. Coś do przemyślenia...
źródło
Mam ten skrypt z innego pytania / odpowiedzi StackOverflow:
Moja tabela ma 500 milionów rekordów, a powyższe zwraca w mniej niż 1ms. W międzyczasie,
zajmuje pełne 39 minut, 52 sekund!
Dają dokładnie taką samą liczbę wierszy (w moim przypadku dokładnie 519326012).
Nie wiem, czy tak będzie zawsze.
źródło
Możesz spróbować tego sp_spaceused (Transact-SQL)
źródło
Jeśli wersja SQL Server to 2005/2008, możesz użyć DMV do obliczenia liczby wierszy w tabeli:
W przypadku silnika bazy danych SQL Server 2000 sysindexes będzie działał, ale zdecydowanie zaleca się, aby nie używać go w przyszłych wersjach SQL Server, ponieważ może zostać usunięty w najbliższej przyszłości.
Przykładowy kod pobrany z: Jak szybko i bezboleśnie uzyskać liczbę wierszy tabeli
źródło
używam
źródło
Nie jestem tak ekspertem, jak inni, którzy odpowiedzieli, ale miałem problem z procedurą, z której korzystałem, aby wybrać losowy wiersz z tabeli (niezbyt istotne), ale musiałem znać liczbę wierszy w tabeli referencyjnej obliczyć losowy indeks. Używając tradycyjnej pracy Count (*) lub Count (1), ale czasami otrzymywałem do 2 sekund na uruchomienie zapytania. Zamiast tego (dla mojej tabeli o nazwie „tbl_HighOrder”) używam:
Działa świetnie, a czasy zapytań w Management Studio wynoszą zero.
źródło
Późno o 5 lat i nie jestem pewien, czy to pomoże:
Próbowałem policzyć nie. wierszy w tabeli programu SQL Server za pomocą MS SQL Server Management Studio i wystąpił błąd przepełnienia, a następnie użyłem poniższego:
wybierz count_big (1) FROM [dbname]. [dbo]. [FactSampleValue];
Wynik :
24296650578 wierszy
źródło
Znalazłem ten dobry artykuł SQL Server – JAK: szybko pobrać dokładną liczbę wierszy dla tabeli z
martijnh1
której daje dobre podsumowanie dla każdego scenariusza.Potrzebuję go rozszerzyć, gdy muszę podać liczbę w oparciu o konkretny warunek, a kiedy zorientuję się w tej części, zaktualizuję tę odpowiedź dalej.
Tymczasem oto szczegóły z artykułu:
Metoda 1:
Pytanie:
Komentarze:
Wykonuje pełne skanowanie tabeli. Wolno na dużych stołach.
Metoda 2:
Pytanie:
Komentarze:
Szybki sposób na odzyskanie liczby wierszy. Zależy od statystyk i jest niedokładny.
Uruchom DBCC UPDATEUSAGE (baza danych) Z COUNT_ROWS, co może zająć dużo czasu w przypadku dużych tabel.
Metoda 3:
Pytanie:
Komentarze:
Sposób, w jaki studio zarządzania SQL zlicza wiersze (spójrz na właściwości tabeli, pamięć, liczbę wierszy). Bardzo szybko, ale wciąż przybliżona liczba rzędów.
Metoda 4:
Pytanie:
Komentarze:
Szybka (choć nie tak szybka jak metoda 2) i równie ważna, niezawodna.
źródło
Nie wydaje mi się, aby istniało ogólne najszybsze rozwiązanie: niektóre wersje RDBMS / mają specjalną optymalizację, dzięki
SELECT COUNT(*)
czemu korzystają z szybszych opcji, podczas gdy inne po prostu skanują tabelę. Będziesz musiał przejść do stron dokumentacji / wsparcia dla drugiego zestawu, który prawdopodobnie będzie wymagał napisania bardziej szczegółowych zapytań, zwykle takich, które w jakiś sposób trafią w indeks.EDYTOWAĆ:
Oto myśl, która może działać, w zależności od schematu i dystrybucji danych: czy masz indeksowaną kolumnę, która odwołuje się do rosnącej wartości, rosnącego identyfikatora numerycznego, powiedzmy, a nawet sygnatury czasowej lub daty? Następnie, zakładając, że nie nastąpi usunięcie, powinno być możliwe zapisanie liczby do pewnej ostatniej wartości (wczorajsza data, najwyższa wartość identyfikatora w pewnym ostatnim punkcie próbki) i dodanie liczby poza tym, co powinno bardzo szybko rozwiązać w indeksie . Oczywiście bardzo zależy od wartości i wskaźników, ale ma zastosowanie do niemal każdej wersji dowolnego DBMS.
źródło
SELECT COUNT(*)
. Nawet MySQL najwyraźniej to robi ...Spóźniłem się z tym pytaniem, ale oto, co możesz zrobić z MySQL (ponieważ korzystam z MySQL). Tutaj dzielę się swoimi spostrzeżeniami:
Wynik Liczba
wierszy: 508534 Dane
wyjściowe konsoli: Dotknięte wiersze: 0 Znaleziono wiersze: 1 Ostrzeżenia: 0 Czas trwania 1 zapytania: 0,125 sek.
Zajmuje trochę czasu dla tabeli z dużą liczbą wierszy, ale liczba wierszy jest bardzo dokładna.
Wynik
Liczba wierszy: 511235 Dane
wyjściowe konsoli: Dotknięte wiersze: 0 Znaleziono wiersze: 1 Ostrzeżenia: 0 Czas trwania 1 zapytania: 0,250 s Podsumowanie: Liczba wierszy nie jest dokładna.
Wynik
Liczba wierszy: 507806 Dane
wyjściowe konsoli: Dotknięte wiersze: 0 Znaleziono wiersze: 48 Ostrzeżenia: 0 Czas trwania 1 zapytania: 1,701 s.
Liczba wierszy nie jest dokładna.
Nie jestem ekspertem od MySQL ani baz danych, ale odkryłem, że w przypadku bardzo dużych tabel można użyć opcji 2 lub 3 i uzyskać „rzetelny obraz” liczby obecnych wierszy.
Potrzebowałem uzyskać te liczby wierszy do wyświetlania niektórych statystyk w interfejsie użytkownika. Dzięki powyższym zapytaniom wiedziałem, że suma wierszy wynosi ponad 500 000, więc wymyśliłem statystyki takie jak „Ponad 500 000 wierszy” bez pokazywania dokładnej liczby wierszy.
Może tak naprawdę nie odpowiedziałem na pytanie PO, ale dzielę się tym, co zrobiłem w sytuacji, gdy takie statystyki były potrzebne. W moim przypadku wyświetlenie przybliżonych wierszy było do zaakceptowania, więc powyższe zadziałało dla mnie.
źródło
Nie do końca agnostyczne rozwiązanie DBMS, ale przynajmniej twój kod klienta nie zobaczy różnicy ...
Utwórz kolejną tabelę T za pomocą tylko jednego wiersza i jednego pola liczb całkowitych N 1 i utwórz INSERT TRIGGER, który po prostu wykonuje:
Utwórz także DELETE TRIGGER, który wykonuje:
DBMS wart swojej soli zagwarantuje atomowość operacji powyżej 2 , a N będzie zawierał dokładną liczbę wierszy przez cały czas, co jest bardzo szybkie, aby uzyskać po prostu:
Chociaż wyzwalacze są specyficzne dla DBMS, wybranie z T nie jest i kod klienta nie będzie musiał się zmieniać dla każdego obsługiwanego DBMS.
Może to jednak powodować pewne problemy ze skalowalnością, jeśli tabela wymaga intensywnego WSTAWIANIA lub USUWANIA, zwłaszcza jeśli nie zatwierdza się natychmiast po Wstawieniu / Usunięciu.
1 Te nazwy to tylko symbole zastępcze - używaj czegoś bardziej znaczącego w produkcji.
2 Tj. N nie można zmienić przez jednoczesną transakcję między odczytem a zapisem na N, o ile zarówno odczyt, jak i zapis odbywają się w pojedynczej instrukcji SQL.
źródło
Dosłownie szalona odpowiedź, ale jeśli masz skonfigurowany system replikacji (w przypadku systemu z miliardem wierszy, mam nadzieję, że tak), możesz użyć przybliżonego oszacowania (jak
MAX(pk)
), podzielić tę wartość przez liczbę niewolników masz, uruchom kilka zapytań równolegle.W większości przypadków podzielilibyśmy zapytania na urządzenia podrzędne w oparciu o najlepszy klucz (lub chyba klucz podstawowy), w taki sposób (użyjemy 250000000 jako naszych wierszy / niewolników):
Ale potrzebujesz tylko SQL. Co za popiersie. Ok, powiedzmy, że jesteś sadomasochistą. W systemie głównym (lub najbliższym niewolniku) najprawdopodobniej musisz utworzyć tabelę:
Zamiast więc wybierać tylko w twoich niewolnikach, musisz zrobić wstawkę, podobnie jak to:
Możesz napotkać problemy z niewolnikami piszącymi do stołu na master. Być może będziesz potrzebować jeszcze więcej sadis - mam na myśli, kreatywnych:
W końcu powinieneś mieć urządzenie podrzędne, które istnieje jako ostatnie na ścieżce przechodzącej przez wykres replikacji, względem pierwszego urządzenia podrzędnego. Ten niewolnik powinien mieć teraz wszystkie inne wartości liczników i powinien mieć własne wartości. Ale zanim skończysz, prawdopodobnie są dodawane wiersze, więc będziesz musiał wstawić kolejny, kompensując zarejestrowany maksymalny pk w tabeli licznika i bieżący maksymalny pk.
W tym momencie musisz wykonać funkcję agregującą, aby dowiedzieć się, jakie są sumy wierszy, ale jest to łatwiejsze, ponieważ działałbyś na co najwyżej liczbie „niewolników, które masz i zmieniasz”.
Jeśli jesteś w sytuacji, w której masz oddzielne tabele w niewolnikach, możesz
UNION
uzyskać wszystkie potrzebne wiersze.Albo wiesz, bądź nieco mniej szalony i migruj swoje dane do rozproszonego systemu przetwarzania, lub może skorzystaj z rozwiązania Data Warehousing (które zapewni Ci niesamowite awarie danych w przyszłości).
Uwaga: zależy to od tego, jak dobrze skonfigurowana jest Twoja replikacja. Ponieważ głównym wąskim gardłem będzie najprawdopodobniej trwała pamięć masowa, jeśli masz nieuporządkowaną pamięć masową lub źle posegregowane magazyny danych z dużym hałasem sąsiadów, prawdopodobnie spowoduje to wolniejsze działanie niż czekanie na pojedynczy
SELECT COUNT(*) ...
Ale jeśli masz dobrą replikację, to twój wzrost prędkości powinien być bezpośrednio związany z liczbą lub niewolnikami. W rzeczywistości, jeśli uruchomienie kwerendy liczącej zajmie 10 minut, a masz 8 niewolników, skrócisz czas do mniej niż kilku minut. Może za godzinę wyjaśnimy szczegóły tego rozwiązania.
Oczywiście tak naprawdę nigdy nie uzyskałbyś niezwykle dokładnej odpowiedzi, ponieważ to rozwiązanie rozproszone wprowadza trochę czasu, w którym wiersze mogą być usuwane i wstawiane, ale możesz spróbować uzyskać rozproszoną blokadę wierszy w tym samym wystąpieniu i uzyskać dokładną liczbę wierszy w tabeli dla określonego momentu w czasie.
W rzeczywistości wydaje się to niemożliwe, ponieważ w zasadzie utknąłeś w rozwiązaniu opartym tylko na SQL i nie sądzę, że masz mechanizm natychmiastowego uruchamiania podzielonego i zablokowanego zapytania na wielu urządzeniach podrzędnych. Być może, jeśli masz kontrolę nad plikiem dziennika replikacji ... co oznacza, że dosłownie rozpędzasz niewolników w tym celu, co bez wątpienia jest wolniejsze niż uruchamianie kwerendy liczenia na jednym komputerze.
Oto moje dwa grosze z 2013 roku.
źródło
Jeśli wkładka wyzwalacza jest zbyt drogie w użyciu, ale kasowania wyzwalania może być udzielana i nie ma automatycznego przyrostu
id
, a następnie po raz zliczania całą tabelę, pamiętanie licznik jaklast-count
ilast-counted-id
,wtedy każdego dnia wystarczy policzyć
id
>last-counted-id
, dodać tolast-count
i zapisać nowelast-counted-id
.Wyzwalacz usuwania zmniejszyłby ostatnią liczbę, jeśli identyfikator usuniętego rekordu <= ostatni liczony identyfikator.
źródło
Jeśli masz typową strukturę tabeli z kolumną klucza podstawowego z automatyczną inkrementacją, w której wiersze nigdy nie są usuwane, następujący sposób będzie najszybszym sposobem ustalenia liczby rekordów i powinien działać podobnie w większości baz danych zgodnych z ANSI:
Pracuję z tabelami MS SQL zawierającymi miliardy wierszy, które wymagają podsekundowych czasów odpowiedzi na dane, w tym liczby rekordów. Porównywanie podobnego WYBRANEGO LICZBY (*) zajmuje kilka minut.
źródło
INSERT
transakcja zostanie wycofana? Ta wartość klucza podstawowego byłaby nieobecna, więc rzeczywista liczba rekordów byłaby o jeden mniejsza od wartości maksymalnej.count(*)
, jeśli dostawca bazy danych nie zoptymalizuje w wystarczającym stopniucount(*)
: Każdego dnia śledź ostatni automatyczny indeks i odpowiadającą mu liczbę, a następnie poproś o liczbę rekordów powyżej. Może również obsługiwaćdelete
s, jeśli dodasz wyzwalacz podczas usuwania, który zmniejsza poprzednią sumę, jeśli usunięty rekord id <= ten ostatni autoindeks.W przypadku serwera Sql spróbuj tego
źródło
wybierz wiersze z sysindexes, gdzie id = Object_ID ('TableName') i indid <2
źródło
Umieść indeks w jakiejś kolumnie. To powinno umożliwić optymalizatorowi wykonanie pełnego skanu bloków indeksu zamiast pełnego skanu tabeli. To znacznie obniży koszty IO. Spójrz na plan wykonania przed i po. Następnie zmierz czas na ścianie na dwa sposoby.
źródło
Jeśli używasz Oracle, co powiesz na to (zakładając, że statystyki tabeli są aktualizowane):
last_analyzed pokaże czas, kiedy statystyki zostały ostatnio zebrane.
źródło
Z PostgreSQL:
źródło
W SQL Server 2016 mogę po prostu sprawdzić właściwości tabeli, a następnie wybrać kartę „Pamięć” - daje mi to liczbę wierszy, miejsce na dysku używane przez tabelę, używane miejsce na indeks itp.
źródło
database vendor independent solution
. Wymaga to również GUI i nie można go zautomatyzować. Również nie jest szybszy niż COUNT (*)Może trochę za późno, ale może to pomóc innym w MSSQL
źródło