【问题标题】:PDO::rowCount VS COUNT(*)PDO::rowCount 与 COUNT(*)
【发布时间】:2013-10-07 05:37:35
【问题描述】:

我有一个使用 PDO 的查询,首先计算行数,如果行 >1 则获取数据

SELECT * WHERE id=:id
$row=$SQL->rowCount();

if($row>0){
    while($data=$SQL->fetch(PDO::FETCH_ASSOC)){...

    }
}
else{echo "no result";}

SELECT COUNT(*), * WHERE id=:id
$data=fetch(POD::FETCH_NUM);
$row=data[0];


if($row>0){
//fetch data
}
else{echo "no result";}

哪个性能更好?

第二。问题,如果我在 id 上设置了索引

COUNT(id)COUNT(*) 哪个更好

【问题讨论】:

  • 注意:对于 select 语句,并非所有数据库都会通过 PDO::rowCount 返回行数,强 iirc MySQL 会这样做。
  • 你的SQL语句不会如你所愿,去掉第二颗星SELECT COUNT(*) FROM tablename WHERE id=:id
  • @martinstoeckli 这个声明没问题。虽然问题中的唯一陈述
  • @YourCommonSense - 据我了解,count(*) 总是返回 1(或 0),因为第二颗星总是返回唯一的行,所以它没有意义。但是正如您正确指出的那样,如果问题仅是是否存在一行,它就可以工作,我会投票赞成您的答案。
  • @martinstoeckli 实际上第二颗星将返回语法错误。而 count(*) 将返回找到的所有行数

标签: php mysql optimization pdo


【解决方案1】:

第一个问题:

使用计数COUNT(),内部服务器(MySQL)将以不同的方式处理请求。

在做COUNT()时,服务器(MySQL)只会分配内存来存储计数的结果。

当使用$row=$SQL->rowCount(); 时,服务器(Apache/PHP)将处理整个结果集,为所有这些结果分配内存,并将服务器置于获取模式,这涉及到许多不同的细节,例如锁定。

请注意,PDOStatement::rowCount() 返回受最后一条语句影响的行数,而不是返回的行数。如果关联 PDOStatement 执行的最后一条 SQL 语句是 SELECT 语句,则某些数据库可能会返回该语句返回的行数。但是,并非所有数据库都可以保证这种行为,并且不应依赖于可移植应用程序。

根据我的分析,如果你使用COUNT(),处理会被分到MySQL和PHP,如果你使用$row=$SQL->rowCount();,处理会更多地使用PHP。

因此,COUNT() 在 MySQL 中更快。

第二个问题:

COUNT(*) 优于 COUNT(id)

解释:

mysql 中的count(*) 函数被优化用于查找值的计数。使用通配符意味着它不会获取每一行。它只找到计数。所以尽可能使用count(*)

来源:

【讨论】:

  • COUNT(id) is way better than COUNT(*) 不是。 COUNT(*)更好
  • COUNT(1) vs COUNT(*)COUNT(id) 怎么样?
  • @eisberg: 优化器在解析步骤中将COUNT(*) 转换为COUNT(1) github.com/twitter/mysql/blob/master/sql/sql_yacc.yy#L8946 PS: 找不到vanilla mysql 的在线repo,但无论如何这些行中的解析器都没有改变
  • 5 票赞成与问题无关的答案。 Stack Overflow 处于最佳状态。
  • downvote:用户想要计算获取的行数,而不仅仅是表中的所有行。 count(*) 是错误的。
【解决方案2】:

事实上,这里不需要 PDO rowCount 和 COUNT(*)。

如果行 >1 则获取数据

是一个错误的陈述。
在一个设计合理的 Web 应用程序中(我知道这对 PHP 来说听起来像是个笑话),不必这样做。
最明智的方法是

  • 先获取
  • 使用获取的数据
  • 如果需要,我们可以使用这个非常获取的数据来查看是否返回了任何内容:

    $data = $stmt->fetch();
    if($data){
        //use it whatever
    } else {
        echo "No record";
    }
    

简单明了,完全没有“哪个无用功能更好”之类的问题。

在您的情况下,假设 id 是唯一索引,则只能返回一行。因此,您根本不需要 while 声明。只需使用上面的 sn-p 来获取并判断是否已获取 enythin。

如果需要很多行,只需将fetch() 更改为fetchAll(),然后使用 foreach 迭代返回的数组:

$data = $stmt->fetchAll();
if($data){
    foreach ($data as $row) {
        //use it whatever
    }
} else {
    echo "No records";
}

请注意,您不应选择超过所需的行数。表示您在常规网页上的查询不应返回多于显示的行数。

谈到问题本身 - 这没有任何意义。无法比较rowCountCOUNT(*),因为这是无与伦比的事情。这两个函数的用途完全不同,不能互换:

  • COUNT(*) 返回单行计数,只有在需要记录计数时才需要使用,但没有记录本身
    如果您需要记录,count(whatever) 既不快也不慢 - 它毫无意义。
  • rowCount() 返回已选择的行数,因此您几乎不需要它,如上所示。

更不用说第二个示例根本不会获取任何行。

【讨论】:

  • 确切地说,原始问题增加了许多错误假设:运行不同的查询可以产生相同的数据,通过不获取空结果我们正在保存一些东西......
  • 如果用while($data=$SQL->fetch(PDO::FETCH_ASSOC))怎么放if($data)?
  • @BenWong 从 query 判断只有一行打算返回,因为 id 应该是唯一索引。如果预期不止一行,则必须使用 fetchAll()
【解决方案3】:

Count(id) 或 count(*) 将使用索引扫描,因此性能会更好。 Rowcount 仅返回受影响的行,并在插入/更新/删除时有用

编辑: 由于对问题进行了编辑以比较 Count(id) 和 count(),因此略有不同。 Count() 将返回受选择影响的行数。 Count(column) 将返回非空值计数,但由于它是 id,因此不会有空列。所以这对这种情况没有影响。

【讨论】:

    【解决方案4】:

    性能差异应该可以忽略不计,因为您在两种情况下都只发出一个查询。第二个查询必须为匹配id 的每一行获取一个具有相同值的额外列,因此它可能会占用大量内存。即使没有COUNT(*),行数也应该可用,因此您应该使用第一种解决方案。

    关于您的第二个问题,AFAIK COUNT(id)COUNT(*) 使用 id 上的索引会更快,因为数据库引擎必须执行范围扫描以检索有问题的行,并且范围扫描 在索引列上过滤时使用索引更快(在您的情况下为id = SOME_ID)。

    【讨论】:

    • "AFAIK COUNT(id) 使用索引会更快" --- COUNT(col)永远COUNT(*) 一样快
    • @zerkms 抱歉,我并不是说它会比 COUNT(*) 快,只是索引会更快。会改正
    【解决方案5】:

    Count(*) 会更快。

    PDOStatement::rowCount() 不保证根据 PDO 文档工作:

    “不保证适用于所有数据库,不应依赖于便携式应用程序。”

    所以在你的情况下,我建议使用count(*)

    见参考: pdostatement.rowcount Manual

    【讨论】:

    • 澄清一下,PDOStatement::rowCount() 不能保证,您建议的计数是 select 语句中的 Count(*) 函数?
    • 到底有谁支持这个完全自相矛盾的答案?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-09-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-04
    • 1970-01-01
    • 2017-03-14
    相关资源
    最近更新 更多