当前位置: 首页 > 面试题库 >

在MySQL中加快行计数

费锋
2023-03-14
问题内容

出于说明目的,假设您正在使用带有三列的简单MySQL“ books”表运行一个库:

(ID,标题,状态)

  • id 是主键
  • 书名 是书的标题
  • status 可以是描述书籍当前状态的枚举(例如,Available,Checkedout,Processing,MISSING)

一个简单的查询来报告每种状态下有多少本书:

SELECT status, COUNT(*) FROM books GROUP BY status

或专门查找有多少本书:

SELECT COUNT(*) FROM books WHERE status = "AVAILABLE"

但是,一旦表增长到数百万行,这些查询将花费几秒钟来完成。在“状态”列中添加索引似乎并没有改变我的经验。

除了在书每次更改状态时(通过触发器或其他某种机制)定期缓存结果或在单独的表中显式更新摘要信息外,是否有任何技术可以加快此类查询的速度?似乎COUNT查询最终查看了每一行,而且(不知道更多详细信息)令我有些惊讶的是,无法以某种方式从索引中确定此信息。

更新

使用具有200万行的示例表(带有索引的“状态”列),我对GROUP
BY查询进行了基准测试。使用InnoDB存储引擎,查询在我的计算机上花费3.0-3.2秒。使用MyISAM,查询需要0.9-1.1秒。在两种情况下,count(*),count(status)或count(1)之间都没有显着差异。

MyISAM肯定要快一点,但是我很好奇是否有办法使等效查询运行 更快(例如10-50毫秒-
足够快,可以在低流量站点的每个网页请求上调用)无需担心缓存和触发器的开销。听起来答案似乎是“没有办法快速运行直接查询”,这正是我所期望的-
我只是想确保自己不会错过一个简单的选择。


问题答案:

所以问题是

有什么技术可以加快这类查询的速度吗?

好吧,不是真的。对于那些SELECT COUNT(*)查询,基于列的存储引擎可能会更快,但是对于几乎所有其他查询,它的性能都会降低。

最好的选择是通过触发器维护摘要表。它没有太多的开销,并且无论表有多大,SELECT部分​​都将是瞬时的。这是一些样板代码:

DELIMITER //

CREATE TRIGGER ai_books AFTER INSERT ON books
FOR EACH ROW UPDATE books_cnt SET total = total + 1 WHERE status = NEW.status
//
CREATE TRIGGER ad_books AFTER DELETE ON books
FOR EACH ROW UPDATE books_cnt SET total = total - 1 WHERE status = OLD.status;
//
CREATE TRIGGER au_books AFTER UPDATE ON books
FOR EACH ROW
BEGIN
    IF (OLD.status <> NEW.status)
    THEN
        UPDATE books_cnt SET total = total + IF(status = NEW.status, 1, -1) WHERE status IN (OLD.status, NEW.status);
    END IF;
END
//


 类似资料:
  • 问题内容: 在MySQL中,哪种方式计算行数应该更快? 这个: 或者,替代方案: 有人会认为第一种方法应该更快,因为在内部确定类似情况时,这显然是数据库领域,而数据库引擎应该比其他任何人都要快。 问题答案: 当您使用count列索引时,它将是最好的结果。使用 MyISAM 引擎的Mysql 实际上存储行数,每次尝试对所有行进行计数时,它都不会对所有行进行计数。(基于主键的列) 使用PHP计数行不是

  • 问题内容: 我有这个MySQL查询: 返回如下内容: 我真正想要的是末尾的另一列显示运行总计: 这可能吗? 问题答案: 也许这对您来说是一个更简单的解决方案,并且可以防止数据库不得不执行大量查询。这仅执行一个查询,然后在一次通过中对结果进行一点数学运算。 这将为您提供一个额外的RT(运行总计)列。不要错过顶部的SET语句来首先初始化运行的total变量,否则您将只获得一列NULL值。

  • 问题内容: 我正在对MySQL数据库进行“ select sum(foo)from bar”查询,该数据库总计7.3mm记录,每次运行大约需要22秒。在MySQL中有加快总和的技巧吗? 问题答案: 不,您不能加快功能本身。问题实际上是您要选择730万条记录。MySQL必须扫描整个表,而730万是一个很大的数字。实际上,它完成得如此之快给我留下了深刻的印象。 您可以采用的策略是将数据分成较小的子集(

  • 问题内容: 内容: 我们有一个PHP / MySQL应用程序。 计算的某些部分直接在SQL中完成。例如:最近24小时内创建的所有用户都将通过SQL查询返回(NOW()– 1天) 我和其他开发人员之间正在进行辩论,我认为我们应该这样做: A.将所有计算/代码/逻辑保存在PHP中,并将MySQL视为“愚蠢的”信息存储库 他的意见: B.根据更简单/更快的方式进行混合搭配。http://www.onex

  • 问题内容: 我有这个MySQL查询: 返回如下内容: 我真正想要的是末尾的另一列以显示运行总计: 这可能吗? 问题答案: 也许对您来说是一个更简单的解决方案,并且可以防止数据库不得不执行大量查询。这仅执行一个查询,然后在一次通过中对结果进行一些数学运算。 这将为您提供一个额外的RT(运行总计)列。不要错过顶部的SET语句来首先初始化运行中的total变量,否则您将只获得一列NULL值。

  • 对于这个问题,我找到了一些不同的答案,但似乎无法使查询正常工作。 这是我的表,其中包含user、weekNo、salesTotalYTD列。 我目前正在把这些拿出来,按周分组,就像这样: 我试图做但无法完成的是: 这是我为第一次通过工作的查询,但之后的每一次通过都是错误的: 更新 更新代码由蒂姆提供,但返回错误: