进行更高效的 COUNT

Doing a more efficient COUNT

我有一个加载一些高级统计信息的页面。没什么特别的,只有大约 5 个指标。有两个特定的查询,每个查询大约需要 5 秒才能加载:

+ SELECT COUNT(*) FROM mybooks WHERE book_id IS NOT NULL
+ SELECT COUNT(*) FROM mybooks WHERE is_media = 1

table 有大约 500,000 行。两列都已编入索引。

此信息一直在变化,所以我认为在此处缓存行不通。使用哪些技术可以加快速度?我在想:

这里有什么建议?要求是页面在1s内加载。

Table结构:

您可以采取一些措施来加快查询速度。

  1. 运行 optimize table 在你的 mybooks table

  2. 将您的 book_id 列更改为 int unsigned,它允许 42 亿个值并占用 4 个字节而不是 8 个字节 (bigint),使table 和索引更有效率。

此外,我不确定这是否可行,但我不会执行 count(*),而是 select where 子句中的列。因此,例如,您的第一个查询将是 SELECT COUNT(book_id) FROM mybooks WHERE book_id IS NOT NULL

统计数据 table 可能是物超所值的 biggest/quickest。假设您可以完全控制 MySQL 服务器并且还没有适当的作业调度来处理这个问题,您可以使用 mysql 事件调度程序来解决这个问题。正如 Vlad 上面提到的,您的数据会有点过时。这是一个简单的例子:

示例统计数据 table

CREATE TABLE stats(stat VARCHAR(20) PRIMARY KEY, count BIGINT);

初始化你的值

INSERT INTO stats(stat, count)
VALUES('all_books', 0), ('media_books', 0);

创建每 10 分钟更新一次的活动

DELIMITER |

CREATE EVENT IF NOT EXISTS updateBookCountsEvent
ON SCHEDULE EVERY 10 MINUTE STARTS NOW()
COMMENT 'Update book counts every 10 minutes'
DO
BEGIN
    UPDATE stats
    SET count = (SELECT COUNT(*) FROM mybooks)
    WHERE stat = 'all_books';
    UPDATE stats
    SET count = (SELECT COUNT(*) FROM mybooks WHERE is_media = 1)
    WHERE stat = 'media_books';
END |

查看是否执行

SELECT * FROM mysql.event;

没有?检查事件调度程序是否已启用

SELECT @@GLOBAL.event_scheduler;

如果它关闭,您需要在启动时使用参数 --event-scheduler=ON 或在您的 my.cnf 中设置它来启用它。看到这个 answer or the docs.