Najszybszy sposób na zliczenie dokładnej liczby wierszy w bardzo dużej tabeli?


234

Natknąłem się na artykuły, które stwierdzą, że SELECT COUNT(*) FROM TABLE_NAMEbę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.


4
Ciekawe, dlaczego potrzebna jest dokładna natychmiastowa liczba wierszy, gdy masz ich miliardy ...
zerkms

2
Czy nie wszyscy mielibyśmy nadzieję, że ten konkretny konstrukt został zoptymalizowany przez naszego dostawcę bazy danych?
KevinDTimm

5
@Swaranga, czy możesz wyjaśnić nieco więcej na temat celu utrzymania bazy danych, który musi znać dokładną liczbę wierszy w tabeli? Nie wyobrażam sobie I jak mówi Kevin, jeśli byłby szybszy sposób niż COUNT (*), to dostawca DBMS (powinien) z pewnością ponownie zaimplementowałby COUNT (*), aby z niego skorzystać ...
Tony Andrews

3
Z pewnością, jeśli tabela jest często zapisywana, wówczas dokładna liczba będzie dokładna tylko dla określonego momentu w czasie i może nawet nie być dokładna, jeśli inne procesy zapisują do tabeli, chyba że zablokujesz zapytanie w zapytaniu.
Steve Ford

2
Możesz użyć wyzwalaczy wstawiania i usuwania, aby zachować ciągłą liczbę?
paparazzo

Odpowiedzi:


246

Prosta odpowiedź:

  • Niezależne od dostawcy bazy danych rozwiązanie = użyj standardu = COUNT(*)
  • Istnieją przybliżone rozwiązania SQL Server, ale nie używaj COUNT (*) = poza zakresem

Uwagi:

COUNT (1) = COUNT (*) = COUNT (PrimaryKey) na wszelki wypadek

Edytować:

Przykład programu SQL Server (1,4 miliarda wierszy, 12 kolumn)

SELECT COUNT(*) FROM MyBigtable WITH (NOLOCK)
-- NOLOCK here is for me only to let me test for this answer: no more, no less

1 biegi, 5:46 minut, liczba = 1 401 659,700

--Note, sp_spaceused uses this DMV
SELECT
   Total_Rows= SUM(st.row_count)
FROM
   sys.dm_db_partition_stats st
WHERE
    object_name(object_id) = 'MyBigtable' AND (index_id < 2)

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)


9
Nie, COUNT(*) = COUNT(key). To jest po prostu złe. Jeśli nie ma żadnych NOT NULLograniczeń - nie mogą być one równe (zarówno w wynikach, jak i w planie wykonania).
zerkms

14
@zerkmsby: Przez COUNT (klucz) miałem na myśli COUNT (klucz podstawowy), który nie powinien mieć wartości zerowej. Będę wyjaśnić
gbn

8
z (NOLOCK) nie jest czymś, co pozwala mu działać na produkcji, i może prowadzić do niedokładnego liczenia. Kiedy użyjesz tej wskazówki, na pewno zapobiega blokadom, ale efektem ubocznym na polu produkcyjnym jest to, że możesz policzyć rzędy dwa razy w niektórych sytuacjach lub pominąć rzędy w innych sytuacjach. NOLOCK lepiej jest używać na stole, który nie jest zapisywany, ponieważ pozwala na „brudne odczyty”. Nie radzę, aby ludzie używali tej wskazówki, chyba że w pełni rozumieją konsekwencje
Davos,

4
@mishrsud Jedyne dokładne zapytanie to SELECT COUNT (*), ale jest wolne. Możesz mieć dokładny i wolny lub szorstki i szybki. To, co zrobisz, będzie zależeć od tego, co jest ważniejsze dla celu, dla którego potrzebujesz liczenia. ŻADNA ZABLOKOWANIE nie może zawierać lub nawet wykluczać wierszy będących w połowie transakcji lub stron z dowolnego powodu.
Davos,

5
@ gbn bardzo fajne rozwiązanie, czy możesz powiedzieć, z czego korzysta index_id < 2?
popełnić

29

Jak dotąd najszybszym sposobem na MySQL jest:

SHOW TABLE STATUS;

Natychmiast otrzymasz wszystkie swoje tabele z liczbą wierszy (która jest sumą) wraz z mnóstwem dodatkowych informacji, jeśli chcesz.


1
Inteligentny sposób… dzięki temu możesz uzyskać liczbę wierszy wielu tabel w 1 zapytaniu.
Deval Khandelwal,

czy działałeś na db mając tabele z ~ miliardem wpisów takich jak @gbn i zauważyłeś czas?
KNU

jaką wartością jest łączna liczba wierszy dla wszystkich tabel w bazie danych? I są przybliżone - co jeśli chcesz dokładnych wartości liczby wierszy?
Kreeverp

2
to w ogóle nie działa, na przykład w INNODB silnik pamięci masowej odczytuje kilka wierszy i dokonuje ekstrapolacji, aby odgadnąć liczbę wierszy
Martijn Scheffer

10

Natknąłem się na artykuły, które mówią, że WYBIERZ LICZBĘ (*) Z TABELI_NAME będzie powolny, gdy tabela będzie miała wiele wierszy i kolumn.

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 yourtablei uzyskać dość dobre oszacowanie liczby wierszy. Co prowadzi mnie do twojego drugiego pytania.

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?

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.


Tak, Denis, wymagana jest dokładna liczba. :(
Swaranga Sarma

5
To szczęście, że menedżerowie Google są bardziej rozsądni niż szef ... Wyobraź sobie, jak powolny byłby, gdyby zwracał dokładną liczbę wyników wyszukiwania dla każdego z twoich zapytań zamiast trzymać się szacunkowej liczby.
Denis de Bernardy

Przynajmniej współczujesz mi. Co powiesz na jedyne rozwiązanie Oracle? To do pewnego stopnia zmniejszy mój problem. Obecnie klient korzysta z Oracle; więc jeśli wymyślę obejście tylko dla Wyroczni, zrobi to [na razie]. :)
Swaranga Sarma

6
„Tak, Denis, wymagana jest dokładna liczba. :(” - cóż, mogę tylko spekulować. Czy proces konserwacji db wykryje, że w tabeli A jest 42 123 876 wierszy, a następnie utworzy 42 123 876 pustych wierszy w tabeli B, a następnie przejdzie przez tabelę A i zaktualizuj wiersze w tabeli B ...? A może to bardziej szalone? ;-)
Tony Andrews

1
Transakcja 2 nie może się rozpocząć przed zatwierdzeniem transakcji 1. Bez aktualizacji „tabeli zliczeń” wiele transakcji aktualizacji mogłoby działać równolegle. Dzięki „tabeli zliczeń” każda transakcja musi „uzyskać bilet” na aktualizację zliczania. Tak więc transakcje zaczynają się kolejkować w automacie biletowym (harmonogram decyduje, kto będzie następny, aby uzyskać blokadę tabeli liczników).
Erwin Smout,

10

Czy istnieje lepszy sposób na uzyskanie DOKŁADNEJ liczby wierszy tabeli?

Aby odpowiedzieć na twoje pytanie, po prostu: Nie .

Jeśli potrzebujesz niezależnego sposobu DBMS, najszybszym sposobem będzie zawsze:

SELECT COUNT(*) FROM TableName

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...


10

Mam ten skrypt z innego pytania / odpowiedzi StackOverflow:

SELECT SUM(p.rows) FROM sys.partitions AS p
  INNER JOIN sys.tables AS t
  ON p.[object_id] = t.[object_id]
  INNER JOIN sys.schemas AS s
  ON s.[schema_id] = t.[schema_id]
  WHERE t.name = N'YourTableNameHere'
  AND s.name = N'dbo'
  AND p.index_id IN (0,1);

Moja tabela ma 500 milionów rekordów, a powyższe zwraca w mniej niż 1ms. W międzyczasie,

SELECT COUNT(id) FROM MyTable

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.


Czy możesz dodać parametr, aby uzyskać liczbę wierszy za pomocą tego zapytania? Przykład: wybierz COUNT (1) Z TABLENAME GDZIE ColumnFiled = „1” Z twoim zapytaniem?
VnDevil

To jest liczba - liczba wierszy (rekordów) jest w tym przypadku „liczbą”. „500 milionów rekordów” to przybliżona liczba, a „519326012” to dokładna liczba wierszy lub liczba. Rzędy = rekordy = liczba.
JakeJ

9

Możesz spróbować tego sp_spaceused (Transact-SQL)

Wyświetla liczbę wierszy, zarezerwowane miejsce na dysku i miejsce na dysku używane przez tabelę, widok indeksowany lub kolejkę Service Broker w bieżącej bazie danych lub wyświetla miejsce na dysku zarezerwowane i używane przez całą bazę danych.


Czy sp_spaceused nie da mi przybliżonej liczby?
Swaranga Sarma

1
Do Twojej wiadomości: Używa sys.dm_db_partition_stats wewnętrznie
gbn

6

Jeśli wersja SQL Server to 2005/2008, możesz użyć DMV do obliczenia liczby wierszy w tabeli:

-- Shows all user tables and row counts for the current database 
-- Remove is_ms_shipped = 0 check to include system objects 
-- i.index_id < 2 indicates clustered index (1) or hash table (0) 
SELECT o.name, 
 ddps.row_count 
FROM sys.indexes AS i 
 INNER JOIN sys.objects AS o ON i.OBJECT_ID = o.OBJECT_ID 
 INNER JOIN sys.dm_db_partition_stats AS ddps ON i.OBJECT_ID = ddps.OBJECT_ID 
 AND i.index_id = ddps.index_id 
WHERE i.index_id < 2 
 AND o.is_ms_shipped = 0 
ORDER BY o.NAME 

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


Jest to przybliżone, nie jest dokładne : proszę zobaczyć moją odpowiedź
gbn

Czy znasz przykład, w którym nie jest to dokładne? AFAIK, to nie zależy od zaktualizowanych statystyk.
Alireza Maddah

5

używam

select /*+ parallel(a) */  count(1) from table_name a;

wybierz / * + równolegle (a) * / count (1) z nazwa_tabeli a
Mainsh S

5

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:

Declare @max int

Select @max = Row_Count
From sys.dm_db_partition_stats
Where Object_Name(Object_Id) = 'tbl_HighOrder'

Działa świetnie, a czasy zapytań w Management Studio wynoszą zero.


1
FWIW, powinieneś wspomnieć, Z którego dostawcy bazy danych korzystasz; Myślę, że stwierdzenie to będzie nieco inne w zależności od dostawcy.
ToolmakerSteve,

5

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


5

Znalazłem ten dobry artykuł SQL Server – JAK: szybko pobrać dokładną liczbę wierszy dla tabeli zmartijnh1 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:

SELECT COUNT(*) FROM Transactions 

Komentarze:

Wykonuje pełne skanowanie tabeli. Wolno na dużych stołach.

Metoda 2:

Pytanie:

SELECT CONVERT(bigint, rows) 
FROM sysindexes 
WHERE id = OBJECT_ID('Transactions') 
AND indid < 2 

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:

SELECT CAST(p.rows AS float) 
FROM sys.tables AS tbl 
INNER JOIN sys.indexes AS idx ON idx.object_id = tbl.object_id and
idx.index_id < 2 
INNER JOIN sys.partitions AS p ON p.object_id=CAST(tbl.object_id AS int) 
AND p.index_id=idx.index_id 
WHERE ((tbl.name=N'Transactions' 
AND SCHEMA_NAME(tbl.schema_id)='dbo')) 

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:

SELECT SUM (row_count) 
FROM sys.dm_db_partition_stats 
WHERE object_id=OBJECT_ID('Transactions')    
AND (index_id=0 or index_id=1); 

Komentarze:

Szybka (choć nie tak szybka jak metoda 2) i równie ważna, niezawodna.


Dzięki! Naprawdę przydatna wskazówka. Nie mam uprawnień do przeglądania tabel systemowych, więc metoda 4 to nie ja. Jednak metoda 3 jest wystarczająco dobra.
Nicholas Humphrey,

3

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.


Mam wielką nadzieję, że każdy porządny DBMS użyje indeksu SELECT COUNT(*). Nawet MySQL najwyraźniej to robi ...
śleske,

zakładając, że usunięcia się nie zdarzają - poważnie? ; p
ToolmakerSteve

3

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:

1) SELECT COUNT(*) AS TOTAL_ROWS FROM <TABLE_NAME>

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.

2) SHOW TABLE STATUS or SHOW TABLE STATUS WHERE NAME="<TABLE_NAME>"

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.

3) SELECT * FROM information_schema.tables WHERE table_schema = DATABASE();

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.


2

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:

UPDATE T SET N = N + 1

Utwórz także DELETE TRIGGER, który wykonuje:

UPDATE T SET N = N - 1

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:

SELECT N FROM T

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.


2

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):

-- First slave
SELECT COUNT(pk) FROM t WHERE pk < 250000000
-- Ith slave where 2 <= I <= N - 1
SELECT COUNT(pk) FROM t WHERE pk >= I*250000000 and pk < (I+1)*250000000
-- Last slave
SELECT COUNT(pk) FROM t WHERE pk > (N-1)*250000000

Ale potrzebujesz tylko SQL. Co za popiersie. Ok, powiedzmy, że jesteś sadomasochistą. W systemie głównym (lub najbliższym niewolniku) najprawdopodobniej musisz utworzyć tabelę:

CREATE TABLE counter_table (minpk integer, maxpk integer, cnt integer, slaveid integer)

Zamiast więc wybierać tylko w twoich niewolnikach, musisz zrobić wstawkę, podobnie jak to:

INSERT INTO counter_table VALUES (I*25000000, (I+1)*250000000, (SELECT COUNT(pk) FROM ... ), @@SLAVE_ID)

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:

-- A table per slave!
INSERT INTO counter_table_slave_I VALUES (...)

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 UNIONuzyskać wszystkie potrzebne wiersze.

SELECT SUM(cnt) FROM (
    SELECT * FROM counter_table_slave_1
      UNION
    SELECT * FROM counter_table_slave_2
      UNION
    ...
  )

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 pojedynczySELECT 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.


2

Jeśli wkładka wyzwalacza jest zbyt drogie w użyciu, ale kasowania wyzwalania może być udzielana i nie ma automatycznego przyrostuid , a następnie po raz zliczania całą tabelę, pamiętanie licznik jak last-countilast-counted-id ,

wtedy każdego dnia wystarczy policzyć id> last-counted-id, dodać to last-counti zapisać nowe last-counted-id.

Wyzwalacz usuwania zmniejszyłby ostatnią liczbę, jeśli identyfikator usuniętego rekordu <= ostatni liczony identyfikator.


.. przepraszam, nie mam czasu na pokazanie SQL, który zostałby użyty (mój SQL jest zardzewiały). Jeśli ktoś chciałby edytować moją odpowiedź, aby dodać SQL, byłoby świetnie!
ToolmakerSteve

1

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:

SELECT TOP(1) <primarykeyfield> FROM <table> ORDER BY <primarykeyfield> DESC;

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.


1
Nie do końca prawda - co się stanie, jeśli INSERTtransakcja zostanie wycofana? Ta wartość klucza podstawowego byłaby nieobecna, więc rzeczywista liczba rekordów byłaby o jeden mniejsza od wartości maksymalnej.
Sir Crispalot,

Mogą to być luki w sekwencji. Zwykle jest wynikiem wycofania.
Osa E

W rzeczywistości istnieje modyfikacja tej odpowiedzi, która może być znacznie szybsza niż count(*), jeśli dostawca bazy danych nie zoptymalizuje w wystarczającym stopniu count(*): 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ć deletes, jeśli dodasz wyzwalacz podczas usuwania, który zmniejsza poprzednią sumę, jeśli usunięty rekord id <= ten ostatni autoindeks.
ToolmakerSteve

1

W przypadku serwera Sql spróbuj tego

SELECT T.name, 
       I.rows AS [ROWCOUNT] 
FROM   sys.tables AS T 
       INNER JOIN sys.sysindexes AS I 
               ON T.object_id = I.id AND I.indid < 2 
WHERE T.name = 'Your_Table_Name'
ORDER  BY I.rows DESC 

0

wybierz wiersze z sysindexes, gdzie id = Object_ID ('TableName') i indid <2


0

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.


Jeśli tabela ma miliardy wierszy bez indeksu w dowolnej kolumnie, pojawią się powszechne problemy z wydajnością, znacznie przekraczające potrzebę wyrażoną w pierwotnym pytaniu .. ale dobrze, że o tym wspominasz (nic nie zakładaj!) :)
ToolmakerSteve

0

Jeśli używasz Oracle, co powiesz na to (zakładając, że statystyki tabeli są aktualizowane):

select <TABLE_NAME>, num_rows, last_analyzed from user_tables

last_analyzed pokaże czas, kiedy statystyki zostały ostatnio zebrane.


0

Z PostgreSQL:

SELECT reltuples AS approximate_row_count FROM pg_class WHERE relname = 'table_name'

-1

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.


Szukał database vendor independent solution. Wymaga to również GUI i nie można go zautomatyzować. Również nie jest szybszy niż COUNT (*)
Frieder

-3

Może trochę za późno, ale może to pomóc innym w MSSQL

; WITH RecordCount AS (SELECT ROW_NUMBER () OVER (ORDER BY COLUMN_NAME) AS [RowNumber] FROM TABLE_NAME) SELECT MAX (RowNumber) FROM RecordCount


Jest to znacznie gorsze niż COUNT (), chyba że mamy BARDZO szczęście i optymalizatorowi uda się zoptymalizować go do COUNT () - po co pytać o SORTOWANIE w losowej kolumnie?!?
dsz
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.