首先抱歉,如果问题已经得到解答,我在这里和谷歌都搜索了,但找不到我的答案。这个问题不可能没有被问到,但它隐藏在所有“只需使用 LEFT JOIN”和“将其存储在数组中”的答案之下。
我需要加载分布在多个表中的大量数据(然后将其插入另一个数据库引擎,但这并不重要,我需要优化我的 SELECT)。
表格布局如下所示:
带有 a_id 字段的表 A 带有 a_id 和 b_id 字段的表 B 带有 b_id 和 c_id 字段的表 C ...(像这样再进行 3-4 级)。
我目前以这种方式访问数据(伪代码):
query1 = SELECT ... FROM TableA WHERE something=$something
foreach query1 as result1:
query2 = SELECT ... FROM TableB WHERE b_id=result1.a_id
foreach query2 as result2:
query3 = SELECT ... FROM TableC WHERE bc_id=result2.b_id
foreach query3 as result3:
// Another few levels of this, see the millions of SELECTs coming?
到目前为止,我发现的唯一解决方案是:
- 使用慢速方式并发送多个查询(当前解决方案,完成我的小测试集需要很长时间)
- 使用大量的 LEFT JOIN 在一个查询中获取所有数据。涉及数千次传输大量数据,因此在客户端有一些奇特的逻辑将其再次拆分为适当的表,因为每一行都将包含其父表的内容。(我使用 OOP,每个表都映射到一个对象,每个对象都包含彼此)。
- 将表 A 中的每个对象存储在一个数组中,然后加载所有表 B,存储到一个数组中,然后在表 C 上继续。适用于小型集合,但我的是几 GB,根本不适合 ram。
有没有办法避免在这样的循环中每秒执行 10k 次查询?
(我正在使用 PHP,从 MySQL 转换为 MongoDB,这样可以更好地处理嵌套对象,如果这有帮助的话)
编辑:似乎对我要做什么以及为什么有些困惑。我将尝试更好地解释:我需要批量转换为新结构。新结构效果很好,甚至不用费心去看。我正在从头开始改造一个非常古老的网站,并选择 MongoDB 作为我的存储引擎,因为我们有大量这样的嵌套数据,而且它对我来说效果很好。切换回 MySQL 对我来说甚至不是一个选择,新的结构和代码已经很成熟,我已经为此工作了大约一年。我不是在寻找优化当前架构的方法,我做不到。数据是这样的,我需要读取整个数据库。一次。然后我就完成了。
我需要做的就是从旧网站导入数据,处理并转换它,以便我可以将其插入到我们的新网站中。MySQL 出现了:旧站点是一个非常普通的 PHP/MySQL 站点。我们有很多桌子(实际上大约有 70 张左右)。我们的用户不多,但每个用户都有大量数据,分布在 7 个表上。
我目前所做的是循环每个用户(1 个查询)。对于这些用户中的每一个(70k),我加载表 A,其中每个用户包含 10-80 行。然后,我在 A 的每个循环上查询表 B(因此,10-80 乘以 70k),其中每个 A 包含 1-16 行。然后是表 C,每个 B 包含 1-4 行。我们现在是 4 *80*70k 查询要做。然后我有 D,每个 C 有 1-32 行。E 每个 D 有 1-16 行。F 每个 E 有 1-16 行。表 F 有几百万行。
问题是
我最终对 MySQL 服务器进行了数千甚至数百万次查询,其中生产数据库甚至不在我的本地计算机上,而是在 5-10 毫秒之外。即使在 0.01 毫秒,我也有几个小时的网络延迟。我创建了一个本地副本,因此我的受限测试集运行得更快,但下载这样的几 GB 数据仍然需要很长时间。
我可以将成员表保存在 RAM 中,也可以保存在表 A 中,这样我就可以一次下载每个数据库,而不是进行数千次查询,但是一旦在表 B 中,在内存中跟踪它就会变得一团糟,尤其是因为我使用 PHP(至少是命令行),与我可以严格控制 RAM 的 C++ 程序相比,它使用的内存要多一些。所以这个解决方案也不起作用。
我可以将所有表连接在一起,但如果它适用于 2-3 个表,则对 7 个表执行此操作会导致额外的巨大带宽损失,从服务器传输相同数据数百万次而不使用(同时也使代码以适当的顺序将它们拆分回来真的很复杂)。
问题是:有没有办法不经常查询数据库?就像,告诉 MySQL 服务器一个过程或什么我需要按这个顺序所有这些数据集,这样我就不必重新查询每一行,所以数据库只是不断地为我吐出数据?当前的问题是我做了太多查询,以至于脚本和数据库几乎都处于空闲状态,因为一个总是在等待另一个。查询本身实际上是对索引 int 字段非常快速的基本准备 SELECT 查询。
这是我过去在使用 MySQL 时经常遇到的问题,直到现在才真正给我带来麻烦。在当前状态下,脚本需要几个小时甚至几天才能完成。这不是那么糟糕,但如果有办法我可以做得更好,我会很高兴知道。如果没有,那好吧,我就等它完成,至少它最多会运行 3-4 次(2-3 次测试运行,让用户检查他们的数据是否正确转换,修复错误,再试一次,然后最后运行最后的错误修正)。
提前致谢!