【问题标题】:Doing a more efficient COUNT做一个更有效的 COUNT
【发布时间】:2015-02-21 22:14:53
【问题描述】:

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

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

该表有大约 500,000 行。两列都有索引。

这些信息一直在变化,所以我认为这里的缓存不会起作用。使用哪些技术可以加快速度?我在想:

  • 创建一个非规范化的stats 表,在更新列时更新该表。
  • 通过 ajax 加载慢速查询(这不会加快速度,但可以让页面立即加载)。

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

表结构:

  • id(pk,自动递增)
  • book_id (bigint)
  • is_media(布尔值)

【问题讨论】:

  • 我个人会走AJAX路线..易于实现,解决问题,不需要新表并避免mybooksstats之间可能出现的数据不一致。
  • 能否包含您的表结构?
  • @Pattle 请查看更新后的问题。
  • 500,000 行并不多。扫描它们不应花费 5 秒钟。如果频繁更新这张表,可能意味着计数查询被简单阻塞,等待了很长时间。我可能会创建一个统计表并随着数据的变化对其进行更新。或者,如果您可以允许统计信息有点过时,请每 10 分钟左右在后台运行这些计数查询以更新统计信息表。从某种意义上说,缓存结果。
  • 即使你得到了完美的 INDEX,它也将有 500K 行长,并且必须扫描该索引。也许不是 5 秒,但仍然“太长”。

标签: mysql sql count


【解决方案1】:

统计数据表可能是最大/最快的收益。假设您完全控制了 MySQL 服务器并且还没有安排作业调度来处理这个问题,您可以使用 mysql 事件调度程序来解决这个问题。正如 Vlad 上面提到的,您的数据会有点过时。这是一个简单的例子:

示例统计表

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 中设置它来启用它。请参阅此answerdocs

【讨论】:

    【解决方案2】:

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

    1. 在您的 mybooks 表上运行 optimize table

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

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

    【讨论】:

    • OPTIMIZE TABLE 几乎没有任何帮助。它会做一些碎片整理,但这是有限的和暂时的。 COUNT(book_id) 只计算非 NULL book_ids,因此 WHERE 子句的更改是多余的。
    猜你喜欢
    • 2011-07-12
    • 1970-01-01
    • 2014-08-04
    • 1970-01-01
    • 2012-10-19
    • 2011-02-27
    • 1970-01-01
    • 2014-04-13
    相关资源
    最近更新 更多