【发布时间】:2021-12-24 03:41:32
【问题描述】:
我使用 MySql 后端来存储我们在单页 Angular 应用程序中使用的数据。我们从服务器发送数据并将其存储在 Chrome 内的 IndexedDB 中。我们有相当多的信息表,但特别是有一个包含大约 20k 个条目和接近 300 个字段的表。当我们最初开发平台时,我们运行一个标准的 SQL 查询,然后我们迭代结果以构建一个 JSON 语句来返回。这个过程大约需要 35 秒,所以我们一直在寻求改进。从那以后,我一直在测试 MySQL 中更多特定的 JSON 工具,比如 json_array 和 json_arrayagg。我发现我已经从一个迭代过程很慢的非常快的 select 语句变成了一个不需要迭代的非常慢的 select 语句。总而言之,它所花费的时间没有任何改进。我可以使用更有效的流程来加快速度吗?作为参考,迭代是在 PHP 中完成的,以防那里可以使用的东西。
好的,编辑以解决一些 cmets。我们正在向客户提供这么多的数据。我们实际上有几个这种大小的表,我们在前端使用 ag-grid,以便用户可以过滤、排序、分组等。所以我们在登录时在本地加载所有数据,并在初始加载后提供一个快速的环境。初始负载是我希望改进的。对于更多的上下文,这些表之一是产品数据库。我们的用户将进入数据库,并可以按任何可用字段进行过滤。筛选依据的选项由网格中已有的数据生成。这只是一个例子,但长话短说,我们需要本地数据。
我通过记录 sql 语句周围的时间戳以及处理 sql 结果的 while 循环之前和之后来测量时间。
在创建 JSON 后返回的时间很短(几秒钟)。
我们实际上是根据运行它的模块动态构建 sql 语句,但作为参考,这里是 select 的构建方式。大模块显然会列出每个字段:
$select = " SELECT json_objectagg(json_object(
'docType' VALUE 'EXOAD_BidGroup',
'date_modified' VALUE exoad_bidgroup.date_modified ABSENT ON NULL,
'name' VALUE exoad_bidgroup.name ABSENT ON NULL,
'deleted' VALUE exoad_bidgroup.deleted ABSENT ON NULL,
'id' VALUE exoad_bidgroup.id ABSENT ON NULL,
'_id' VALUE exoad_bidgroup._id ABSENT ON NULL,
'isChanged' VALUE '0')) ";
最初的过程是一个基本的选择语句,然后我们使用以下内容对结果进行迭代,以在返回 JSON 之前拼凑起来:
while ($row = $GLOBALS['db']->fetchByAssoc($dbResult)) {
$id = $row['id'];
$singleResult = array();
$singleResult['docType'] = $module;
$singleResult['_id'] = $row['id'];
$singleResult['isChanged'] = 0;
$parentKeyValue = '';
if ($isHierarchical == 'Yes') {
if (isset($row[$parentModuleKey]) && $row[$parentModuleKey] != ''){
$parentKeyValue = $row[$parentModuleKey];
} else {
continue;
}
}
foreach ($row as $key => $value) {
if ($value !== null && trim($value) <> '' && $key !== 'user_hash') { //put this in tenant utils
$singleResult[$key] = html_entity_decode($value, ENT_QUOTES);
}
}
$result_count++;
if ($isHierarchical == 'Yes' && $parentKeyValue != '') {
if (!isset($output_list[$module . '-' . $parentKeyValue])) {
$GLOBALS['log']->info('hier module key -->> ' . $module . '-' . $parentKeyValue);
$output_list[$module . '-' . $parentKeyValue] = array();
}
$output_list[$module . '-' . $parentKeyValue][$id] = $singleResult;
} else {
$output_list[$id] = $singleResult;
}
}
如果我可以提供任何其他详细信息,请告诉我。
另一个编辑...
时间肯定是在 while 语句中的 foreach 循环中花费的。我没有确切的数字,但如果没有那个 foreach,整个过程将下降到几秒钟。但是......这就是将数据格式化为 JSON 的方式,因此任何关于加速该部分的想法都是我正在寻找的。我的猜测是它不存在,但如果有一些 php 函数可以获取每个结果行并将数据转换为 json 而无需遍历每个字段,那就太好了。
【问题讨论】:
-
您正在向客户端交付价值 20,000 行 * 300 列的 JSON?
-
您是仅测量 JSON 的生成,还是同时测量交付?您的 MySQL 到 JSON 管道是什么样的,您使用的是 DTO 还是普通的旧数组?
-
可以是任何东西,你应该发布你的代码
-
从您的描述中无法说出瓶颈在哪里。是PHP代码吗? PHP 代码能写得更高效吗?大概。但是您还没有显示代码,所以没有人可以提出改进它的建议。无论如何,准备如此庞大的结果集无论如何都需要一些时间。
-
您真的需要一次性获取大量数据吗?为什么不只是在需要时获取所需的数据呢?那将是最有效的。您还说您遍历数据,这是有原因的吗?当你迭代它时,你到底在做什么?您可以将整个结果转换为 json 而无需添加您自己的迭代。但正如其他人所说,我们需要更多详细信息(如您的代码等)