创造性地使用GROUP_CONCAT来避免查询...可以检索记录组吗?

时间:2014-10-01 14:07:28

标签: mysql group-concat

我运营的网站用户数量很少,我希望很快就会增长。我正在使用共享的Web托管服务,我无法在Web服务器上更改MySQL默认设置。我正在尝试最小化查询并找到一个重复的查询对(通过setTimeout到Ajax调用每10秒发生一次),其中GROUP_CONCAT可以帮助减少以下2个查询:

$logid = mysqli_real_escape_string($cxn, $_SESSION['login_id']);

$sql1 = mysqli_query($cxn, "SELECT COUNT(bid) AS count FROM table1 WHERE login_id = '$logid'");

$sql2 = mysqli_query($cxn, "SELECT cid FROM table2 WHERE (login_id1 = '$logid' OR login_id2 = '$login_id')");

一个查询:

SELECT COUNT(table1.bid) AS count,
GROUP_CONCAT(table2.cid) AS cidList 
FROM table1 
LEFT JOIN table2
ON (table1.login_id = table2.login_id1 OR table1.login_id = table2.login_id2)
WHERE table1.login_id = '$logid';

问题是group_concat_max_len默认设置为1024,我调用了我的共享托管服务,我无法更改它。上面查询中的每个table2.cid都是20个字符,所以(包括逗号分隔符)GROUP_CONCAT只能返回48个table2.cid记录,但我需要能够返回多达1000个。我已经知道我可以更改这个使用如下查询的默认限制:

SET SESSION group_concat_max_len = 1000000;

但是这个添加的查询失败了,因为即使上面的两个查询被压缩到一个查询,我现在已经添加了这个最新的查询,所以每次进行Ajax调用两个查询都是仍然做了(我还没有保存任何东西)。

是否有某种方法可以将GROUP_CONCAT聚集在一起,为每个GROUP_CONCAT检索一些记录(table2.cid)?例如,类似于(例如100条记录):

SELECT COUNT(table1.bid) AS count,
GROUP_CONCAT(table2.cid ORDER BY table2.cid LIMIT 0,47) AS cidList1,
GROUP_CONCAT(table2.cid ORDER BY table2.cid LIMIT 48,95) AS cidList2,
GROUP_CONCAT(table2.cid ORDER BY table2.cid LIMIT 96,99) AS cidList3
FROM table1 
LEFT JOIN table2
ON (table1.login_id = table2.login_id1 OR table1.login_id = table2.login_id2)
WHERE table1.login_id = '$logid';

顺便说一下,我尝试了一个测试用例并且查询因添加LIMIT而失败,因为没有LIMIT会返回正确的PHP回显字符串,并且使用LIMIT返回一个空的PHP回显字符串以及错误日志消息:

PHP Warning:  mysqli_fetch_assoc() expects parameter 1 to be mysqli_result, boolean given in

2 个答案:

答案 0 :(得分:3)

只需发出常规SELECT table1.bid, table2.cid FROM ...即可。如果bid永远不是NULL,那么SELECT cid就足够了(在这种情况下,COUNT(bid) = COUNT(cid)

计算bid并加入应用层中的cid列表几乎是即时的。无论如何,以逗号分隔的cid列表的构建绝对属于此层。

至于bid的计数,这不太明显。如果你真的想让MySQL做计数并仍然保存一个数据库调用,我宁愿做这样的事情:

SELECT COUNT(table1.bid) FROM table1 WHERE blah blah
UNION ALL
SELECT cid FROM table2 WHERE blah blah

但这是理论。说真的,不要这样做。


第二个想法,实际上有一个不那么尴尬的解决方案:

SELECT COUNT(table1.bid), table2.cid FROM ...
GROUP BY table2.cid WITH ROLLUP

table2.cidNULL的最后一行包含总计数。

答案 1 :(得分:2)

这是给你的一招:

SELECT COUNT(table1.bid) AS count,
GROUP_CONCAT(case when mod(table2.cid,3)=0 then table2.cid else null end) AS cidList1,
GROUP_CONCAT(case when mod(table2.cid,3)=1 then table2.cid else null end) AS cidList2,
GROUP_CONCAT(case when mod(table2.cid,3)=2 then table2.cid else null end) AS cidList3
FROM table1 
LEFT JOIN table2
ON (table1.login_id = table2.login_id1 OR table1.login_id = table2.login_id2)
WHERE table1.login_id = '$logid';