私はこれに似たテーブルを持っています(簡略化):
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の機能を逃してしまったのではないかと思っています。
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)