【问题标题】:Fastest way to count total number and then list a set of records in MySQL计算总数然后在MySQL中列出一组记录的最快方法
【发布时间】:2009-10-13 20:15:15
【问题描述】:

我有一条 SQL 语句从表中选择结果。我需要知道找到的记录总数,然后列出它们的子集(分页)。

通常,我会进行 2 个 SQL 调用:

  1. 一个用于统计记录总数(使用COUNT),
  2. 另一个用于返回子集(使用 LIMIT)。

但是,这样一来,您实际上在 MySQL 上复制了相同的操作:两个调用中的 WHERE 语句是相同的。

难道没有办法提高速度而不是在 MySQL 上重复选择吗?

【问题讨论】:

  • 你能发布你已经拥有的吗?
  • 第一个:SELECT COUNT(*) FROM table WHERE field>100;第二:SELECT * FROM table WHERE field>100 LIMIT 0,5;

标签: sql mysql performance


【解决方案1】:

第一个查询将导致数据被拉入缓存,因此推测第二个查询应该很快。我不会太担心这个。

【讨论】:

  • 正确 - 使您的 where 子句尽可能完整,然后不必担心执行第二个查询。因为它是紧跟在第一个之后,所以结果会像我说的那样来自缓存。
【解决方案2】:

您必须同时进行两个 SQL 查询,并且 COUNT 非常快,没有 WHERE 子句。尽可能缓存数据。

【讨论】:

  • 这是确定分页的潜在行数时唯一可靠的答案。
  • COUNT 与 LIMIT 具有相同的 WHERE 子句。
【解决方案3】:

您应该只运行一次 COUNT,然后将其缓存在某处。然后,您可以根据需要运行分页查询。

【讨论】:

  • 不是我。 ;) 但是,您的解决方案正是我所做的:具有相同 WHERE 子句的两个 SQL 查询。
  • 我阅读了您的问题,因为每次有人想要查看新页面时,我都会运行 2 个查询。我的建议是运行一次获取计数的查询并将结果缓存在一个变量中,然后为请求的每组新值运行分页查询。
【解决方案4】:

如果您真的不想运行 COUNT() 查询 - 正如其他人所说,这不会显着减慢速度 - 那么您必须决定您的块大小(即前面的LIMIT 号码)。这将为您节省 COUNT() 查询,但您最终可能会得到不幸的分页结果(例如 2 页,而第 2 页只有 1 个结果)。

因此,快速设置COUNT(),然后设置合理的LIMIT,或者不设置COUNT() 和任意LIMIT,这可能会增加您必须执行的更昂贵查询的数量。

【讨论】:

    【解决方案5】:

    您可以尝试只选择一个字段(例如 ID)并查看是否有帮助,但我认为不会有帮助 - 我想最大的开销是 MySQL 首先找到正确的行。

    如果您只是想计算整个表中的总行数(即没有WHERE 子句),那么我相信SELECT COUNT(*) FROM table 相当有效。

    否则,如果您需要显示总数,唯一的解决方案是选择所有行。但是,您可以将其缓存在另一个表中。例如,如果您从类别中选择某些内容,请存储类别 UID 和选定的总行数。然后,每当您添加/删除行时,再次计算总数。

    另一种选择——尽管它可能会牺牲一点可用性——是只选择当前页面和下一页所需的行。如果有一些行可用于下一页,请添加“下一页”链接。对上一页执行相同操作。如果每页有 20 行,则每次加载页面时最多选择 60 行,并且不需要计算所有可用行。

    【讨论】:

    • 我想向用户展示有多少结果(数量),即使只显示实际结果的子集也很难。
    【解决方案6】:

    如果您编写查询以包含一个包含计数的列(在每一行中),然后是第二个查询中的其余列,您可以:

    1. 避免第二次数据库往返(这可能比您的查询更昂贵)
    2. 增加 MySQL 解析器生成优化执行计划以重用基本查询的可能性。
    3. 使操作原子化。

    不幸的是,它还会产生一些重复,返回的数据比您真正需要的要多。但我希望它无论如何都会更有效率。这是许多 ORM 产品在急切地从具有多对一或多对多关系的连接表中加载对象时使用的策略。

    【讨论】:

      【解决方案7】:

      正如其他人已经指出的那样,在这种情况下可能不值得太担心——只要对“字段”进行索引,两个选择都会非常快。

      如果您遇到(无论出于何种原因)这还不够的情况,您可以创建一个基于内存的临时表(即由内存存储引擎支持的临时表),然后将您的记录选择到该临时表中。然后,您可以从临时表中进行选择,并且可以确信它们会很快。虽然这可能会占用大量内存(即,它会强制数据在持续时间内全部保留在内存中),因此除非您确定:

      1. 数据量真的很小;
      2. 你有这么多内存没关系;或
      3. 否则机器将几乎处于空闲状态。

      这主要是因为如果您有一个非常复杂的选择,它无法避免扫描所有大表(或多个表)但只产生少量数据。

      【讨论】:

        猜你喜欢
        • 2016-08-23
        • 1970-01-01
        • 2018-01-10
        • 1970-01-01
        • 1970-01-01
        • 2012-09-09
        • 1970-01-01
        • 2014-11-07
        • 1970-01-01
        相关资源
        最近更新 更多