Php 不使用GROUP_CONCAT的原因?

Php 不使用GROUP_CONCAT的原因?,php,mysql,sql,Php,Mysql,Sql,我刚刚发现了这个非常有用的MySQL函数GROUP\u CONCAT。它对我来说是如此的有用和过于简化,以至于我真的害怕使用它。主要是因为自从我开始从事网络编程已经有一段时间了,我在任何地方都没有见过它。下面是一个很棒的用法示例 表clients为每个客户机保存一行具有唯一ID的客户机(您不会说…。 表货币有3列客户id、货币和金额 现在,如果我想从clients表中获取用户15的名称及其余额,使用“旧”数组覆盖方法,我必须使用以下SQL SELECT id, name, currency, a

我刚刚发现了这个非常有用的MySQL函数
GROUP\u CONCAT
。它对我来说是如此的有用和过于简化,以至于我真的害怕使用它。主要是因为自从我开始从事网络编程已经有一段时间了,我在任何地方都没有见过它。下面是一个很棒的用法示例

clients
为每个客户机保存一行具有唯一ID的客户机(您不会说…。
货币
有3列
客户id
货币
金额

现在,如果我想从
clients
表中获取用户15的
名称
及其余额,使用“旧”数组覆盖方法,我必须使用以下SQL

SELECT id, name, currency, amount 
FROM clients LEFT JOIN currencies ON clients.id = client_id 
WHERE clients.id = 15
然后在php中,我必须循环遍历结果集并执行数组覆盖(我真的不太喜欢这样做,尤其是在大量结果集中)

但是,对于新发现的函数,我可以使用

SELECT id, name, GROUP_CONCAT(currency) as currencies GROUP_CONCAT(amount) as amounts 
FROM clients LEFT JOIN currencies ON clients.id = client_id 
WHERE clients.id = 15
GROUP BY clients.id
然后在应用程序级别上,事情是如此的棒和漂亮

$results = $stmt->fetchAll();
foreach($results as $k => $v){
    $results[$k]['currencies'] = array_combine(explode(',', $v['currencies']), explode(',', $v['amounts']));
}
我想问的问题是,在性能或任何方面使用此函数是否有任何缺点,因为对我来说,它看起来就像纯粹的令人敬畏的东西,这让我认为人们不经常使用它一定是有原因的

编辑:
我想问,最终,除了数组覆盖之外,还有什么其他选项可以从MySQL结果集中得到一个多维数组,因为如果我选择15列,那么编写beast真的是一件非常痛苦的事。

我看到的
GROUP_CONCAT
最大的问题是它对MySql非常特定:如果你想移植你的代码以在任何其他平台上运行,你必须重写所有使用
GROUP_CONCAT
的查询。例如,您的第一个查询的可移植性要高得多—您可能可以针对任何主要的RDBMS引擎运行它,而无需更改其中的单个字符

如果您只使用MySql(比如,因为您正在编写一个专门针对MySql的工具),使用
GROUP\u CONCAT
的查询可能会更快,因为RDBMS会为您做更多的工作,节省数据传输的大小。

  • 使用GROUP_CONCAT()通常通过逻辑调用GROUP并创建临时表,这通常会对性能造成很大的负面影响。有时,您可以添加正确的索引以避免GROUPBY查询中的temp表,但并非在所有情况下都如此

  • 正如@MarcB指出的,组连接字符串的默认长度限制非常短,许多人对截断列表感到困惑。你可以增加限额

  • 在PHP中将字符串分解为数组并不是免费的。仅仅因为在PHP中可以在一个函数调用中完成,并不意味着它是性能最好的。我还没有对差异进行基准测试,但我怀疑你也没有

  • GROUP_CONCAT()是一个MySQLism。其他SQL产品并不广泛支持它。在某些情况下(例如SQLite),它们有一个GROUP_CONCAT()函数,但它的工作原理与MySQL中的不完全相同,因此如果您必须支持多个RDBMS后端,这可能会导致混淆错误。当然,如果您不需要担心移植,这不是一个问题

  • 如果要从
    currences
    表中获取多个列,则需要多个GROUP_CONCAT()表达式。是否保证列表的顺序相同?也就是说,一个列表中的第三个字段是否对应于下一个列表中的第三个字段?答案是否定的——除非在GROUP_CONCAT()中使用
    order BY
    子句指定订单

我通常喜欢您的第一种代码格式,使用传统的结果集,循环结果,保存到一个新的数组中,通过客户端id索引,将货币附加到数组中。这是一个简单的解决方案,使SQL保持简单且易于优化,并且如果要获取多个列,效果会更好


我不是想说groupconcat()不好!它在很多情况下都非常有用。但是,试图制定任何一刀切的规则来使用(或避免)任何函数或语言功能都是过于简单的。

这很方便,但并不普遍方便。它可以返回的字符串的长度是有限的,默认情况下通常是1024个字符。如果你有一个“大”数据集,你的压缩字符串很容易超过1024个字符,它将被自动截断/损坏。这里已经介绍了长度可以配置端口我的代码?伙计,如果我的房间温度发生变化,我的代码就不起作用了!lol
:D
我在这个答案中错过的是一个解释,为什么从来没有一个好的理由在第一时间甚至需要group_concat。@popovitsj数组覆盖大量的结果集和选定的列是低效的,对代码来说是痛苦的,这不是一个好的理由吗?(不是说group_concat更有效,只是在想)@popovitsj,请看我的答案,包括评论中的讨论。@php_nub_qq,我会根据具体情况进行测试。正如您所说,在任一表中获取的行数都会影响哪个解决方案更有效。别猜,测试@我不明白为什么你认为你需要这个数组覆盖,但当然,我不知道你的应用程序的其他任何东西。我喜欢相信,你不经常看到group_concat()的原因是因为它违背了关系数据库的一个核心原则,我认为对这个函数的需求主要是由那些没有真正“获取”关系数据库的人推动的。
$results = $stmt->fetchAll();
foreach($results as $k => $v){
    $results[$k]['currencies'] = array_combine(explode(',', $v['currencies']), explode(',', $v['amounts']));
}