web-dev-qa-db-ja.com

インデックスを使用するときにCOUNT(*)を高速化する

私はこれに似たテーブルを持っています(簡略化):

CREATE TABLE books (
    id INT AUTO_INCREMENT,
    category INT NOT NULL,
    PRIMARY KEY (id),
    KEY (category)
);

このテーブルには10,000,000 rows、約12 categories。したがって、各カテゴリの平均は833,333 books

カウントを照会する場合:

SELECT COUNT(*) FROM books WHERE category=1;

クエリを実行するときにインデックスを使用していますが、完了するまでにかなり長い時間がかかります(数秒)。これをどのように最適化しますか?

以前は、書籍に挿入するたびに(カテゴリ->書籍数に関連するテーブルに)数を増やしていましたが、コードは複雑で、多くの場所で書籍を挿入または削除しています。これをEVENTSで解決できることは知っていますが、MySQLの機能を逃してしまったのではないかと思っています。

2
gilm

categoryインデックスのカーディナリティが低いため、クエリは遅くなります。 12のカテゴリがあるため、クエリは平均してインデックスの1/12の部分を読み取ります。このクエリを改善することはできません。

元のアプローチでは、全体的なパフォーマンスを向上させることができます。手動で更新する代わりにbook_count INSERTおよびDELETEイベントでトリガーを作成します。

PDATE:クエリが部分的にインデックスを読み取ることを証明するためにcategory

mysql> select count(*) from books;
+----------+
| count(*) |
+----------+
|     1000 |
+----------+
1 row in set (0.00 sec)

mysql> select category, count(*) from books group by 1;
+----------+----------+
| category | count(*) |
+----------+----------+
|        0 |       50 |
|        1 |       77 |
|        2 |       88 |
|        3 |       84 |
|        4 |      102 |
|        5 |       79 |
|        6 |       79 |
|        7 |       73 |
|        8 |       84 |
|        9 |       76 |
|       10 |       87 |
|       11 |       83 |
|       12 |       38 |
+----------+----------+
13 rows in set (0.01 sec)

mysql> flush status;
Query OK, 0 rows affected (0.00 sec)

mysql> select count(*) from books where category = 6;
+----------+
| count(*) |
+----------+
|       79 |
+----------+
1 row in set (0.00 sec)

mysql> show status like 'Hand%';
+----------------------------+-------+
| Variable_name              | Value |
+----------------------------+-------+
| Handler_commit             | 1     |
| Handler_delete             | 0     |
| Handler_discover           | 0     |
| Handler_external_lock      | 2     |
| Handler_mrr_init           | 0     |
| Handler_prepare            | 0     |
| Handler_read_first         | 0     |
| Handler_read_key           | 1     |
| Handler_read_last          | 0     |
| Handler_read_next          | 79    |
| Handler_read_prev          | 0     |
| Handler_read_rnd           | 0     |
| Handler_read_rnd_next      | 0     |
| Handler_rollback           | 0     |
| Handler_savepoint          | 0     |
| Handler_savepoint_rollback | 0     |
| Handler_update             | 0     |
| Handler_write              | 0     |
+----------------------------+-------+
18 rows in set (0.01 sec)
2
akuzminsky