【问题标题】:How to count and limit record in a single query in MYSQL?如何在MYSQL中对单个查询中的记录进行计数和限制?
【发布时间】:2010-10-22 14:08:30
【问题描述】:

我正在如下表中搜索记录:

SELECT Id, Name FROM my_table WHERE Name LIKE '%prashant%' LIMIT 0, 10;

现在,我添加 LIMIT 来维护我的分页。但是当用户搜索“prashant”这个词时,我拥有的“prashant”的总记录是 124 条。但是由于对查询的限制,所以它只在我的 PHP 脚本中获取 10 条记录,当我计算 PHP 代码中的 mysql 变量时,它返回的总记录数是 10。

所以基本上我想使用单个查询来计数和限制,通过在上面的查询中进行一些修改,我想要记录的总数(124)。我不想运行单独的 count(*) 查询来计算查询找到的总结果。

谢谢。

【问题讨论】:

    标签: php mysql count


    【解决方案1】:
    SELECT SQL_CALC_FOUND_ROWS
      Id, Name
    FROM my_table
    WHERE
      Name LIKE '%prashant%'
    LIMIT 0, 10;
    
    # Find total rows
    SELECT FOUND_ROWS();
    

    more info

    【讨论】:

    • MySQL 在 ad-hocery 部门总是令人惊叹。
    • "MySQL 在临时部门总是令人惊叹。" - 我不明白,请解释...
    • 这是一个支持网页分页的不太有价值的扩展,阅读 MySQL 文档很明显,在添加之前它并没有经过深思熟虑。而且性能很差。简而言之,这是一个 hack。
    【解决方案2】:

    MySQL 支持使用 Ionut 提到的 SQL_CALC_FOUND_ROWS 执行此操作。然而,事实证明in many cases 使用两个语句以老式方式执行它实际上更快,其中一个是常规的count()。然而,这确实要求可以使用索引扫描来完成计数,对于这个查询来说,情况并非如此,但我想我还是会提到它。

    【讨论】:

    【解决方案3】:

    如果表很大并选择多个字段(不仅仅是您的示例中的 Id、Name),我建议使用 2 个查询。首先使用所有这些 WHERE 子句选择 count(0),然后才构建分页、选择数据等。 例如,它会在一些流行的电子商务网站上运行得更快。

    【讨论】:

      【解决方案4】:

      这是为其他有相同需求的人准备的(考虑到这个问题已经 3 年了)。

      我遇到了类似的问题,我不想创建 2 个查询。所以我所做的就是为总数创建一个额外的列,并将LIMITOFFSET 子句移到最后:

      SELECT SQL_CALC_FOUND_ROWS * FROM (
          SELECT `id`, `name`
          FROM `my_table`
          WHERE `name` LIKE '%prashant%'
      ) res,
      (SELECT /*CEIL(FOUND_ROWS()/10) AS 'pages',*/ FOUND_ROWS() AS 'total') tot
      LIMIT 0, 10
      

      所以结果是这样的

      | id  |      name      | total |
      +-----+----------------+-------+
      |  1  | Jason Prashant |  124  |
      |  2  | Bob Prashant   |  124  |
      |  3  | Sam Prashant   |  124  |
      |  4  | etc. prashant  |  124  |
      

      而且我认为这个解决方案在时间上没有缺点,因为它只获取一次结果,然后将已经计算的行数用于附加列。

      【讨论】:

        【解决方案5】:

        不要使用 SQL_CALC_FOUND_ROWS 和 FOUND_ROWS()

        1. 报告了错误
          在这里:https://bugs.mysql.com/bug.php?id=18454
          在这里:https://bugs.mysql.com/bug.php?id=19553

        2. 在小型表上,BENCHMARK 更多地依赖于其他事物,因此您的 SELECT 将花费的时间将与 COUNT(0) 大致相同 - SQL_CALC_FOUND_ROWS 仍然限制 LIMIT 和 ORDER BY 数据库优化,所以如果您依赖它们不要使用 SQL_CALC_FOUND_ROWS

        3. 在大型表上,BENCHMARK 差异变得巨大,其中 COUNT(0) 可能需要 0.003 秒,而相同的 SQL_CALC_FOUND_ROWS 现在可能需要 20 秒

        从所有指标来看,COUNT(0) 是最佳选择

        COUNT(0) 个语法:

        (SELECT COUNT(0) FROM tableNames WHERE condition) AS alias
        // alias is optional but needed if you need to use the result later
        

        所以你的总查询应该是这样的

        (SELECT COUNT(0) FROM my_table WHERE name LIKE '%prashant%') AS countResults;
        
        SELECT Id, Name FROM my_table WHERE Name LIKE '%prashant%' LIMIT 0, 10;
        

        然后只需在其他地方需要它的任何地方调用 countResults...

        使用 COUNT(0) 的另一个优点是您可以使用它来搜索与此处相同的表,也可以使用它来搜索不同的表...

        例如,如果找到的每个人也分别有 3、2、1、5 个不同的工作......你可以添加一个

        (SELECT COUNT(0) FROM my_jobs_table WHERE name = name_row_in_jobs_table) AS jobs
        

        像这样在你原来的 SELECT 里面

        SELECT Id, Name (SELECT COUNT(0) FROM my_jobs_table WHERE name = name_row_in_jobs_table) AS jobs FROM my_table WHERE Name LIKE '%prashant%' LIMIT 0, 10;
        

        给你:

        --------------------
        | id | Name | jobs |
        --------------------
        | 1  | Alice| 3    |
        --------------------
        | 2  | John | 2    |
        --------------------
        | 3  | Bob  | 1    |
        --------------------
        | 4  | Jill | 5    |
        --------------------
        

        因此,当显示姓名[3](即 Bob)时,您还可以通过调用 jobs[3] 来显示 Bob 有 1 份工作...

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2016-03-09
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多