Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Reasons not to use GROUP_CONCAT?

Tags:

sql

php

mysql

I just discovered this amazingly useful MySQL function GROUP_CONCAT. It appears so useful and over-simplifying for me that I'm actually afraid of using it. Mainly because it's been quite some time since I started in web-programming and I've never seen it anywhere. A sample of awesome usage would be the following

Table clients holds clients ( you don't say... ) one row per client with unique IDs.
Table currencies has 3 columns client_id, currency and amount.

Now if I wanted to get user 15's name from the clients table and his balances, with the "old" method of array overwriting I would have to do use the following SQL

SELECT id, name, currency, amount 
FROM clients LEFT JOIN currencies ON clients.id = client_id 
WHERE clients.id = 15

Then in php I would have to loop through the result set and do an array overwrite ( which I'm really not a big fan of, especially in massive result sets ) like

$result = array();
foreach($stmt->fetchAll() as $row){
    $result[$row['id']]['name'] = $row['name'];
    $result[$row['id']]['currencies'][$row['currency']] = $row['amount'];
}

However with the newly discovered function I can use this

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

Then on application level things are so awesome and pretty

$results = $stmt->fetchAll();
foreach($results as $k => $v){
    $results[$k]['currencies'] = array_combine(explode(',', $v['currencies']), explode(',', $v['amounts']));
}

The question I would like to ask is are there any drawbacks to using this function in performance or anything at all, because to me it just looks like pure awesomeness, which makes me think that there must be a reason for people not to be using it quite often.

EDIT:

I want to ask, eventually, what are the other options besides array overwriting to end up with a multidimensional array from a MySQL result set, because if I'm selecting 15 columns it's a really big pain in the neck to write that beast..

like image 402
php_nub_qq Avatar asked Oct 06 '14 21:10

php_nub_qq


1 Answers

  • Using GROUP_CONCAT() usually invokes the group-by logic and creates temporary tables, which are usually a big negative for performance. Sometimes you can add the right index to avoid the temp table in a group-by query, but not in every case.

  • As @MarcB points out, the default length limit of a group-concatenated string is pretty short, and many people have been confused by truncated lists. You can increase the limit with group_concat_max_len.

  • Exploding a string into an array in PHP does not come for free. Just because you can do it in one function call in PHP doesn't mean it's the best for performance. I haven't benchmarked the difference, but I doubt you have either.

  • GROUP_CONCAT() is a MySQLism. It is not supported widely by other SQL products. In some cases (e.g. SQLite), they have a GROUP_CONCAT() function, but it doesn't work exactly the same as in MySQL, so this can lead to confusing bugs if you have to support multiple RDBMS back-ends. Of course, if you don't need to worry about porting, this is not an issue.

  • If you want to fetch multiple columns from your currencies table, then you need multiple GROUP_CONCAT() expressions. Are the lists guaranteed to be in the same order? That is, does the third field in one list correspond to the third field in the next list? The answer is no -- not unless you specify the order with an ORDER BY clause inside the GROUP_CONCAT().

I usually favor your first code format, use a conventional result set, and loop over the results, saving to a new array indexed by client id, appending the currencies to an array. This is a straightforward solution, keeps the SQL simple and easier to optimize, and works better if you have multiple columns to fetch.

I'm not trying to say GROUP_CONCAT() is bad! It's really useful in many cases. But trying to make any one-size-fits-all rule to use (or to avoid) any function or language feature is simplistic.

like image 195
Bill Karwin Avatar answered Sep 20 '22 01:09

Bill Karwin