MariaDB:带有子查询的 group_concat 失败
Posted
技术标签:
【中文标题】MariaDB:带有子查询的 group_concat 失败【英文标题】:MariaDB: group_concat with subquery failing 【发布时间】:2018-02-05 22:19:38 【问题描述】:在 mysql 5.6.34(我的新开发服务器)和 MariaDB 10.2.8(我的新生产服务器,我以为我今天终于部署代码的地方——叹息!)上的数据库结构和数据完全相同,MySQL 是工作而 MariaDB 没有。这是多年来在 MySQL 5.0.95 上运行良好的代码。我已将查询简化为显示问题的最小示例 - 似乎 GROUP_CONCAT()
和子查询不混合。这是查询:
SELECT person.PersonID,
GROUP_CONCAT(CategoryID ORDER BY CategoryID SEPARATOR ',') AS categories
FROM person LEFT JOIN percat ON person.PersonID=percat.PersonID
WHERE person.PersonID IN (SELECT PersonID FROM action WHERE ActionTypeID=3)
GROUP BY person.PersonID
这是一张合成的屏幕截图,显示了所有三个表的结构:
在 MySQL 上,它运行良好,因为它已经运行了多年。这是结果和EXPLAIN
:
这是我在 MariaDB 上得到的疯狂结果:
我不太了解数据库引擎的内部工作原理,无法关注EXPLAIN
,但我认为线索就在某处。我发现this bug report 听起来很相关,但我真的不明白他们在说什么,更重要的是,我应该怎么做。
【问题讨论】:
【参考方案1】:这是一个错误,显然它与您发现的不完全相同(因为上述错误报告中的测试用例在 10.2.8 上运行良好,而您的确实不行)。请随时通过MariaDB JIRA 报告新的。
同时,我认为您应该能够通过设置来解决它
optimizer_switch=orderby_uses_equalities=off
在您的 cnf 文件中。这是一个新启用的优化,显然不是完美无缺的。
更新:该错误现在报告为https://jira.mariadb.org/browse/MDEV-13694
【讨论】:
如果关闭,我似乎无法关闭 - 显然我做错了。在/etc/my.cnf
,[mysqld]
部分,我添加了optimizer_switch = orderby_uses_equalities=off
(我尝试了带单引号和不带单引号 - 我在两者的网络上看到了示例)并重新启动了 mysqld(它也有奇怪的行为 - 它没有给出我的ssh 提示返回,直到我在等待一段时间后按 ^C)。但是SELECT @@optimizer_switch\G
说orderby_uses_equalities
还在,查询行为没有变化。
截面和线条都很好。首先,检查您的服务器是否确实重新启动(例如通过验证SHOW STATUS LIKE 'Uptime'
和/或错误日志。)听起来服务器并没有真正关闭,然后尝试重新启动,并开始争夺数据目录,例如用于锁定 aria 控制文件等。如果服务器确实重新启动,则另一个可能的原因是您的安装未使用此 cnf 文件。您可以在 optimizer_switch 之后放置一些独特的东西,例如lock_wait_timeout=42
(或任何你能认出的),看看它是否被捡起。
是的,就是这样 - 它实际上并没有重新启动(我的命令错误)。您的解决方法就像一个魅力!当我有更多时间时,我会简化我的代码,但是现在,我可以继续启动我的新服务器,感谢你。
感谢您报告错误。我必须先注册为 JIRA 的成员,但我还没有开始。
@OsakaWebbie - 向我们展示整个 SET
声明。也许你在使用 GLOBAL
而应该使用 SESSION
。【参考方案2】:
解决方法这无法回答为什么会有差异,但您应该将DISTINCT
添加到GROUP_CONCAT
。
“为什么” 答案可能深深植根于优化器中。自 5.0 以来发生了很多变化。 5.6有很多新代码;与此同时,MariaDB 正在分叉到 10.0。在这次分叉中,优化器出现了显着差异。 10.2 更进一步,但未必在优化这种类型的查询。
改进的查询 可以对查询执行几项操作。有些可能会更快:
SELECT p.PersonID,
( SELECT GROUP_CONCAT(pc.CategoryID
ORDER BY CategoryID SEPARATOR ',')
FROM percat
WHERE PersonID = p.PersonID
) AS categories
FROM person
JOIN action AS a ON p.PersonID = a.PersonID
WHERE ActionTypeID = 3
GROUP BY p.PersonID
转换LEFT JOIN
可能会减少GROUP BY
的负载。可能GROUP BY
可以删除。
因为PRIMARY KEY(PersonID, CategoryID)
,应该不需要DISTINCT
。
需要的索引这个“覆盖索引”会加快速度:INDEX(ActionTypeID, PersonID)
。
【讨论】:
添加 DISTINCT 只消除了重复的 CategoryID - 它对主要问题没有影响:当应该有多个时,我仍然只得到一个人记录。至于您通过将子查询更改为连接来优化的想法,请注意我在这里共享的查询非常简化 - 在我的实际应用程序中,用户可以组合各种搜索条件,我必须以编程方式进行任何他们选择一个工作查询。如果没有子查询,我无法找到一种方法。GROUP BY PersonID
导致每人只有一行。我想我不知道你想要什么。而且您的样本输出每人只有一行。模拟你想要的输出。
有四个人匹配 WHERE,所以应该返回四行。正确的输出可以在“On MySQL...”屏幕截图中看到。我不知道为什么前三个人没有返回,但这是主要问题。以上是关于MariaDB:带有子查询的 group_concat 失败的主要内容,如果未能解决你的问题,请参考以下文章