【问题标题】:Fastest way to check elements of large array not present in MySQL检查 MySQL 中不存在的大型数组元素的最快方法
【发布时间】:2016-12-10 23:45:47
【问题描述】:

我需要检查数组的哪些元素不存在于 MySQL 表中。 我正在进行个别查询,但它正在炸毁我的 MySQL。

【问题讨论】:

  • 使用带有NOT IN的查询。
  • 多大?您可以使用 `NOT IN` 子句
  • 或者创建一个将数组作为数据的表,并使用外连接查看缺少的内容。或不存在。
  • @Machavity,这不是重复的,而是相反的问题。
  • @BillKarwin 啊,原来如此。撤回它

标签: php mysql arrays


【解决方案1】:

此线程上的几个答案和 cmets 误解了 OP 的要求。 OP 没有要求您的 PHP 数组中不存在的 MySQL 表中的值。 OP 要求相反:PHP 数组中的值不存在于 MySQL 表中。

将值加载到临时表中。我假设一个包含整数的变量$array。这是一次插入多行的代码。如果这会生成比max_allowed_packet 更长的 INSERT 语句,则分批加载数组。

$pdo->query("CREATE TEMPORARY TABLE values_to_search (value INT PRIMARY KEY)");

$sql = "INSERT INTO values_to_search (value) VALUES " 
    . implode(",", array_fill(1, count($array), "(?)"));
$stmt = $pdo->prepare($sql);
$stmt->execute($array);

对正在搜索的表进行外部联接。如果不匹配,则该值不存在。

$sql = "SELECT v.value
    FROM values_to_search AS v
    LEFT OUTER JOIN mytable t ON v.value = t.value
    WHERE t.value IS NULL";
$stmt = $pdo->query($sql);
$results = $stmt->fetchAll(PDO::FETCH_NUM);

【讨论】:

  • 您好,感谢您的回答。我使用这个解决方案,它可以工作,但仍然需要 140 秒才能完成 17000 行的外部连接。这正常吗?
  • 您应该在要加入的 value 列上有一个索引,但即使没有索引,我认为 140 秒也太长了。您的服务器可能有问题。例如,它是交换吗?让系统管理员检查一下。
  • 我使用 3 核和 4Gb 内存的 VPS,它将 17k 行与 57k 进行比较,现在需要 160 秒。
  • 索引呢?
  • 我添加了索引,现在需要 200 多秒。只有临时表有索引,因为另一个来自 prestashop,我没有更改它
【解决方案2】:

如果有大量值,请将它们加载到临时表中并在其上进行左连接。

  $sql =  "select t.* from temptable t left join foo f on f.id = t.id where f.id is null";

【讨论】:

  • 如果你正在使用VARCHAR 值,你也需要转义,你不能只是连接。
  • @BillKarwin 哎呀!感谢您的提醒,更正查询
  • @BillKarwin 全部更新以反映 OP 所需的结果!
【解决方案3】:

您可以结合使用array_diff()select distinct ... 来快速获得所需的结果:

$array = [1,2,3,4,5,6,7,8,9,0];
$mysql_array = [];
// $mysql_array = [3,7,9]; // uncomment this if you wish to test without DB data

$sql = 'select distinct id as id from mysql_table';

// mysql querying functions or PDO or whatever

while(looping results)
{
    $mysql_array[] = $row['id'];
}

print_r(array_diff($array, $mysql_array));

// If using $mysql_array = [3,7,9]; test data then you will get this result
/*
Array
(
    [0] => 1
    [1] => 2
    [3] => 4
    [4] => 5
    [5] => 6
    [7] => 8
    [9] => 0
)
*/

重要提示:

如果distinct 查询返回一百万条或更多记录,上述方法可能会耗尽 PHP 脚本的可用内存。

【讨论】:

  • 这是个坏主意,因为它会在 PHP 脚本中消耗无限量的内存,具体取决于 MySQL 表中不同 id 的数量。这可能是数十亿美元。
  • @BillKarwin true,但 OP 没有指定他们的表格大小。我选择在这里留下这个答案,因为做事的方式总是不止一种。不过,我会记下您指出的内存问题。谢谢!
【解决方案4】:

我建议一个替代解决方案,基于 OP 的上下文意味着要探索 所有 已注册的值。
编辑:查看@MonkeyZeus 答案 I意识到他们可能不止一次注册,所以我在下面的查询中添加了DISTINCT

可能会更快,因为它只使用一个简单的查询...但不确定,因为它还会迭代一个巨大的数组。
另一方面,它不会导致内存问题,因为只使用了fetch(),而不是fetchAll()

假设value 是相关列的名称,$searched_values 是包含搜索值的(简单)数组:

// make known values and searched values sorted the same
$stmt = $pdo->query('SELECT DISTINCT value FROM mytable ORDER BY value');
sort($searched_values);

$unknown_values = [];
$known_value = NULL;

foreach ($searched_values as $searched_value) {
    if (!$known_value) {
        // previous known_value already consumed (or end), try to get next one 
        $known_value = $stmt->fetch()['value'];
    }
    if ($known_value == $searched_value) {
        // consume current known_value
        $known_value = NULL;
    } else {
        // otherwise current $searched_value is unknown, register it:
        $unknown[] = $searched_value;
    }
}

【讨论】:

    猜你喜欢
    • 2023-03-17
    • 2012-05-07
    • 2013-12-26
    • 2011-10-20
    • 1970-01-01
    • 2021-05-26
    • 2012-05-07
    • 2012-12-16
    相关资源
    最近更新 更多