MySQL: Cara tercepat untuk menghitung jumlah baris

117

Cara mana untuk menghitung jumlah baris yang harus lebih cepat di MySQL?

Ini:

SELECT COUNT(*) FROM ... WHERE ...

Atau, alternatifnya:

SELECT 1 FROM ... WHERE ...

// and then count the results with a built-in function, e.g. in PHP mysql_num_rows()

Orang akan berpikir bahwa metode pertama harus lebih cepat, karena ini jelas merupakan wilayah database dan mesin database harus lebih cepat daripada orang lain saat menentukan hal-hal seperti ini secara internal.

Franz
sumber
1
Oh, saya menemukan pertanyaan serupa ( stackoverflow.com/questions/1855226/… ). Tapi kemudian, saya menggunakan SELECT 1dan tidak SELECT *. Apakah ada bedanya?
Franz
saya tidak tahu, tetapi mungkin kedua jawaban ini identik - pengoptimal kueri mysql dapat melakukan hal yang sama pada masing-masing. yang mengatakan yang pertama kurang ambigu dibandingkan yang terakhir. mengapa Anda tidak menulis beberapa tolok ukur dan mengujinya?
Jesse Cohen
Uhm, anggap saja saya mencoba meningkatkan visibilitas mesin pencari SO dengan mengajukan pertanyaan serupa dengan kata yang berbeda;)
Franz
1
Perbedaannya adalah jumlah data yang dikirim ke sisi PHP. Semakin banyak kolom yang Anda miliki, semakin lambat SELECT * relatif terhadap SELECT 1, karena semua kolom diambil alih-alih hanya nomor 1. Saat Anda menjalankan mysql_query(), misalnya, seluruh rangkaian hasil dikirim ke PHP dari MySQL, apa pun yang Anda lakukan. lakukan dengan data itu.
toon81
Mengajukan pertanyaan seperti ini adalah cara yang bagus untuk mendapatkan wawasan atau ide-ide baru, tetapi pada akhirnya jika Anda benar-benar memiliki skenario tertentu di mana Anda menginginkan kecepatan lebih, Anda harus menjalankan tes untuk melihat mana yang tercepat.
still_dreaming_1

Jawaban:

125

Ketika Anda COUNT(*)mengambil indeks kolom hitung, jadi itu akan menjadi hasil terbaik. Mysql dengan mesin MyISAM sebenarnya menyimpan jumlah baris, tidak menghitung semua baris setiap kali Anda mencoba menghitung semua baris. (berdasarkan kolom kunci utama)

Menggunakan PHP untuk menghitung baris tidak terlalu pintar, karena Anda harus mengirim data dari mysql ke php. Mengapa melakukannya ketika Anda dapat mencapai hal yang sama di sisi mysql?

Jika COUNT(*)lambat, Anda harus menjalankan EXPLAINkueri, dan memeriksa apakah indeks benar-benar digunakan, dan di mana mereka harus ditambahkan.


Berikut ini bukan cara tercepat , tetapi ada kasus, di mana COUNT(*)tidak benar-benar cocok - ketika Anda mulai mengelompokkan hasil, Anda dapat mengalami masalah, di mana COUNTtidak benar-benar menghitung semua baris.

Solusinya adalah SQL_CALC_FOUND_ROWS. Ini biasanya digunakan saat Anda memilih baris tetapi masih perlu mengetahui jumlah baris total (misalnya, untuk paging). Saat Anda memilih baris data, cukup tambahkan SQL_CALC_FOUND_ROWSkata kunci setelah PILIH:

SELECT SQL_CALC_FOUND_ROWS [needed fields or *] FROM table LIMIT 20 OFFSET 0;

Setelah Anda memilih baris yang dibutuhkan, Anda bisa mendapatkan hitungan dengan kueri tunggal ini:

SELECT FOUND_ROWS();

FOUND_ROWS() harus dipanggil segera setelah kueri pemilihan data.


Kesimpulannya, semuanya sebenarnya tergantung pada berapa banyak entri yang Anda miliki dan apa yang ada di pernyataan WHERE. Anda harus benar-benar memperhatikan bagaimana indeks digunakan, ketika ada banyak baris (puluhan ribu, jutaan, dan lebih tinggi).

Mārtiņš Briedis
sumber
14
Koreksi: MyISAMmenyimpan jumlah baris. Mesin penyimpanan lain seperti InnoDB tidak menyimpan jumlah baris dan akan menghitung semua baris setiap saat .
The Scrum Meister
1
Apakah Anda tahu mana yang paling cepat ketika Anda hanya ingin mengetahui apakah ada baris: SELECT 1 FROM ... LIMIT 1atau SELECT COUNT(*) FROM ...?
Franz
1
Mungkin berguna untuk dicatat bahwa jika Anda tetap memerlukan data dan hanya ingin menghitung pagination / etc. lebih efisien untuk mendapatkan data kemudian menghitung baris dalam program Anda.
Tyzoid
6
Tidak relevan apakah jumlah baris penyimpanan mesin. Pertanyaannya dengan jelas menyatakan ada WHEREklausul.
Álvaro González
1
@Franz SELECT COUNT(*) FROM ...dapat memakan banyak waktu, tergantung pada apa yang harus dipindai (mis. Tabel yang sangat besar atau indeks jutaan / miliaran / triliunan baris). SELECT 1 FROM ... LIMIT 1segera kembali karena Anda membatasinya ke baris pertama.
jbo5112
59

Setelah berbicara dengan rekan satu tim saya, Ricardo memberi tahu kami bahwa cara yang lebih cepat adalah:

show table status like '<TABLE NAME>' \G

Tetapi Anda harus ingat bahwa hasilnya mungkin tidak tepat.

Anda juga dapat menggunakannya dari baris perintah:

$ mysqlshow --status <DATABASE> <TABLE NAME>

Informasi lebih lanjut: http://dev.mysql.com/doc/refman/5.7/en/show-table-status.html

Dan Anda bisa menemukan pembahasan lengkapnya di mysqlperformanceblog

MagMax
sumber
2
Untuk InnoDB, ini adalah perkiraan.
Martin Tournoij
2
Ini bagus untuk mengetahui ketika membutuhkan gambaran kasar tentang jumlah baris dalam tabel yang sangat besar di mana hitungan (*) dapat memakan waktu berjam-jam!
Mark Hansen
Ini menyelamatkan saya dari mencabut semua rambut saya. COUNT (*) membutuhkan waktu lama untuk menghitung semua 33 juta lebih baris dalam database saya. Bagaimanapun, saya hanya ingin tahu apakah fungsi baris hapus paralel saya berfungsi atau tidak. Saya tidak butuh nomor pasti.
joemar.ct
1
+1 Menggunakan status tabel alih-alih "JUMLAH (*)" seharusnya jawaban yang benar untuk pertanyaan ini seperti tentang "tercepat" bukan "akurasi".
lepe
2
Menggunakan SHOW TABLE STATUS(atau yang setara SELECTdalam information_schema) itu cepat, tetapi tidak menangani WHEREklausa. Ini tepat untuk MyISAM, tetapi tidak tepat (terkadang dengan faktor 2) untuk InnoDB.
Rick James
29

Pertanyaan bagus, jawaban bagus. Inilah cara cepat untuk menggemakan hasil jika ada yang membaca halaman ini dan melewatkan bagian itu:

$counter = mysql_query("SELECT COUNT(*) AS id FROM table");
$num = mysql_fetch_array($counter);
$count = $num["id"];
echo("$count");
Dan Horvat
sumber
5
mysql_query adalah fungsi usang pada PHP 5.5.0.
Omar Tariq
8
Mengapa tidak as count? idmembingungkan pada pandangan pertama.
Orkhan Alikhanov
Tidak menjawab pertanyaan
mentalic
17

Kueri ini (yang mirip dengan bayuah yang diposting ) menunjukkan ringkasan yang bagus dari semua tabel yang dihitung di dalam database: (versi sederhana dari prosedur tersimpan oleh Ivan Cachicatari yang sangat saya rekomendasikan).

SELECT TABLE_NAME AS 'Table Name', TABLE_ROWS AS 'Rows' FROM information_schema.TABLES WHERE TABLES.TABLE_SCHEMA = '`YOURDBNAME`' AND TABLES.TABLE_TYPE = 'BASE TABLE'; 

Contoh:

+-----------------+---------+
| Table Name      | Rows    |
+-----------------+---------+
| some_table      |   10278 |
| other_table     |     995 |
lepe
sumber
Ini memberi saya hasil. Tetapi hasil dari hitungan (1) dan yang ini berbeda. Cara ini memberikan jumlah yang lebih sedikit daripada kueri hitungan. Ada pemikiran?
Ayyappan Sekar
3
Sekedar catatan untuk para pembaca. Metode ini sangat cepat tetapi hanya berlaku jika Anda dapat bekerja dengan perkiraan jumlah baris karena nilai yang disimpan information_schematidak sama dengan yang dikembalikan oleh SELECT count(*) FROMjika InnoDB digunakan. Jika Anda membutuhkan nilai yang ketat maka perlu diingat bahwa metode ini memberikan nilai yang ketat hanya dengan tabel MyISAM. Dengan InnoDB jumlah baris merupakan perkiraan kasar.
Bartosz Firyn
13

Saya selalu mengerti bahwa di bawah ini akan memberi saya waktu respons tercepat.

SELECT COUNT(1) FROM ... WHERE ...
adarshr
sumber
1
Bukankah PILIH 1 DARI ... MANA ... menjadi lebih cepat?
patrick
3
@patrick - SELECT 1 ...akan kembali sebagai banyak baris sebagai WHEREdan LIMITmeminta, dan mereka semua akan "1".
Rick James
1
show table status like '<TABLE NAME>' Ini akan jauh lebih cepat.
dalam
@ dalam - tetapi tidak relevan jika Anda memiliki WHEREklausul. Dan, untuk InnoDB, itu hanya perkiraan.
Rick James
@RickJames ya benar!
dalam
6

Jika Anda perlu menghitung seluruh rangkaian hasil, Anda dapat mengambil pendekatan berikut:

SELECT SQL_CALC_FOUND_ROWS * FROM table_name LIMIT 5;
SELECT FOUND_ROWS();

Ini biasanya tidak lebih cepat daripada menggunakan COUNTmeskipun orang mungkin berpikir sebaliknya adalah kasusnya karena melakukan perhitungan secara internal dan tidak mengirim data kembali ke pengguna sehingga peningkatan kinerja dicurigai.

Melakukan dua kueri ini bagus untuk penomoran halaman untuk mendapatkan total tetapi tidak secara khusus untuk menggunakan WHEREklausa.

Alex Rashkov
sumber
Intersting. Apakah itu berfungsi di sistem database yang paling umum? MySQL, Postgres, SQLite ...?
Franz
4
Ini sebenarnya seringkali tidak lebih cepat daripada menggunakan COUNT (*) sama sekali. Lihat stackoverflow.com/questions/186588/…
toon81
2
Anda harus SANGAT berhati-hati saat menggunakan fungsi ini. Penggunaannya yang sembrono pernah membuat seluruh lingkungan produksi kami terhenti. Ini SANGAT intensif sumber daya, jadi gunakan dengan hati-hati.
Janis Peisenieks
6

Saya melakukan beberapa tolok ukur untuk membandingkan waktu eksekusi COUNT(*)vs COUNT(id)(id adalah kunci utama dari tabel - diindeks).

Jumlah percobaan: 10 * 1000 kueri

Hasil: COUNT(*)lebih cepat 7%

LIHAT GRAFIK: benchmarkgraph

Saran saya adalah menggunakan: SELECT COUNT(*) FROM table

SamuelCarreira
sumber
1
FYI ada juga cara menghitung yang umum COUNT(1), pasti menarik melihat beberapa benchmark disana ...
Sliq
4

Coba ini:

SELECT
    table_rows "Rows Count"
FROM
    information_schema.tables
WHERE
    table_name="Table_Name"
AND
    table_schema="Database_Name";
bayuah
sumber
@lepe maafkan aku. Maksud saya, alangkah baiknya jika seseorang yang melakukan downvoting memberikan penjelasan mengapa dia melakukan itu, sehingga semua orang bisa belajar sesuatu tentangnya.
bayuah
1
Ini akan memberi Anda jawaban perkiraan dengan cepat. Jika Anda membutuhkan jawaban yang tepat, Anda perlu melakukan select count(*) from table_nameatau sesuatu yang lain. dba.stackexchange.com/questions/151769/…
Programster
@Programster Terima kasih. Ini lebih baik daripada meninggalkanku dalam kegelapan selama hampir setahun.
bayuah
1
@bayuah Saya tidak yakin apa yang Anda maksud dengan komentar terakhir Anda. Saya hanya dapat berasumsi bahwa Anda mengira saya adalah orang yang menolak jawaban Anda, padahal bukan.
Programster
1
@Programster Tidak, maaf, saya tidak bermaksud begitu. Maksud saya terima kasih atas penjelasan Anda, jadi saya bisa menebak apa yang mungkin dipikirkan Downvoter ketika dia melakukan itu.
bayuah
3

Mungkin Anda mungkin ingin mempertimbangkan untuk melakukan a SELECT max(Id) - min(Id) + 1. Ini hanya akan berfungsi jika Id Anda berurutan dan baris tidak dihapus. Namun itu sangat cepat.

sky-dev
sumber
3
Hati-hati: server terkadang menggunakan nilai kenaikan otomatis> 1 (untuk alasan cadangan), jadi solusi ini bagus tetapi Anda harus memeriksa konfigurasi DB Anda terlebih dahulu.
Alex
1

EXPLAIN SELECT id FROM ....melakukan trik untuk saya. dan saya bisa melihat jumlah baris di bawah rowskolom hasilnya.

ssrp
sumber
0

Saya menangani tabel untuk Pemerintah Jerman dengan kadang-kadang 60 juta catatan.

Dan kami perlu mengetahui berkali-kali jumlah baris.

Jadi kami programmer database memutuskan bahwa dalam setiap tabel adalah record satu selalu record di mana jumlah record disimpan. Kami memperbarui nomor ini, bergantung pada baris INSERT atau DELETE.

Kami mencoba semua cara lain. Sejauh ini cara tercepat.

Scoobeedo Cool
sumber
1
dan apa detail cara Anda memperbarui baris itu? Yang berarti meskipun desain yang salah ke meja, di mana semua baris akan membutuhkan int yang terbuang untuk ikut serta dalam perjalanan.
Drew
5
Ya, itu benar-benar bodoh haha. Dengan setiap kueri, Anda harus mengabaikan baris pertama. Saya hanya akan membuat tabel total dan mengisinya berdasarkan pemicu. Tabel pengguna di sisipkan, perbarui tabel total. Tabel pengguna di hapus, perbarui tabel total.
HTMLGuy
-1

Pernyataan hitungan (*) dengan kondisi di mana pada kunci utama mengembalikan jumlah baris jauh lebih cepat untuk saya menghindari pemindaian tabel penuh.

SELECT COUNT(*) FROM ... WHERE <PRIMARY_KEY> IS NOT NULL;

Ini jauh lebih cepat bagi saya daripada

SELECT COUNT(*) FROM ...
ayakout
sumber