gpt4 book ai didi

mysql - 如何跨多个表检索大型数据集并避免循环查询

转载 作者:行者123 更新时间:2023-11-29 01:03:40 27 4
gpt4 key购买 nike

首先很抱歉,如果问题已经被回答了,我在这里和谷歌上都搜索了,但找不到我的答案。这个问题不可能没有人问过,但它隐藏在所有“只使用左连接”和“存储在数组中”的答案下。
我需要加载分布在多个表中的大量数据(然后将其插入到另一个数据库引擎中,但这并不重要,我需要优化我的选择)。
表格布局如下:
表A带A_id字段
表B的a_id和B_id字段
带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?

到目前为止,我找到的唯一解决办法是:
使用慢速方式发送多个查询(当前解决方案,完成我的小测试集需要很长时间)
使用大量左联接将所有数据放在一个查询中。涉及到上千次传输大量数据,因此在客户端需要一些特殊的逻辑来再次将这些数据拆分成相应的表,因为每一行都包含其父表的内容。(我使用OOP,每个表映射到一个对象,每个对象包含彼此)。
将表A中的每个对象存储在一个数组中,然后加载所有表B,存储到一个数组中,继续执行表C。适用于小型集,但我的表大一些GB,根本不适合ram。
有没有办法避免在这样一个循环中每秒进行10000次查询?
(我正在使用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.E有1-32行,每个D.F有1-16行,每个E.E有1-16行,表F有几百万行。
问题是
最后,我对MySQL服务器进行了数千次甚至数百万次的查询,其中的生产数据库甚至不在我的本地计算机上,而是在5-10毫秒之外。即使在0.01毫秒,我也有几个小时的网络延迟。我创建了一个本地副本,因此我的受限测试集运行得更快,但是下载这样的几GB数据仍然需要很长时间。
我可以将成员表保存在RAM中,也可以是表A,这样我就可以一次一次地下载每个数据库,而不是做成千上万的查询,但是一旦在表B中,而且在内存中跟踪这将是一个真正的混乱,尤其是因为我使用PHP(至少是命令行),它使用的内存比如果我是C++程序时要多一些。活塞控制严密。所以这个解决方案也不起作用。
我可以将所有的表连接在一起,但是如果它适用于2-3个表,那么对7个表执行此操作将导致额外的巨大带宽损失,在不使用的情况下从服务器传输相同的数据数百万次(同时也使代码非常复杂,无法按适当的顺序将它们拆分回去)。
问题是:有没有办法不经常查询数据库?比如,告诉MySQL服务器一个过程或其他东西,我将需要所有这些数据集,这样我就不必重新查询每一行,所以数据库只是不断地为我吐出数据?当前的问题是我做了太多的查询,以至于脚本和数据库几乎都处于空闲状态,因为其中一个总是在等待另一个。查询本身实际上是非常快速的,基本准备好的索引int字段上的SELECT查询。
这是我过去经常遇到的MySQL问题,直到现在才真正给我带来麻烦。在当前状态下,脚本需要几个小时(如果不是几天)才能完成。没那么糟,但如果有办法我能做得更好,我会很高兴知道的。如果没有,那么好吧,我就等它完成,至少它最多运行3-4次(2-3次测试运行,让用户检查其数据是否正确转换,修复错误,再试一次,最后运行最后一次错误修复)。
提前谢谢!

最佳答案

假设您的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!

现在对于您的第二个表,您只需要一个查询就可以得到您需要加入的所有值(不是通过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_和_b,格式如下:
$result_a_and_b[INDEX]['a']
$result_a_and_b[INDEX]['b'][INDEX]

因此,对于两个查询,我们得到的结果与TABLE_a_ROWS_NUMBER+1相似(一个是第一个表的初始查询)
像这样继续做你想要的水平。
使用链接表的id查询数据库
获取CSV字符串中的id
在下一个表中使用WHERE id进行查询(11,22,33,44,55,…)
以编程方式联接
提示:您可以使用 unset()释放临时变量的内存。
我想我是在回答你的问题“有没有办法不经常查询数据库?”
注意:代码没有被测试是否有错别字,也许我漏掉了一个或两个逗号,也许没有
我相信你会明白的:)希望它有帮助!

关于mysql - 如何跨多个表检索大型数据集并避免循环查询,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17158314/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com