mysql8.0 with cte查询_MySQL8.0.19-通过Limit调试递归CTE

本文介绍了在MySQL 8.0中如何使用LIMIT子句调试递归通用表表达式(CTE),以解决由于错误或数据循环导致的无限递归问题。通过示例说明了递归CTE在查询逻辑错误或数据变化时可能导致无限循环,并展示了如何利用LIMIT找出循环的原因。
摘要由CSDN通过智能技术生成

作者:Guilhem Bichot 译:徐轶韬

在MySQL 8.0.1中,我们引入了对递归通用表表达式(CTE)的支持。今天,我想提出一个解决方案,当使用递归CTE编写查询时,几乎每个人都会遇到:发生无限递归时,如何调试?

考虑以下示例查询,该查询生成从1到5的整数:

3592d07f0091b2daeb3b5014587f705e.png

此查询正常执行,这是它的结果:

caa2747177fc86bb60aaf7ed4601afc0.png

现在,假设我在键入它时犯了一个小错误(这只是键盘意外,在“

2769463a97562e0db7129c2396b38dbc.png

MySQL现在将错误的WHERE条件转换为“ n * 5 <> 0”,这对于所有行都是正确的。因此,递归算法将生成越来越多的行,进行越来越多的迭代,直到达到默认的最大迭代次数,从而导致错误:““ERROR 3636 (HY000): Recursive query aborted after 1001 iterations. Try increasing @@cte_max_recursion_depth to a larger value.”

在这种情况下,增加变量不会有任何改善。解决方案是仔细检查查询,直到发现输入错误为止。

尽管这只是一个小示例,但CTE可以永远递归还有其他原因:查询可能非常复杂,我们犯了逻辑错误;或数据集可能是格式错误的层次结构,并且包含意外的循环。或者,在开发时一切都正确,但是,过了一段时间,数据模型得到了发展,原本不可能的循环现在变得完全可能了,查询需要进行一些修复以免阻塞。

举一个例子,关于火箭发射的场景。

2300年,地球人满为患,鼓励人们乘坐下面的太空火箭,迁徙到附近的星球:

0d8661b02a696e75eda5961af6d755ec.png

请注意,地球的统治者没有建立任何从这些行星返回地球的方法。让我们列出所有可以从地球到达的目的地:首先找到可以直接到达的行星,然后找到可以从这些行星直接到达的行星,依此类推:

1032f10a23ecebf1542ad772b36bfc07.png

现在是2400年,地球上的人口减少了太多,统治者决定将一些移民带回去,于是他们从土星向地球发射了一枚新火箭:

791080ccceaf13d2ad7bda5f3609275a.png

让我们重复一下查询以列出可以从地球到达的所有目的地:

eda31e09535c039e157df3e16b51b5a1.png

在查询开发很久以后,数据经历了发展,现在需要进行一些修复。而且,修复它的开发人员并不知道是新的土星到地球火箭的原因。他正在寻找发现问题的方法。

因此,无论出于何种原因,您所遇到的只是上述3636错误,现在该怎么办?如果查询有数十行,您如何了解逻辑错误在哪里?如果数据可以合法地显示一个循环,那么最终您可能会修改查询,以便进行循环检测。但是在进行此类修改之前,您可能更希望先了解循环是如何形成的,涉及哪些表、列……。

为此,MySQL可以做什么来帮助我们调试问题?

从版本8.0.19开始,我使它允许任何递归CTE包含LIMIT子句。因此,递归算法将开始工作,照常运行迭代,累积行,并在这些行的数量超过LIMIT时停止。这时CTE将被视为已完成,并且不会发出任何错误。

当遇到错误3636时,我们现在要做的第一件事是添加一些LIMIT(最初10行?还是100?我们可以尝试)。然后获取查询的输出;通过查看这些数据,我们可以开始了解它们是如何生成的以及为什么产生这么多。

在我们的例子里:

6f4d16d7199494f6c64aa5780b77c93a.png

首先是火星,然后是木星,土星,地球,火星!好吧,我们看到似乎在5行之后形成循环;通过在到达的每个行星附近添加路径上的前一个行星,它变得更加清晰:

1abd3673b51d122af74a884a22a183c7.png

发现了!有一个土星到地球的火箭,它关闭了循环!这项工作的调试部分已经完成。

在本文的结尾,虽然LIMIT-in-CTE可能不会改变SQL的面貌,但我相信它几乎可以为在MySQL中操作递归CTE的每个人节省时间,这是一件非常好的事情!

一如既往,感谢您选择MySQL!

数据库迭代查询作业 emp(eno, ename, salary, mgr),其中mgr是员工领导,设计约束:要求领导的工资不能低于他的下属平均工资。(注意,这是一个递归查询) 下面是一些样例数据 CREATE TABLE dbo.Employees ( empid INT NOT NULL PRIMARY KEY, mgrid INT NULL REFERENCES dbo.Employees, empname VARCHAR(25) NOT NULL, salary MONEY NOT NULL, CHECK (empid mgrid) ); INSERT INTO dbo.Employees(empid, mgrid, empname, salary) VALUES(1, NULL, 'David', $10000.00); INSERT INTO dbo.Employees(empid, mgrid, empname, salary) VALUES(2, 1, 'Eitan', $7000.00); INSERT INTO dbo.Employees(empid, mgrid, empname, salary) VALUES(3, 1, 'Ina', $7500.00); INSERT INTO dbo.Employees(empid, mgrid, empname, salary) VALUES(4, 2, 'Seraph', $5000.00); INSERT INTO dbo.Employees(empid, mgrid, empname, salary) VALUES(5, 2, 'Jiru', $5500.00); INSERT INTO dbo.Employees(empid, mgrid, empname, salary) VALUES(6, 2, 'Steve', $4500.00); INSERT INTO dbo.Employees(empid, mgrid, empname, salary) VALUES(7, 3, 'Aaron', $5000.00); INSERT INTO dbo.Employees(empid, mgrid, empname, salary) VALUES(8, 5, 'Lilach', $3500.00); INSERT INTO dbo.Employees(empid, mgrid, empname, salary) VALUES(9, 7, 'Rita', $3000.00); INSERT INTO dbo.Employees(empid, mgrid, empname, salary) VALUES(10, 5, 'Sean', $3000.00); INSERT INTO dbo.Employees(empid, mgrid, empname, salary) VALUES(11, 7, 'Gabriel', $3000.00); INSERT INTO dbo.Employees(empid, mgrid, empname, salary) VALUES(12, 9, 'Emilia' , $2000.00); INSERT INTO dbo.Employees(empid, mgrid, empname, salary) VALUES(13, 9, 'Michael', $2000.00); INSERT INTO dbo.Employees(empid, mgrid, empname, salary) VALUES(14, 9, 'Didi', $1500.00);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值