web-dev-qa-db-ja.com

MySQL-行をカウントするためのcount(*)とinformation_schema.tablesの使用の違い

数百万行あるテーブルの行数をすばやくカウントする方法を探しています。 Stack Overflowに「 MySQL:行数をカウントする最速の方法 」という投稿を見つけました。これで問題が解決したようです。 Bayuahがこの回答を提供しました:

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

スキャンではなくルックアップのように見えるのでどちらが好きだったので、高速であるはずですが、テストを行うことにしました。

_SELECT COUNT(*) FROM table 
_

パフォーマンスの違いがどの程度あったかを確認します。

残念ながら、以下に示すように、さまざまな答えが得られます。

enter image description here

質問

回答が約200万行異なるのはなぜですか?全テーブルスキャンを実行するクエリがより正確な数だと思いますが、この遅いクエリを実行しなくても正しい数を取得できる方法はありますか?


私は_ANALYZE TABLE data_302_を実行しましたが、0.05秒で完了しました。もう一度クエリを実行すると、34384599行という非常に近い結果が得られますが、34906061行のselect count(*)とはまだ同じ数ではありません。分析テーブルはすぐに戻り、バックグラウンドで処理されますか?これはテストデータベースであり、現在書き込まれていないことに言及する価値があると思います。

それが誰かにテーブルの大きさを伝えるだけのケースであるかどうかは誰も気にしませんが、データベースにクエリを行う「同じサイズの」非同期クエリを作成するためにその数値を使用するコードに行カウントを渡したかったのです。並列で、Alexander Rubinによる 並列クエリ実行による低速クエリパフォーマンスの向上 に示されている方法に似ています。そのまま、_SELECT id from table_name order by id DESC limit 1_で最も高いIDを取得するだけで、テーブルが断片化しすぎないことを願っています。

16
Programster

テーブル内の行を「カウント」するには、さまざまな方法があります。何が最適かは要件(カウントの正確さ、実行頻度、テーブル全体のカウントが必要か、変数whereおよび_group by_句を使用するかなど)によって異なります。

  • a)通常の方法です。 数えるだけそれら。

    _select count(*) as table_rows from table_name ; 
    _

    精度:クエリの実行時に100%正確なカウント。
    効率:大きなテーブルには適していません。 (MyISAMテーブルは驚くほど高速ですが、InnoDBに比べて多くの欠点があるため、最近は誰もMyISAMを使用していません。 "かなり高速"も適用されますMyISAMテーブル全体の行をカウントする場合-クエリにWHERE条件がある場合でも、テーブルまたはインデックスをスキャンする必要があります。)
    InnoDBテーブルの場合、エンジンはテーブル全体またはインデックス全体をスキャンして正確なカウントを取得する必要があるため、テーブルのサイズに依存します。テーブルが大きいほど、速度は遅くなります。

  • b)_SQL_CALC_FOUND_ROWS_FOUND_ROWS()を使用します。少数の行も必要な場合(LIMITを変更)、前の方法の代わりに使用できます。私はそれがページングに使用されるのを見ました(いくつかの行を取得し、同時に合計がいくつあるかを知り、pgegの数を計算するため)。

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

    精度:前と同じ。
    効率:前と同じ。

  • c)_information_schema_テーブルをリンクされた質問として使用:

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

    精度:概算のみ。テーブルが頻繁な挿入と削除のターゲットである場合、結果は実際のカウントから大きく外れる可能性があります。これは、_ANALYZE TABLE_をより頻繁に実行することで改善できます。
    効率:非常に良好で、テーブルにまったく触れません。

  • d)データベースにカウントを保存し(別の"counter"テーブル)、テーブルが挿入、削除、または切り捨てられるたびにその値を更新します(これにより、トリガーを使用するか、挿入手順と削除手順を変更することで実現できます)。
    これにより、当然、挿入と削除ごとに追加の負荷がかかりますが、正確なカウントが提供されます。

    精度:100%正確なカウント。
    効率:非常に優れており、別のテーブルから1行のみを読み取る必要があります。
    ただし、データベースに追加の負荷がかかります。

  • e)アプリケーション層でのカウントの格納(caching)-および1番目の方法(または前の方法の組み合わせ)を使用します。例:正確なカウントクエリを10分ごとに実行します。 2つのカウント間の平均時間では、キャッシュされた値を使用します。

    精度:概算ですが、通常の状況ではそれほど悪くありません(数千行が追加または削除された場合を除きます)。
    効率:非常に良い、値は常に利用可能です。

24
ypercubeᵀᴹ

INNODBの場合、information_schema.INNODB_SYS_TABLESTATS.NUM_ROWSではなくinformation_schema.TABLES.TABLE_ROWSを使用すると、正確なテーブル行数データが​​得られます。

詳細はこちらに投稿しました: https://stackoverflow.com/questions/33383877/why-does-information-schema-tables-give-such-an-unstable-answer-for-number-of-ro/ 49184843#4918484

1
Rob Bradshaw