与 ID 数组相比,检测数据库中要删除的字段的最佳方法

Posted

技术标签:

【中文标题】与 ID 数组相比,检测数据库中要删除的字段的最佳方法【英文标题】:Optimal way to detect fields to delete in database comparing to an array of IDs 【发布时间】:2018-08-10 17:50:34 【问题描述】:

我正在尝试执行以下操作。

我正在使用 Web 服务咨询外部数据库。 Web 服务的作用是为我提供客户使用的 ERP 系统中的所有产品。由于服务器和连接都不是很快,所以我决定做的基本上是在我的 Web 服务器上同步数据库,并在那里处理大部分操作,这样网站才能顺利运行。

一切正常我只需要最后一步来确保网站上的库存与 ERP 上可用的库存相匹配。唯一的问题是他们(客户)删除了 ERP 系统上的某些内容。

目前我正在考虑如果我没有在 Web 服务结果中收到产品,那么从我的 Products 表中删除产品的理想策略是什么(最少的资源和时间)。

所以我基本上有以下流程:

    我查询所有产品的 Web 服务,给它们一些格式并将它们存储在一个数组中。最终大小约为 600 个索引。 然后我做的是我做一个foreach 循环并有以下子流程。 我查询我的数据库以检查product_id 是否存在。 如果该产品存在,我只需使用最新信息、库存数据对其进行更新。 如果产品不存在,我就插入它。

因此,我正在考虑执行以下操作,但我认为这不是理想的方式:

执行SELECT * FROM Products 并生成一个包含所有产品的数组。 在结果数组中执行foreach 循环,并在每个循环中扫描 ERP 数组以检查特定产品是否存在。如果不是,我删除它,如果是,我继续下一个产品。

现在考虑到在前面的所有步骤之后,这将涉及几个嵌套的foreach,我有点担心它可能会消耗太多内存并且需要更长的处理时间。

我在想也许像array_diffarray map 这样的东西可以解决这个问题,但我对这些功能没有真正的经验,而且两个数组的结构差异很大,所以我不确定是否会很容易工作。

你们会推荐什么?

【问题讨论】:

另一个选项是在processing...的数据库表中有一个新字段...将整个表行设置为processing=1,然后在更新/插入时将处理设置回零(如它正在处理中)。然后最后,任何产品仍然保留为processing = 1,您可以批量删除。不需要数组,也不需要用于删除的 foreachs。您还可以使用 product_status 等另一个字段来保留已删除的行,并将它们设置为零或“已删除”(如果是枚举)。 听起来不错,我实际上想过用同步日期来做这件事,但这很难满足条件。我认为您可以将该选项作为答案发布:) 不,这是一个相当广泛的问题,而且有自以为是的回答......所以我宁愿把它作为评论:) Do a SELECT * FROM Products and generate an array that has all the products 您只需要 ID,不需要完整数据。在您进行更新时,只需从您的 ID 数组中删除该 ID,剩下的任何内容都可以删除。 您可以创建一个staging 表,其中包含来自网络服务器的数据。然后执行 2 个命令。第一个将根据staging 表更新每个产品。第二个将插入不存在的产品。在我看来更快更容易。 【参考方案1】:

其实很简单:

SELECT id FROM Products

然后你有一个产品 ID 数组,例如:

[123,5679,345]

然后当你进行更新或插入时,从数组中删除 id。

[用于更新]我查询我的数据库以检查 product_id 是否存在。

现在这是多余的。

有几种方法可以从数组中删除值(当您进行更新时),我可能会这样做。

 if(false !== ($index = array_search($data['product_id'],$myids)))
   //note the !== type comparison because array_search can return 0 for the first index, we must check for boolean false.
   //find the index of the product id in our list of id's from local DB
     unset($myids[$index]);
     //If our incoming product_id is in the local list we Do Update
 else
     //Otherwise we Do Insert
 

正如我在上面进行更新/插入时提到的,您不再需要检查 ID 是否存在,因为您已经通过数据库中的 ID 数组知道这一点。仅此一项就可以为您节省 (n) 个查询(apx 600)。

如果你有剩余的 ID,那就很简单了。

  //I wouldn't normally concatenate variables into SQL, in this case it's a list of int IDs from the database.
  //you can of course come up with a loop to make it a prepared statement if you wish, but for the sake of simplistically, I'll leave that as an exercise for another day..
  'DELETE FROM Products WHERE id IN('.implode(',', $myids).')'

因为您在更新时取消了这些设置,所以唯一剩下的就是不再存在的产品。

结论:

您别无选择(除了重复键查询或忽略异常)然后提取产品 ID。您已经在逐行执行此操作。所以我们可以有效地用一块石头杀死2只鸟。

如果您需要更多数据而不是 ID,例如,您在进行更新之前检查产品是否已更改。然后将这些数据提取出来,但我建议使用 PDO 和 FETCH_GROUP 选项。我不会详细介绍它,但要说它可以让您轻松地以这种方式构建数组:

 [product_id => [ product_name, product_price etc..]];

product_id 基本上是行数据的嵌套数组的键,这将使查找更容易。

这样你就可以这样查找了。

   //then instead of array_search
  //if(false !== ($index = array_search($data['product_id'],$myids)))

  if(isset($myids[$data['product_id']]))
     unset($myids[$data['product_id']]);
      //do your checks, then your update
  else
      //do inserts
  

参考资料:

http://php.net/manual/en/function.array-search.php

array_search — 在数组中搜索给定值,如果成功则返回第一个对应的键

警告 此函数可能返回布尔值 FALSE,但也可能返回计算结果为 FALSE 的非布尔值。请阅读有关布尔值的部分以获取更多信息。使用 === 运算符来测试这个函数的返回值。

更新

还有另一种非常好的方法可以做到这一点,那就是添加一个名为 sync_date 的字段,现在当您执行插入或更新时,请将 sync_date 设置为当前数据。

这样,当您完成后,可以删除同步日期早于今天的那些产品。在这种情况下,最好在执行此操作时将时间缓存起来,以便您知道确切的时间。

$time = data('Y-m-d H:i:s'); //or time() if you prefer timestamp
//use this same variable for the whole coarse of the script.

那你就可以了

 'DELETE from products WHERE sync_time != $time'

这实际上可能会更好一些,因为它具有更多的实用性。上次运行它是什么时候,现在你知道了。

【讨论】:

我最终实现了array_search,它成功了,问题是日期可以按秒变化,所以我更喜欢左边的 ID。我认为它保证不会留下任何人。顺便说一句,好答案! :)

以上是关于与 ID 数组相比,检测数据库中要删除的字段的最佳方法的主要内容,如果未能解决你的问题,请参考以下文章

MongoDb:将模型字段从字符串数组修改为引用另一个模型的 id 数组的最佳方法是啥?

删除内部字段数组 MongoDb 的元素 [重复]

element vue Array数组和Map对象的添加与删除

Rails - 如何将 id 数组作为隐藏字段的参数传递?

jqGrid中要添加自定义列,并且支持自定义数据对应显示!

可以对主键使用字符值吗?