进行更高效的 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 行。两列都已编入索引。
此信息一直在变化,所以我认为在此处缓存行不通。使用哪些技术可以加快速度?我在想:
- 创建一个非规范化的
stats
table,只要更新列,它就会更新。
- 通过 ajax 加载缓慢的查询(这不会加快速度,但它允许页面立即加载)。
这里有什么建议?要求是页面在1s内加载。
Table结构:
- id(pk,自动递增)
- book_id (bigint)
- is_media(布尔值)
您可以采取一些措施来加快查询速度。
运行 optimize table
在你的 mybooks
table
将您的 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.
我有一个加载一些高级统计信息的页面。没什么特别的,只有大约 5 个指标。有两个特定的查询,每个查询大约需要 5 秒才能加载:
+ SELECT COUNT(*) FROM mybooks WHERE book_id IS NOT NULL
+ SELECT COUNT(*) FROM mybooks WHERE is_media = 1
table 有大约 500,000 行。两列都已编入索引。
此信息一直在变化,所以我认为在此处缓存行不通。使用哪些技术可以加快速度?我在想:
- 创建一个非规范化的
stats
table,只要更新列,它就会更新。 - 通过 ajax 加载缓慢的查询(这不会加快速度,但它允许页面立即加载)。
这里有什么建议?要求是页面在1s内加载。
Table结构:
- id(pk,自动递增)
- book_id (bigint)
- is_media(布尔值)
您可以采取一些措施来加快查询速度。
运行
optimize table
在你的mybooks
table将您的
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.