MySQL - Perbedaan antara menggunakan count (*) dan information_schema.tables untuk menghitung baris


16

Saya ingin cara cepat untuk menghitung jumlah baris di meja saya yang memiliki beberapa juta baris. Saya menemukan posting " MySQL: Cara tercepat untuk menghitung jumlah baris " di Stack Overflow, yang sepertinya akan menyelesaikan masalah saya. Bayuah memberikan jawaban ini:

SELECT
    table_rows "Rows Count"
FROM
    information_schema.tables
WHERE
    table_name="Table_Name"
AND
    table_schema="Database_Name";

Yang saya sukai karena itu terlihat seperti pencarian bukan pemindaian, jadi harus cepat, tapi saya memutuskan untuk mengujinya

SELECT COUNT(*) FROM table 

untuk melihat seberapa besar perbedaan kinerja yang ada.

Sayangnya saya mendapat jawaban berbeda seperti yang ditunjukkan di bawah ini:

masukkan deskripsi gambar di sini

Pertanyaan

Mengapa jawabannya berbeda sekitar 2 juta baris? Saya menebak permintaan yang melakukan pemindaian tabel penuh adalah angka yang lebih akurat, tetapi apakah ada cara saya bisa mendapatkan nomor yang benar tanpa harus menjalankan permintaan lambat ini?


Saya berlari ANALYZE TABLE data_302, yang selesai dalam 0,05 detik. Ketika saya menjalankan kueri lagi, saya sekarang mendapatkan hasil yang jauh lebih dekat dari 34384599 baris, tetapi itu masih tidak sama select count(*)dengan 34906061 baris. Apakah tabel analisis segera kembali dan diproses di latar belakang? Saya merasa layak menyebutkan ini adalah database pengujian dan saat ini sedang tidak ditulis.

Tidak ada yang akan peduli jika itu hanya kasus memberitahu seseorang seberapa besar sebuah tabel, tapi saya ingin meneruskan jumlah baris ke sedikit kode yang akan menggunakan angka itu untuk membuat kueri asinkron yang "berukuran sama" untuk menanyakan database. secara paralel, mirip dengan metode yang ditunjukkan dalam Meningkatkan kinerja permintaan lambat dengan eksekusi permintaan paralel oleh Alexander Rubin. Karena itu, saya hanya akan mendapatkan id tertinggi SELECT id from table_name order by id DESC limit 1dan berharap meja saya tidak terlalu terfragmentasi.

Jawaban:


23

Ada berbagai cara untuk "menghitung" baris dalam sebuah tabel. Apa yang terbaik tergantung pada persyaratan (keakuratan penghitungan, seberapa sering dilakukan, apakah kita perlu menghitung seluruh tabel atau dengan variabel wheredan group byklausa, dll.)

  • a) cara normal. Hitung saja mereka.

    select count(*) as table_rows from table_name ; 

    Akurasi : Hitungan 100% akurat pada saat kueri dijalankan.
    Efisiensi : Tidak bagus untuk meja besar. (untuk tabel MyISAM sangat cepat tetapi tidak ada yang menggunakan MyISAM hari ini karena memiliki begitu banyak kelemahan di InnoDB. "Sangat cepat" juga berlaku hanya ketika menghitung baris seluruh tabel MyISAM - jika kueri memiliki WHEREkondisi, maka masih harus memindai tabel atau indeks.)
    Untuk tabel InnoDB tergantung pada ukuran tabel karena mesin harus melakukan pemindaian seluruh tabel atau seluruh indeks untuk mendapatkan penghitungan yang akurat. Semakin besar tabel, semakin lambat.

  • b) menggunakan SQL_CALC_FOUND_ROWSdan FOUND_ROWS(). Dapat digunakan sebagai ganti cara sebelumnya, jika kita juga menginginkan sejumlah kecil baris juga (mengubah LIMIT). Saya pernah melihatnya digunakan untuk paging (untuk mendapatkan beberapa baris dan pada saat yang sama tahu berapa banyak total int dan menghitung jumlah pgeg).

    select sql_calc_found_rows * from table_name limit 0 ; 
    select found_rows() as table_rows ;

    Akurasi : sama seperti sebelumnya.
    Efisiensi : sama dengan sebelumnya.

  • c) menggunakan information_schematabel, sebagai pertanyaan terkait:

    select  table_rows
    from    information_schema.tables
    where   table_schema = 'database_name'
      and   table_name = 'table_name' ;

    Akurasi : Hanya perkiraan. Jika tabel adalah target dari seringnya memasukkan dan menghapus, hasilnya bisa jauh dari jumlah sebenarnya. Ini dapat ditingkatkan dengan menjalankan ANALYZE TABLElebih sering.
    Efisiensi : Sangat bagus, tidak menyentuh meja sama sekali.

  • d) menyimpan hitungan dalam database (di lain, "counter" tabel ) dan memperbarui nilai itu setiap kali tabel memiliki menyisipkan, menghapus atau memotong (ini dapat dicapai dengan pemicu atau dengan memodifikasi prosedur menyisipkan dan menghapus) .
    Ini tentu saja akan menempatkan beban tambahan di setiap sisipan dan menghapus tetapi akan memberikan jumlah yang akurat.

    Akurasi : Hitungan 100% akurat.
    Efisiensi : Sangat bagus, hanya perlu membaca satu baris dari tabel lain.
    Namun menempatkan beban tambahan ke database.

  • e) menyimpan ( caching ) hitungan di lapisan aplikasi - dan menggunakan metode 1 (atau kombinasi dari metode sebelumnya). Contoh: jalankan kueri hitungan persis setiap 10 menit. Sementara waktu antara dua hitungan, gunakan nilai yang di-cache.

    Akurasi : perkiraan tetapi tidak terlalu buruk dalam keadaan normal (kecuali ketika ribuan baris ditambahkan atau dihapus).
    Efisiensi : Sangat bagus, nilainya selalu tersedia.


1

Untuk INNODBAnda inginkan information_schema.INNODB_SYS_TABLESTATS.NUM_ROWSuntuk data jumlah baris tabel yang akurat, bukan information_schema.TABLES.TABLE_ROWS.

Saya memposting rincian lebih lanjut di sini: /programming/33383877/why-does-information-schema-tables-give-such-an-unstable-answer-for-number-of-ro/49184843#49184843


1
Informasi yang salah ... "Untuk InnoDB Anda ingin information_schema.INNODB_SYS_TABLESTATS.NUM_ROWS untuk baris tabel yang akurat:" manual jelas mengatakan diperkirakan pada NUM_ROWSColum
Raymond Nijland
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.