首先对不起,如果问题已经得到解答,我在这里搜索了谷歌并且无法找到我的答案。这个问题可能还没有被问到,但它隐藏在所有的&#34之下;只需使用LEFT JOIN"并且"将它存储在数组中"答案。
我需要在多个表中加载大量数据(然后将其插入另一个数据库引擎,但这并不重要,我需要优化我的SELECT)。
表格布局如下所示:
表A带有a_id字段 表B带有a_id和b_id字段 表C带有b_id和c_id字段 ......(另外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?
到目前为止我找到的唯一解决方案是:
有没有办法避免在这样的循环中每秒进行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中包含每行的1-4行。我们现在在4 * 80 * 70k查询要做。然后我为每个C. E设置D,1-32行,每个D为1-16行.F每个E为1-16行。表F有几百万行。
问题是
我最终对MySQL服务器进行了数千次(如果不是数百万次)查询,其中生产数据库甚至不在我的本地机器上,而是在5-10ms之外。即使在0.01毫秒,我也只有几个小时的网络延迟。我创建了一个本地副本,因此我的受限测试集运行速度非常快,但是下载几GB这样的数据还需要很长时间。
我可以将成员表保存在RAM和表A中,这样我就可以一次性下载每个数据库,而不是进行数千次查询,但是一旦在表B中进行,那么跟踪这将是一个真正的混乱在内存中,特别是因为我使用PHP(至少是命令行),它使用的内存比C ++程序要多得多,因为我可能有严格的RAM控制。所以这个解决方案也不起作用。
我可以将所有表连接在一起,但如果它适用于2-3个表,那么对7个表执行此操作将导致额外的巨大带宽损失,从服务器传输相同数据数百万次而无需使用(同时也使代码真的很复杂,以适当的顺序将它们拆分)。
问题:有没有办法不经常查询数据库?比如,告诉MySQL服务器有一个程序或者我需要这个顺序的所有这些数据集,所以我不必每行重新查询一次,所以数据库只是不断地为我吐出数据?当前的问题只是我做了很多查询,脚本和数据库几乎都处于空闲状态,因为一个人总是在等待另一个。查询本身实际上是非常快速的,对索引的int字段进行基本准备的SELECT查询。
这是我过去常常使用MySQL的问题,直到现在才真正给我带来麻烦。在当前状态下,如果不是几天完成,脚本需要几个小时。它不是那么糟糕,但如果我能做得更好,我会很高兴知道。如果没有,那么好吧,我只是等待它完成,至少它将运行最多3-4次(2-3次测试运行,让用户检查他们的数据是否正确转换,修复错误,再试一次,以及最后一次错误修正的运行。)
提前致谢!
答案 0 :(得分:0)
假设您的7个表由ID链接,请执行以下操作
第一次查询
'SELECT * FROM table_a WHERE a_id IN (12,233,4545,67676,898999)'
// store the result in $result_of_first_query
然后执行foreach并在逗号分隔变量(csv)中选择要在下一个查询中使用的ID
foreach($result_of_first_query as $a_row_from_first_table)
{
$csv_for_second_query = $csv_for_second_query.$a_row_from_first_table['b_id'].",";
}
$csv_for_second_query = trim($csv_for_second_query,", "); // problem is we will have a lot of duplicate entries
$temp_arr = array(); // so lets remove the duplicates
$temp_arr = explode(",",$csv_for_second_query); // explode values in array
$temp_arr = array_unique($temp_arr); // remove duplicates
$csv_for_second_query = implode(",",$temp_arr); // create csv string again. ready!
现在为你的第二个表,只需1个查询就可以获得JOIN所需的所有值(不是通过mysql,我们将用php执行此操作)
第二次查询
'SELECT * FROM table_b where a_id IN ('.$csv_for_second_query.')'
// store the result in $result_of_second_query;
然后我们只需要以编程方式连接两个数组。
$result_a_and_b = array(); // we will store the joined result of every row here
// lets scan every row from first table
foreach($result_of_first_query as $inc=> $a_row_from_first_table)
{
// assign every row from frist table to result_a_and_b
$result_a_and_b[$inc]['a']=$a_row_from_first_table;
$inc_b=0; // counter for the joins that will happen by data from second table
// for every row from first table we will scan every row from second table
// so we need this nested foreach
foreach($result_of_second_query as $a_row_from_second_table)
{
// are data need to join? if yes then do so! :)
if($a_row_from_first_table['a_id']==$a_row_from_second_table['a_id'])
{
$result_a_and_b[$inc]['b'][$inc_b]=$a_row_from_second_table; // "join" in our "own" way :)
++$inc_b; // needed for the next join
}
}
}
现在我们有这个格式的数组$ result_a_and_b:
$result_a_and_b[INDEX]['a']
$result_a_and_b[INDEX]['b'][INDEX]
所以对于2个查询,我们得到一个类似于TABLE_A_ROWS_NUMBER + 1的结果(一个是第一个表的初始查询)
像这样继续做你想要的多个级别。
提示:您可以使用unset()
释放临时变量的内存。
我相信我在你的问题中回答“有没有办法不经常查询数据库?”
注意:代码没有测试错别字,也许我错过了逗号或两个 - 或者可能不是
我相信你可以得到点:)希望它有所帮助!
答案 1 :(得分:0)
谢谢大家的回答。我得出结论,我实际上无法以其他方式做到这一点。
我自己的解决方案是在localhost上设置副本数据库(如果快照足够,则只是副本)。这样,它可以减少网络延迟,并允许脚本和数据库达到100%的CPU使用率,而且如果不完全重新组织我的脚本,它似乎是最快的。
当然,这仅适用于一次性脚本。处理这个问题的正确方法是我现在得到的两个答案的混合:在线程中使用多个无缓冲连接,并逐个处理(从表A加载50行,在ram中存储,加载与表A相关的所有数据)表B,存储在RAM中,然后处理所有这些并继续从表A)。
无论如何,谢谢你的答案!