MySQLのCOUNT(*)のパフォーマンスについて話します

序文

基本的に、職場のプログラマーは、count(*)、count(1)、またはcount(プライマリキー)を使用して、データベーステーブルの行数をカウントします。それらの違いとパフォーマンスを知っていますか?

実際、プログラマーの開発プロセスでは、大きなテーブルの行の総数を数えるのは非常に時間のかかる操作です。それでは、より速く数えるためにどの方法を使用する必要がありますか?

次に、MySQLの合計行数をカウントする方法とパフォーマンスについて説明します。

count(*)、count(1)、count(primary key)のどちらが速いですか?

1.テーブルを作成し、実験テスト用に1,000万個のデータを挿入します。

# 创建测试表
CREATE TABLE `t6` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(50) NOT NULL,
  `status` tinyint(4) NOT NULL,
  PRIMARY KEY (`id`),
  KEY `idx_status` (`status`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

# 创建存储过程插入1000w数据
CREATE PROCEDURE insert_1000w()
BEGIN
    DECLARE i INT;
    SET i=1;
    WHILE i<=10000000 DO
        INSERT INTO t6(name,status) VALUES('god-jiang-666',1);
        SET i=i+1;
    END WHILE;
END;

#调用存储过程,插入1000万行数据
call insert_1000w();

2.実験結果を分析する

# 花了0.572秒
select count(*) from t6;

ここに写真の説明を挿入

# 花了0.572秒
select count(1) from t6;

ここに写真の説明を挿入

# 花了0.580秒
select count(id) from t6;

ここに写真の説明を挿入

# 花了0.620秒
select count(*) from t6 force index (primary);

ここに写真の説明を挿入

上記の実験から、count(*)とcount(1)が最も速く、次にcount(id)が続き、countが必須のプライマリキーを使用する場合が最も遅いと結論付けることができます

それぞれの実行計画のテストを続けましょう。

explain select count(*) from t6;
show warnings;

ここに写真の説明を挿入
ここに写真の説明を挿入

explain select count(1) from t6;
show warnings;

ここに写真の説明を挿入
ここに写真の説明を挿入

explain select count(id) from t6;
show warnings;

ここに写真の説明を挿入
ここに写真の説明を挿入

explain select count(*) from t6 force index (primary);
show warnings;

ここに写真の説明を挿入

ここに写真の説明を挿入

これらの3つのポイントは、上記の実験から引き出すことができます。

  1. count(*)はMySQLクエリオプティマイザによってcount(0)に書き直され、idx_statusインデックスが選択されました
  2. count(1)とcount(id)の両方がidx_statuxインデックスを選択します
  3. フォースインデックス(プライマリ)を追加した後、フォースインデックスはなくなります

このidx_statusは、セカンダリ補助インデックスツリーと同等です。目的は次のとおりです。InnoDBがcount(*)を処理するときに、補助インデックスツリーがある場合は、補助インデックスツリーを優先して行の総数をカウントします。

count(*)が補助インデックスツリーを優先的に選択するという結論を確認するために、次の実験を引き続き見ていきましょう。

# 删除idx_status索引,继续执行count(*)
alter table t6 drop index idx_status;

explain select count(*) from t6;

ここに写真の説明を挿入

上記の実験から、idx_statusのセカンダリインデックスツリーが削除された場合、count(*)がプライマリキーインデックスを選択すると結論付けることができます。したがって、結論:count(*)は補助インデックスを優先し、補助インデックスがない場合は、プライマリキーインデックスを使用します。

count(*)が補助インデックスを優先するのはなぜですか?

MySQL 5.7.18より前は、InnoDBはクラスター化されたインデックスをスキャンしてcount(*)ステートメントを処理していました。

MySQL 5.7.18以降、InnoDBは、使用可能な最小のセカンダリインデックスをトラバースすることにより、count(*)ステートメントを処理します。セカンダリインデックスがない場合は、クラスター化されたインデックスをスキャンします。

新しいバージョンがcount(*)を処理するためにセカンダリインデックスを使用するのはなぜですか?

InnoDBセカンダリインデックスツリーのリーフノードにはプライマリキーが格納され、プライマリキーインデックスツリーのリーフノードにはデータの行全体が格納されるため、セカンダリインデックスツリーはプライマリキーインデックスツリーよりも小さくなります。したがって、コストの考慮事項に基づいて、クエリオプティマイザはセカンダリインデックスを優先します。したがって、インデックスcount(*)はcount(primary key)よりも高速です。

総括する

この記事の結論は、count(*)= count(1)> count(id)です。

プライマリキーインデックスがなくなった場合、count(id)が遅くなるのはなぜですか?count(id)は主キーを取り出し、それが空ではないと判断してから合計する必要があるため、コストが高くなります。

count(*)はすべてのNOT NULLフィールドとNULLフィールドをカウントし、count(id)はNULLフィールドをカウントしないため、テーブルを作成するときにNOT NULLを使用して、デフォルトのnullを指定しようとします。

最後に、将来データベーステーブルの行の総数を合計するときは、count(*)またはcount(1)を大胆に使用できます。

参照

  • 「高性能MySQL」(第3版)第6章最適化COUNT()クエリ
  • 「MySQL45レクチャー」LinXiaobin

おすすめ

転載: blog.csdn.net/weixin_37686415/article/details/109755245