PHP脚本可将数据从一个表插入到另一个表(从数据到大表)

时间:2018-09-12 08:43:10

标签: php mysql

我创建了一个PHP脚本,该脚本正在将数据从一个表移动到另一个表。

背景

我正在将两个数据库合并为一个大型数据库。这些数据库有一些类似的表,例如venue表。我将场所表合并到了新数据库中。

我有多个具有外键venue_id的表,但是显然因为我已经将2个场所表合并在一起,venue_id的位置现在可能是不同的场所。我创建此功能是为了获得正确的场地。

function get_tracking_venue_id($old_venue_id) {
    $db_tracking = new PDO("mysql:host=localhost;dbname=tracking", 'username', 'password');
    $db_tracking->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

    $db_intelli_sense = new PDO("mysql:host=localhost;dbname=intelli_sense", 'username', 'password');
    $db_intelli_sense->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

    $tracking_venue_table = $db_tracking->prepare("
        SELECT name FROM venue WHERE id = :venue_id
    ");
    $tracking_venue_table->bindParam(':venue_id', $old_venue_id);
    $tracking_venue_table->execute();
    $venue_name = $tracking_venue_table->fetchColumn();

    $intelli_sense_venue_table = $db_intelli_sense->prepare("
        SELECT id FROM venue WHERE name = :venue_name
    ");
    $intelli_sense_venue_table->bindParam(':venue_name', $venue_name);
    $intelli_sense_venue_table->execute();
    $venue_id = $intelli_sense_venue_table->fetchColumn();

    return $venue_id;
}

该功能不是仅能帮助解释为什么我不得不使用PHP将数据从一个表插入到具有外键venue_id的另一个表中的问题

问题是我要移至的表具有超过300万条记录。因此,脚本不断崩溃,并显示内存不足错误。我花了几个小时尝试解决此问题,但我认为服务器的内存不足。

fectchAll()引起了内存不足错误

$fetch_summary_data = $db_tracking->prepare("SELECT * FROM table");
$fetch_summary_data->execute();
$tracking_summary_data_array = $fetch_summary_data->fetchAll();

我决定将代码包装在for循环中,一次仅获得500,000条记录,这停止了内存不足错误。我现在收到此错误消息

PHP Warning:  Error while sending QUERY packet. PID=526 in /home/ubuntu/sql_scripts/tracking_wifi_merge/scripts/php_scripts/insert_tracking_daily_stats_venue_unique_device_uuids_per_hour_script.php on line 23
PHP Fatal error:  Uncaught PDOException: SQLSTATE[HY000]: General error: 2006 MySQL server has gone away in /home/ubuntu/sql_scripts/tracking_wifi_merge/scripts/php_scripts/insert_tracking_daily_stats_venue_unique_device_uuids_per_hour_script.php:23

此脚本需要花费几个小时才能运行,这就是为什么我对运行它感到厌烦,然后决定中途崩溃。如果有人知道原因或有更好的解决方案来插入数据,我将很乐意听到。

完整的脚本可以在下面找到:

<?php

$db_tracking = new PDO("mysql:host=localhost;dbname=tracking", 'username', 'password');
$db_tracking->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

$db_intelli_sense = new PDO("mysql:host=localhost;dbname=intelli_sense", 'username', 'password');
$db_intelli_sense->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

/**
 * Fetch all the tracking drones
 */

$max = 1;

$get_id = $db_tracking->prepare("SELECT id FROM daily_stats_venue_unique_device_uuids_per_hour ORDER BY id ASC LIMIT 1");
$get_id->execute();

$limit_lower  = 0;
$limit_higher = $limit_lower + 500000;

for ($count = 0; $count < $max; $count++) {
    $fetch_summary_data = $db_tracking->prepare("SELECT * FROM daily_stats_venue_unique_device_uuids_per_hour ORDER BY id ASC LIMIT " . $limit_lower . ", " . $limit_higher);
    $fetch_summary_data->execute();
    $tracking_summary_data_array = $fetch_summary_data->fetchAll();

    if (count($tracking_summary_data_array) != 0) {
        echo "hi";

        foreach($tracking_summary_data_array as $tracking_summary_data) {

            // Get the new venue ID
            $venue_id = get_tracking_venue_id($tracking_summary_data['venue_id']);
            if(empty($venue_id)) {
                $venue_id = 0;
            }

            /**
             * Insert the data in the zone table 
             */
            $insert_tracking_summary_data = $db_intelli_sense->prepare("
                INSERT INTO `tracking_daily_stats_venue_unique_device_uuids_per_hour` (day_epoch, day_of_week, hour, venue_id, device_uuid, device_vendor_id, first_seen, last_seen, is_repeat)
                VALUES (:day_epoch, :day_of_week, :hour, :venue_id, :device_uuid, :device_vendor_id, :first_seen, :last_seen, :is_repeat)
            ");

            $insert_tracking_summary_data->bindParam(':day_epoch', $tracking_summary_data['day_epoch']);
            $insert_tracking_summary_data->bindParam(':day_of_week', $tracking_summary_data['day_of_week']);
            $insert_tracking_summary_data->bindParam(':hour', $tracking_summary_data['hour']);
            $insert_tracking_summary_data->bindParam(':venue_id', $venue_id);
            $insert_tracking_summary_data->bindParam(':device_uuid', $tracking_summary_data['device_uuid']);
            $insert_tracking_summary_data->bindParam(':device_vendor_id', $tracking_summary_data['device_vendor_id']);
            $insert_tracking_summary_data->bindParam(':first_seen', $tracking_summary_data['first_seen']);
            $insert_tracking_summary_data->bindParam(':last_seen', $tracking_summary_data['last_seen']);
            $insert_tracking_summary_data->bindParam(':is_repeat', $tracking_summary_data['is_repeat']);

            $insert_tracking_summary_data->execute();
        }

        $limit_lower = $limit_lower + 500001;
        $limit_higher = $limit_higher + 500000;
        $max = $max + 1;
    }
}


function get_tracking_venue_id($old_venue_id) {
    $db_tracking = new PDO("mysql:host=localhost;dbname=tracking", 'username', 'password');
    $db_tracking->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

    $db_intelli_sense = new PDO("mysql:host=localhost;dbname=intelli_sense", 'username', 'password');
    $db_intelli_sense->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

    $tracking_venue_table = $db_tracking->prepare("
        SELECT name FROM venue WHERE id = :venue_id
    ");
    $tracking_venue_table->bindParam(':venue_id', $old_venue_id);
    $tracking_venue_table->execute();
    $venue_name = $tracking_venue_table->fetchColumn();

    $intelli_sense_venue_table = $db_intelli_sense->prepare("
        SELECT id FROM venue WHERE name = :venue_name
    ");
    $intelli_sense_venue_table->bindParam(':venue_name', $venue_name);
    $intelli_sense_venue_table->execute();
    $venue_id = $intelli_sense_venue_table->fetchColumn();

    return $venue_id;
}

1 个答案:

答案 0 :(得分:0)

从目标数据库中选择所有数据,这是导入所必需的,并且可能导致外键错误。然后在源数据库上创建临时表,在其中插入选定的数据并添加带有已转换键的列。之后,您可以以一种不会在目标数据库中引起任何错误的方式从源数据库中获取所有数据。这样,您可以以更少的内存更快地导入数据。不要在事务内执行此操作,因此,如果事务失败,则不必重新开始。

另一种方法是在目标数据库上创建表而不受限制,出于性能考虑,我建议使用引擎“ MEMORY”或“ MYISAM”。然后按原样导入数据,因此无需转换约束或所有内容。即使有数百万条记录,这也应该非常快。完成后,运行更新命令将外键设置为正确的外键。然后,您可以使用单个小查询移动数据。另外,您可以编写事件或设置cron以在每次迭代中仅移动一部分数据。