Mysql

使用索引時加快 COUNT(*)

  • July 17, 2020

我有一個類似的表(簡化):

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 事件上創建觸發器。

**更新:**證明查詢將部分讀取索引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)

引用自:https://dba.stackexchange.com/questions/108769