Cara tercepat untuk menghitung jumlah baris dalam tabel yang sangat besar?

234

Saya telah menemukan artikel yang menyatakan bahwa SELECT COUNT(*) FROM TABLE_NAMEakan lambat ketika tabel memiliki banyak baris dan banyak kolom.

Saya memiliki tabel yang mungkin berisi miliaran baris [memiliki sekitar 15 kolom]. Apakah ada cara yang lebih baik untuk mendapatkan hitungan EXACT dari jumlah baris tabel?

Harap pertimbangkan yang berikut sebelum jawaban Anda:

  • Saya mencari solusi independen vendor database. Tidak apa-apa jika mencakup MySQL , Oracle , MS SQL Server . Tetapi jika benar - benar tidak ada solusi vendor database independen maka saya akan puas dengan solusi yang berbeda untuk vendor database yang berbeda.

  • Saya tidak bisa menggunakan alat eksternal lain untuk melakukan ini. Saya terutama mencari solusi berbasis SQL.

  • Saya tidak bisa menormalkan desain database saya lebih jauh. Itu sudah dalam 3NF dan terlebih lagi banyak kode telah ditulis di sekitarnya.

Swaranga Sarma
sumber
4
Dan hanya ingin tahu mengapa diperlukan jumlah instan baris yang tepat ketika Anda memiliki milyarannya ...
zerkms
2
Tidakkah kita semua berharap bahwa konstruksi khusus ini telah dioptimalkan oleh vendor database kami?
KevinDTimm
5
@Swaranga, dapatkah Anda menjelaskan sedikit lebih banyak tentang apa tujuan pemeliharaan basis data ini yang harus mengetahui jumlah persis baris dalam tabel? Saya tidak bisa membayangkan. Dan seperti kata Kevin, jika ada cara yang lebih cepat dari COUNT (*) maka vendor DBMS pasti (harus) menerapkan kembali COUNT (*) untuk menggunakannya ...
Tony Andrews
3
Tentunya jika tabel sedang ditulis untuk sering maka jumlah pasti Anda hanya akan tepat untuk titik waktu tertentu, dan bahkan mungkin tidak akurat jika proses lain menulis ke tabel, kecuali jika Anda meletakkan kunci meja pada kueri.
Steve Ford
2
Anda dapat menggunakan sisipkan dan hapus pemicu untuk menjaga jumlah yang bergulir?
paparazzo

Jawaban:

246

Jawaban sederhana:

  • Vendor independen solusi basis data = gunakan standar = COUNT(*)
  • Ada perkiraan solusi SQL Server tetapi jangan gunakan COUNT (*) = di luar cakupan

Catatan:

COUNT (1) = COUNT (*) = COUNT (PrimaryKey) untuk berjaga-jaga

Edit:

Contoh SQL Server (1,4 miliar baris, 12 kolom)

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

1 lari, 5:46 menit, hitung = 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 run, keduanya di bawah 1 detik, hitung = 1.401.659.670

Yang kedua memiliki lebih sedikit baris = salah. Akan sama atau lebih tergantung pada penulisan (penghapusan dilakukan di luar jam di sini)

gbn
sumber
9
Tidak COUNT(*) = COUNT(key). Ini salah. Jika tidak ada NOT NULLkendala - maka mereka tidak bisa sama (dalam hasil maupun dalam rencana eksekusi).
zerkms
14
@zerkmsby: Untuk COUNT (kunci) yang saya maksud COUNT (primarykey) yang seharusnya tidak dapat dibatalkan. Saya akan mengklarifikasi
gbn
8
dengan (NOLOCK) bukan sesuatu yang memungkinkannya berjalan pada produksi, dan dapat menyebabkan hitungan yang tidak akurat. Ketika Anda menggunakan petunjuk itu, yakin itu mencegah kunci tetapi efek samping pada kotak produksi adalah bahwa Anda dapat menghitung baris dua kali dalam beberapa situasi atau melewati baris dalam situasi lain. NOLOCK lebih baik digunakan pada tabel yang tidak ditulis karena memungkinkan "membaca kotor". Jangan menyarankan orang untuk menggunakan petunjuk itu kecuali mereka sepenuhnya memahami konsekuensinya
Davos
4
@mishrsud Satu-satunya permintaan akurat adalah SELECT COUNT (*), tetapi lambat. Anda dapat memiliki tepat & lambat, atau kasar dan cepat. Apa yang Anda lakukan akan bergantung pada apa yang lebih penting untuk tujuan yang Anda perlukan. TIDAK KUNCI mungkin termasuk atau memang mengecualikan baris yang tengah transaksi atau halaman bergerak untuk alasan apa pun.
Davos
5
@ Gbn solusi yang sangat bagus, bisakah Anda tahu apa gunanya index_id < 2?
melakukan
29

Cara tercepat sejauh ini di MySQL adalah:

SHOW TABLE STATUS;

Anda akan langsung mendapatkan semua tabel Anda dengan jumlah baris (yang merupakan total) bersama dengan banyak informasi tambahan jika Anda mau.

salbahra
sumber
1
Cara cerdas..dengan ini Anda bisa mendapatkan jumlah baris beberapa tabel dalam 1 kueri.
Deval Khandelwal
apakah Anda menjalankan db memiliki tabel dengan ~ miliar entri seperti @gbn dan memperhatikan waktu?
KNU
nilai mana yang merupakan jumlah baris total untuk semua tabel dalam database? Dan ini adalah perkiraan - bagaimana jika Anda ingin nilai jumlah baris yang tepat?
Kreeverp
2
ini tidak bekerja sama sekali, pada INNODB misalnya, mesin penyimpanan membaca beberapa baris dan memperkirakan untuk memperkirakan jumlah baris
Martijn Scheffer
10

Saya telah menemukan artikel yang menyatakan bahwa SELECT COUNT (*) FROM TABLE_NAME akan lambat ketika tabel memiliki banyak baris dan banyak kolom.

Itu tergantung pada database. Beberapa mempercepat menghitung, misalnya dengan melacak apakah baris hidup atau mati dalam indeks, memungkinkan untuk hanya memindai indeks untuk mengekstrak jumlah baris. Yang lain tidak, dan akibatnya perlu mengunjungi seluruh meja dan menghitung baris langsung satu per satu. Entah akan lambat untuk meja besar.

Perhatikan bahwa Anda biasanya dapat mengekstraksi estimasi yang baik dengan menggunakan alat optimisasi kueri, statistik tabel, dll. Dalam kasus PostgreSQL, misalnya, Anda dapat mengurai output explain count(*) from yourtabledan mendapatkan estimasi jumlah baris yang cukup baik. Yang membawa saya ke pertanyaan kedua Anda.

Saya memiliki tabel yang mungkin berisi miliaran baris [memiliki sekitar 15 kolom]. Apakah ada cara yang lebih baik untuk mendapatkan hitungan EXACT dari jumlah baris tabel?

Serius? :-) Maksud Anda hitungan yang tepat dari tabel dengan miliaran baris? Apakah kamu benar-benar yakin? :-)

Jika Anda benar - benar melakukannya, Anda bisa menyimpan jejak total penggunaan trigger, tetapi perhatikan konkurensi dan deadlock jika Anda melakukannya.

Denis de Bernardy
sumber
Ya Denis, hitungan yang tepat diperlukan. :(
Swaranga Sarma
5
Untung manajer Google lebih beralasan daripada bos Anda ... Bayangkan betapa lambatnya jika mengembalikan jumlah hasil pencarian yang tepat untuk setiap kueri Anda alih-alih bertahan pada angka taksiran.
Denis de Bernardy
Setidaknya Anda berempati dengan saya. Bagaimana dengan satu-satunya solusi Oracle? Itu akan mengurangi masalah saya sampai batas tertentu. Saat ini pelanggan menggunakan Oracle; jadi jika saya menemukan solusi hanya untuk Oracle, itu akan berlaku [untuk saat ini]. :)
Swaranga Sarma
6
"Ya Denis, perhitungan yang tepat diperlukan. :(" - yah saya hanya bisa berspekulasi. Apakah proses pemeliharaan db mengetahui bahwa ada 42.123.876 baris di tabel A dan kemudian membuat 42.123.876 baris kosong di tabel B, dan kemudian loop melalui tabel A dan perbarui baris pada tabel B ...? Atau lebih gila dari itu? ;-)
Tony Andrews
1
Transaksi 2 tidak dapat dimulai sebelum transaksi 1 dilakukan. Tanpa pembaruan "tabel hitungan", banyak transaksi pembaruan dapat berjalan secara paralel. Dengan "tabel perhitungan", setiap transaksi harus "mendapatkan tiket" untuk memperbarui perhitungannya. Jadi transaksi mulai mengantri di mesin tiket (penjadwal memutuskan siapa yang akan menjadi yang berikutnya untuk mendapatkan kunci di tabel perhitungan).
Erwin Smout
10

Apakah ada cara yang lebih baik untuk mendapatkan hitungan EXACT dari jumlah baris tabel?

Untuk menjawab pertanyaan Anda secara sederhana, Tidak .

Jika Anda memerlukan cara independen DBMS untuk melakukan ini, cara tercepat akan selalu:

SELECT COUNT(*) FROM TableName

Beberapa vendor DBMS mungkin memiliki cara yang lebih cepat yang hanya akan berfungsi untuk sistem mereka. Beberapa opsi ini sudah diposting dalam jawaban lain.

COUNT(*) harus dioptimalkan oleh DBMS (setidaknya DB layak PROD), jadi jangan mencoba untuk memotong optimasi mereka.

Di samping catatan:
Saya yakin banyak pertanyaan Anda yang lain juga membutuhkan waktu lama untuk diselesaikan karena ukuran meja Anda. Setiap masalah kinerja mungkin harus diatasi dengan memikirkan desain skema Anda dengan cepat. Saya menyadari Anda mengatakan bahwa itu bukan opsi untuk berubah, tetapi mungkin ternyata bahwa kueri 10+ menit juga bukan opsi. 3 NF tidak selalu pendekatan yang terbaik ketika Anda membutuhkan kecepatan, dan kadang-kadang data dapat dipartisi dalam beberapa tabel jika catatan tidak memiliki disimpan bersama-sama. Sesuatu untuk dipikirkan...

Jesse Webb
sumber
10

Saya mendapatkan skrip ini dari pertanyaan / jawaban StackOverflow lain:

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

Meja saya memiliki 500 juta catatan dan pengembalian di atas dalam waktu kurang dari 1 ms. Sementara itu,

SELECT COUNT(id) FROM MyTable

membutuhkan 39 menit penuh, 52 detik!

Mereka menghasilkan jumlah baris yang sama persis (dalam kasus saya, tepatnya 519326012).

Saya tidak tahu apakah itu akan selalu terjadi.

JakeJ
sumber
Bisakah Anda menambahkan parameter untuk mendapatkan jumlah baris dengan permintaan ini? Contoh: Pilih COUNT (1) DARI TABLENAME WHERE ColumnFiled = '1' Dengan kueri Anda?
VnDevil
Itu adalah hitungan - jumlah baris (catatan) adalah "hitungan" dalam kasus ini. "500 juta catatan" adalah angka perkiraan, dan "519326012" adalah jumlah baris yang tepat, atau jumlah. Baris = catatan = jumlah.
JakeJ
9

Anda dapat mencoba sp_spaceused ini (Transact-SQL)

Menampilkan jumlah baris, ruang disk yang dicadangkan, dan ruang disk yang digunakan oleh tabel, tampilan yang diindeks, atau antrian Broker Layanan di database saat ini, atau menampilkan ruang disk yang dipesan dan digunakan oleh seluruh database.

selai
sumber
Tidak akan sp_spaceused memberi saya jumlah yang diperkirakan?
Swaranga Sarma
1
FYI: Ini menggunakan sys.dm_db_partition_stats secara internal
gbn
6

Jika edisi SQL Server 2005/2008, Anda bisa menggunakan DMV untuk menghitung jumlah baris dalam tabel:

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

Untuk mesin database SQL Server 2000, sysindex akan berfungsi, tetapi sangat disarankan untuk tidak menggunakannya dalam edisi SQL Server mendatang karena dapat dihapus dalam waktu dekat.

Contoh kode diambil dari: Cara Mendapatkan Hitungan Baris Tabel Dengan Cepat Dan Tanpa Rasa Sakit

Alireza Maddah
sumber
Ini perkiraan tidak tepat : lihat jawaban saya tolong
gbn
Apakah Anda tahu contoh di mana ini tidak akurat? AFAIK, itu tidak tergantung pada statistik yang diperbarui.
Alireza Maddah
5

saya menggunakan

select /*+ parallel(a) */  count(1) from table_name a;
Mainsh S
sumber
pilih / * + parallel (a) * / count (1) dari table_name a
Mainsh S
5

Saya sama sekali tidak ahli seperti orang lain yang telah menjawab tetapi saya memiliki masalah dengan prosedur yang saya gunakan untuk memilih baris acak dari tabel (tidak terlalu relevan) tetapi saya perlu mengetahui jumlah baris dalam tabel referensi saya untuk menghitung indeks acak. Menggunakan Hitungan tradisional (*) atau Hitungan (1) berfungsi tetapi saya kadang-kadang mendapatkan hingga 2 detik untuk menjalankan kueri. Jadi sebagai gantinya (untuk meja saya bernama 'tbl_HighOrder') saya menggunakan:

Declare @max int

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

Ini berfungsi dengan baik dan waktu kueri di Management Studio adalah nol.

hujan john
sumber
1
FWIW, Anda harus menyebutkan vendor database WHICH yang Anda gunakan; Saya pikir pernyataan itu akan sedikit berbeda tergantung pada vendor.
ToolmakerSteve
5

Nah, terlambat 5 tahun dan tidak yakin apakah itu membantu:

Saya mencoba menghitung tidak. baris dalam tabel SQL Server menggunakan MS SQL Server Management Studio dan mengalami beberapa kesalahan overflow, maka saya menggunakan di bawah ini:

pilih count_big (1) DARI [dbname]. [dbo]. [FactSampleValue];

Hasil :

24296650578 baris

Kaliyug Antagonist
sumber
5

Saya menemukan baik artikel ini SQL Server-CARA-TO: cepat mengambil jumlah baris akurat untuk meja dari martijnh1yang memberikan rekap yang baik untuk setiap skenario.

Saya perlu ini diperluas di mana saya perlu memberikan hitungan berdasarkan kondisi tertentu dan ketika saya mencari bagian ini, saya akan memperbarui jawaban ini lebih lanjut.

Sementara itu, berikut detail dari artikel:

Metode 1:

Pertanyaan:

SELECT COUNT(*) FROM Transactions 

Komentar:

Melakukan pemindaian tabel penuh. Lambat di meja besar.

Metode 2:

Pertanyaan:

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

Komentar:

Cara cepat untuk mengambil jumlah baris. Tergantung pada statistik dan tidak akurat.

Jalankan DBCC UPDATEUSAGE (Database) DENGAN COUNT_ROWS, yang bisa memakan waktu cukup lama untuk tabel besar.

Metode 3:

Pertanyaan:

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

Komentar:

Cara studio manajemen SQL menghitung baris (lihat properti tabel, penyimpanan, jumlah baris). Sangat cepat, tetapi masih merupakan perkiraan jumlah baris.

Metode 4:

Pertanyaan:

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

Komentar:

Operasi cepat (walaupun tidak secepat metode 2) dan sama pentingnya, andal.

Thierry
sumber
Terima kasih! Tip yang sangat berguna. Saya tidak memiliki izin untuk melihat tabel sistem sehingga metode 4 bukan saya. Namun metode 3 cukup baik.
Nicholas Humphrey
3

Saya tidak berpikir ada solusi umum yang selalu tercepat: beberapa RDBMS / versi memiliki optimasi khusus untuk SELECT COUNT(*)itu menggunakan opsi lebih cepat sementara yang lain hanya pemindaian tabel. Anda harus pergi ke situs dokumentasi / dukungan untuk set kedua, yang mungkin akan membutuhkan beberapa permintaan khusus untuk ditulis, biasanya yang menyentuh indeks dengan beberapa cara.

EDIT:

Berikut ini pemikiran yang mungkin berhasil, tergantung pada skema dan distribusi data Anda: apakah Anda memiliki kolom yang diindeks yang mereferensikan nilai yang meningkat, ID peningkatan numerik, katakanlah, atau bahkan cap waktu atau tanggal? Kemudian, dengan anggapan penghapusan tidak terjadi, seharusnya dimungkinkan untuk menyimpan penghitungan hingga beberapa nilai terkini (tanggal kemarin, nilai ID tertinggi di beberapa titik sampel terbaru) dan menambahkan penghitungan di luar itu, yang seharusnya diselesaikan dengan sangat cepat dalam indeks . Sangat tergantung pada nilai dan indeks, tentu saja, tetapi berlaku untuk hampir semua versi DBMS apa pun.

Mike Woodhouse
sumber
Saya akan sangat berharap bahwa DBMS yang layak akan menggunakan indeks untuk SELECT COUNT(*). Bahkan MySQL ternyata melakukannya ....
sleske
dengan asumsi penghapusan tidak terjadi - serius ?? ; p
ToolmakerSteve
3

Saya terlambat untuk pertanyaan ini, tetapi di sini adalah apa yang dapat Anda lakukan dengan MySQL (karena saya menggunakan MySQL). Saya membagikan pengamatan saya di sini:

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

Hasil
Baris Hitung: 508534
Output konsol: Baris yang terpengaruh: 0 Baris yang ditemukan: 1 Peringatan: 0 Durasi untuk 1 permintaan: 0,125 dtk.
Butuh beberapa saat untuk tabel dengan jumlah baris yang besar, tetapi jumlah baris sangat tepat.

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

Hasil
Jumlah baris: 511235
Output konsol: Baris yang terpengaruh: 0 Baris yang ditemukan: 1 Peringatan: 0 Durasi untuk 1 permintaan: 0,250 dt Ringkasan: Jumlah baris tidak tepat.

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

Hasil
Jumlah baris: 507806
Output konsol: Baris yang terpengaruh: 0 Baris yang ditemukan: 48 Peringatan: 0 Durasi untuk 1 permintaan: 1,701 dtk.
Hitungan baris tidak tepat.

Saya bukan ahli MySQL atau basis data, tetapi saya telah menemukan bahwa untuk tabel yang sangat besar, Anda dapat menggunakan opsi 2 atau 3 dan mendapatkan 'ide yang adil' tentang berapa banyak baris yang ada.

Saya perlu mendapatkan jumlah baris ini untuk menampilkan beberapa statistik di UI. Dengan pertanyaan di atas, saya tahu bahwa total baris lebih dari 500.000, jadi saya menghasilkan statistik seperti "Lebih dari 500.000 baris" tanpa menunjukkan jumlah baris yang tepat.

Mungkin saya belum benar-benar menjawab pertanyaan OP, tetapi saya membagikan apa yang saya lakukan dalam situasi di mana statistik seperti itu diperlukan. Dalam kasus saya, menampilkan baris perkiraan dapat diterima dan hal di atas berfungsi untuk saya.

sunitkatkar
sumber
2

Bukan solusi DBMS-agnostik, tetapi setidaknya kode klien Anda tidak akan melihat perbedaannya ...

Buat tabel T lain dengan hanya satu baris dan satu bidang bilangan bulat N 1 , dan buat INSERT TRIGGER yang baru saja dijalankan:

UPDATE T SET N = N + 1

Juga buat DELETE TRIGGER yang mengeksekusi:

UPDATE T SET N = N - 1

DBMS yang bernilai garam akan menjamin atomicity operasi di atas 2 , dan N akan berisi jumlah baris yang akurat setiap saat, yang kemudian super cepat didapat hanya dengan:

SELECT N FROM T

Meskipun pemicu adalah spesifik DBMS, memilih dari T tidak dan kode klien Anda tidak perlu berubah untuk setiap DBMS yang didukung.

Namun, ini dapat memiliki beberapa masalah skalabilitas jika tabel INSERT atau DELETE-intensif, terutama jika Anda tidak KOMIT segera setelah INSERT / HAPUS.


1 Nama-nama ini hanya placeholder - gunakan sesuatu yang lebih bermakna dalam produksi.

2 Yaitu N tidak dapat diubah dengan transaksi bersamaan antara membaca dan menulis ke N, selama membaca dan menulis dilakukan dalam pernyataan SQL tunggal.

Branko Dimitrijevic
sumber
2

Jawaban yang benar-benar gila, tetapi jika Anda memiliki semacam pengaturan sistem replikasi (untuk sistem dengan satu miliar baris, saya harap Anda melakukannya), Anda dapat menggunakan estimator kasar (seperti MAX(pk)), bagi nilai itu dengan jumlah budak Anda punya, jalankan beberapa kueri secara paralel.

Untuk sebagian besar, Anda akan mempartisi kueri di seluruh budak berdasarkan kunci terbaik (atau kunci utama saya kira), sedemikian rupa (kita akan menggunakan 250000000 sebagai Baris / Budak kami):

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

Tetapi Anda hanya perlu SQL. Benar-benar payah. Ok, jadi anggaplah Anda seorang sadomasochist. Pada master (atau slave terdekat) Anda kemungkinan besar perlu membuat tabel untuk ini:

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

Jadi, alih-alih hanya menjalankan seleksi di slave Anda, Anda harus melakukan insert, seperti ini:

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

Anda mungkin mengalami masalah dengan budak yang menulis ke meja di master. Anda mungkin perlu mendapatkan lebih banyak sadis- Maksudku, kreatif:

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

Anda pada akhirnya harus memiliki budak yang ada di jalur terakhir yang dilalui oleh grafik replikasi, relatif terhadap budak pertama. Budak itu sekarang harus memiliki semua nilai counter lainnya, dan harus memiliki nilai sendiri. Tetapi pada saat Anda selesai, mungkin ada baris yang ditambahkan, jadi Anda harus memasukkan satu lagi untuk mengkompensasi pk max yang tercatat di counter_table Anda dan pk maks saat ini.

Pada titik itu, Anda harus melakukan fungsi agregat untuk mencari tahu apa total barisnya, tetapi itu lebih mudah karena Anda akan menjalankannya paling banyak pada "jumlah budak yang Anda miliki dan ubah" baris.

Jika Anda berada dalam situasi di mana Anda memiliki tabel terpisah di slave, Anda bisa UNIONmendapatkan semua baris yang Anda butuhkan.

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

Atau Anda tahu, menjadi sedikit lebih tidak waras dan memigrasikan data Anda ke sistem pemrosesan terdistribusi, atau mungkin menggunakan solusi Data Warehousing (yang akan memberi Anda data yang luar biasa juga di masa depan).

Perhatikan, ini tergantung pada seberapa baik replikasi Anda diatur. Karena bottleneck utama kemungkinan besar adalah penyimpanan yang persisten, jika Anda memiliki penyimpanan yang kasar atau penyimpanan data yang terpisah dengan kebisingan tetangga yang tinggi, ini mungkin akan membuat Anda lebih lambat daripada hanya menunggu satu pun.SELECT COUNT(*) ...

Tetapi jika Anda memiliki replikasi yang baik, maka peningkatan kecepatan Anda harus langsung terkait dengan jumlah atau budak. Faktanya, jika hanya perlu 10 menit untuk menjalankan kueri penghitungan, dan Anda memiliki 8 budak, Anda akan memotong waktu Anda menjadi kurang dari beberapa menit. Mungkin satu jam untuk menyelesaikan detail dari solusi ini.

Tentu saja, Anda tidak akan pernah benar-benar mendapatkan jawaban yang luar biasa akurat karena penyelesaian terdistribusi ini memperkenalkan sedikit waktu di mana baris dapat dihapus dan dimasukkan, tetapi Anda dapat mencoba untuk mendapatkan kunci terdistribusi dari baris pada contoh yang sama dan mendapatkan penghitungan yang tepat dari baris dalam tabel untuk saat tertentu dalam waktu.

Sebenarnya, ini sepertinya tidak mungkin, karena pada dasarnya Anda terjebak dengan solusi SQL-only, dan saya tidak berpikir Anda menyediakan mekanisme untuk menjalankan kueri yang beling dan terkunci di banyak budak, secara instan. Mungkin jika Anda memiliki kendali atas file log replikasi ... yang berarti Anda benar-benar akan memutar budak untuk tujuan ini, yang tidak diragukan lagi lebih lambat daripada hanya menjalankan kueri hitungan pada satu mesin saja.

Jadi ada dua sen 2013 saya.

Yangmun Choi
sumber
2

Jika pemicu sisipan terlalu mahal untuk digunakan, tetapi pemicu penghapusan bisa dilakukan, dan ada peningkatan otomatisid , kemudian setelah menghitung seluruh tabel satu kali, dan mengingat hitungan sebagai last-countdan last-counted-id,

maka setiap hari hanya perlu menghitung untuk id> last-counted-id, menambahkannya ke last-count, dan menyimpan yang baru last-counted-id.

Pemicu hapus akan mengurangi jumlah-terakhir, jika id dari catatan yang dihapus <= id-terakhir-dihitung.

ToolmakerSteve
sumber
.. maaf tidak punya waktu untuk menunjukkan SQL yang akan digunakan (SQL saya berkarat). Jika ada yang ingin mengedit jawaban saya untuk menambahkan SQL, itu akan bagus!
ToolmakerSteve
1

Jika Anda memiliki struktur tabel tipikal dengan kolom kunci primer yang bertambah secara otomatis di mana baris tidak pernah dihapus, berikut ini akan menjadi cara tercepat untuk menentukan jumlah rekaman dan harus bekerja dengan cara yang sama di sebagian besar basis data yang sesuai dengan ANSI:

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

Saya bekerja dengan tabel MS SQL yang berisi miliaran baris yang memerlukan waktu respons sub-detik untuk data, termasuk jumlah rekaman. SELECT COUNT (*) yang serupa akan membutuhkan waktu beberapa menit untuk diproses dengan perbandingan.

KevinS
sumber
1
Tidak sepenuhnya benar - bagaimana jika INSERTtransaksi dibatalkan? Nilai kunci primer itu akan tidak ada, sehingga jumlah rekaman aktual akan menjadi kurang dari nilai maksimum.
Sir Crispalot
Bisa jadi ada celah secara berurutan. Biasanya merupakan hasil dari rollback.
Osa E
Sebenarnya, ada modifikasi dari jawaban ini yang mungkin secara signifikan lebih cepat daripada count(*), jika vendor database belum cukup dioptimalkan count(*): Setiap hari melacak indeks-otomatis terakhir dan jumlah yang sesuai, kemudian meminta hitungan catatan melewati itu. Dapat juga menangani deletejika menambahkan pemicu pada delete yang menurunkan total sebelumnya , jika record id dihapus <= indeks otomatis terakhir.
ToolmakerSteve
1

Untuk server Sql coba ini

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 
Abhishek B Patel
sumber
0

pilih baris dari sysindexes di mana id = Object_ID ('TableName') dan indid <2

Enzero
sumber
0

Letakkan indeks pada beberapa kolom. Itu harus memungkinkan pengoptimal untuk melakukan pemindaian penuh blok indeks, bukan pemindaian penuh tabel. Itu akan mengurangi biaya IO Anda. Lihatlah rencana eksekusi sebelum dan sesudah. Kemudian mengukur waktu jam dinding dua arah.

EvilTeach
sumber
Jika sebuah tabel memiliki miliaran baris tanpa indeks pada kolom apa pun, maka akan ada masalah kinerja luas, jauh melebihi kebutuhan yang dinyatakan dalam pertanyaan asli .. tapi bagus yang Anda sebutkan (asumsikan tidak ada!) :)
ToolmakerSteve
0

Jika Anda menggunakan Oracle, bagaimana dengan ini (dengan asumsi statistik tabel diperbarui):

select <TABLE_NAME>, num_rows, last_analyzed from user_tables

last_analyzed akan menunjukkan waktu ketika statistik terakhir dikumpulkan.

Diogo Ferreira
sumber
0

Dengan PostgreSQL:

SELECT reltuples AS approximate_row_count FROM pg_class WHERE relname = 'table_name'
Dorian
sumber
-1

Di SQL server 2016, saya hanya bisa memeriksa properti tabel dan kemudian pilih tab 'Storage' - ini memberi saya jumlah baris, ruang disk yang digunakan oleh tabel, ruang indeks yang digunakan dll.

SenSei
sumber
Dia mencari seorang database vendor independent solution. Juga ini membutuhkan GUI dan tidak bisa otomatis. Juga tidak lebih cepat dari COUNT (*)
Frieder
-3

Mungkin agak terlambat tetapi ini mungkin membantu orang lain untuk MSSQL

; DENGAN RecordCount AS (SELECT ROW_NUMBER () LEBIH (ORDER DENGAN COLUMN_NAME) SEBAGAI [RowNumber] DARI TABLE_NAME) SELECT MAX (RowNumber) DARI RecordCount

Justus Swanevelder
sumber
Ini secara signifikan LEBIH BURUK dari COUNT (), kecuali kami SANGAT beruntung dan pengoptimal berhasil mengoptimalkannya menjadi COUNT () - mengapa meminta SORT pada kolom acak?!?
dsz