【问题标题】:Transfer data into optimized MySQL tables from "raw" tables in cron with php使用 php 从 cron 中的“原始”表将数据传输到优化的 MySQL 表中
【发布时间】:2011-08-07 17:44:43
【问题描述】:

我正在与 MLS 房地产上市提供商 (RETS) 合作。每 48 小时,我们将在 cron 作业中将数据从他们的服务器提取到 SQL 数据库。我负责编写一个 php 脚本,该脚本将在来自远程服务器的数据转储到我们的“原始”表后运行。在这些原始表中,所有列都是VARCHAR(255),我们希望将数据移动到优化表中。在我将脚本发送给负责设置 cron 作业的人之前,我想知道是否有更有效的方法可以做到这一点,以免我看起来很傻。

这就是我正在做的事情:

共有 8 个表,4 个原始表和 4 个优化表 - 都在同一个数据库中。原始表列名称是非描述性的,例如 c1、c2、c2、c4 等。这是有意的,因为每列中的数据可能会发生变化。原始表列名称通过 php 映射到正确的优化表列,如下所示:

$tables['optimized_table_name1']['raw_table'] = 'raw_table_name1';
$tables['optimized_table_name1']['data_map'] = array(
    'c1'    =>  array( // <--- "c1" is the raw table column name
                    'column_name'   =>  'id',
                    // I use other values for table creation,
                    // but they don't matter to the question.
                    // Just explaining why the array looks like this
                    //'type'        =>  'VARCHAR',
                    //'max_length'  =>  45,
                    //'primary_key' =>  FALSE,
                    // etc.
                ),
    'c9'    =>  array('column_name' =>  'address'),
    'c25'   =>  array('column_name' =>  'baths'),
    'c2'    =>  array('column_name' =>  'bedrooms') //etc.
    );

我对 4 个表中的每一个都做同样的事情:SELECT * FROM 原始表,读取配置数组并创建一个巨大的 SQL 插入语句,TRUNCATE 优化表,然后运行 ​​INSERT 查询.

foreach ($tables as $table_name => $config):

$raw_table  =   $config['raw_table'];
$data_map   =   $config['data_map'];
$fields =   array();
$values =   array();
$count      =   0;

// Get the raw data and create an array mapped to the optimized table columns.
$query = mysql_query("SELECT * FROM dbname.{$raw_table}");

while ($row = mysql_fetch_assoc($query))
{
    // Reading column names from my config file on first pass
    // Setting up the array, will only run once per table
    if (empty($fields))
    {
        foreach ($row as $key => $val)
        {// Produces an array with the column names
            $fields[] = $data_map[$key]['column_name'];
        }
    }
    foreach ($row as $key => $val)
    {// Assigns data to an array to be imploded later
        $values[$count][] = $val;
    }
    $count++;
}

// Create the INSERT statement string
$insert = array();
$sql = "\nINSERT INTO `{$table_name}` (`".implode('`,`', $fields)."`) VALUES\n";
foreach ($values as $key => $vals)
{
    foreach ($vals as &$val)
    {
        // Escape the data
        $val = mysql_real_escape_string($val);
    }
    // Using implode for simplicity, could avoid the nested foreach if I wanted to
    $insert[] = "('".implode("','", $vals)."')";
}
$sql .= implode(",\n", $insert).";\n";

// TRUNCATE optimized table and run INSERT query here

endforeach;

这会产生类似这样的东西(只是更大 - 每个表最多大约 15,000 条记录,每个表一个插入语句):

INSERT INTO `optimized_table_name1` (`id`,`beds`,`baths`,`town`) VALUES
('50300584','2','1','Fairfield'),
('87560584','3','2','New Haven'),
('76545584','2','1','Bristol');

现在我承认,我在 ORM 的支持下已经有很长一段时间了,并且没有使用我的普通 mysql/php。这是一个非常简单的任务,我想让代码保持简单。

我的问题:

  1. TRUNCATE/INSERT 方法是实现此目的的好方法吗?
  2. 您认为我的代码有什么问题吗?我知道你看到了嵌套的 foreach 循环,只是不寒而栗,但我想保持代码尽可能小而干净,并避免大量混乱的字符串连接(以产生插入查询)。就像我说的,我也很长时间没有使用 SQL 的原生 php 函数了。
  3. 我觉得如果代码在每 2 天凌晨 3 点运行一次,是否没有优化代码真的没关系。 重要吗?这段代码可以执行吗?
  4. 是否有更好的整体策略来完成这项任务?
  5. 我需要使用事务吗?
  6. 如何知道 cron 脚本中可能出现的错误?

抱歉,如果我没有使用正确的 cron 术语,这对我来说是新的。

【问题讨论】:

    标签: php mysql cron


    【解决方案1】:

    保持简单。 ORM 会很适合这项任务。

    答案:

    1. 是的。
    2. 您的代码是可读的。至少我读起来没有任何问题。
    3. 我们有一个一大早运行的脚本。它没有优化并消耗大量内存。四年后,它开始消耗超过 512 Mb。我花了 2 个小时来优化它,所以现在它消耗了 7 Mb(非常好的优化,嗯?:))。我个人认为你的脚本现在没有优化是“好的”。如果这个脚本开始失败,你会发现问题出在哪里。也许它会耗尽内存,也许你的 SQL 查询会导致死锁......也许你稍后会优化它以从从服务器读取......我不知道,但它现在可以正常工作,没关系。
    4. 我会做一些与您的代码类似的事情。但我可能会先生成文件,然后通过运行 shell 命令mysql -u username --password=password &lt; import_file.sql 将数据加载到服务器中。所以我会把我的文件存储在磁盘上的某个地方,所以我总是看一下它。甚至可以编辑一次性校正负载。但是你仍然可以通过将你的 sql 语句写入文件来做到这一点。
    5. 没有。这只是一个查询。如果您使用 InnoDB 引擎,它已经是一个事务。
    6. 首先,使用error_reporting(E_ALL & ~E_NOTICE)。其次,使用mysql_error PHP 函数来确保您的查询正确执行。第三,在您的 cronjob 输出错误流到某个文件中,如下所示:0 7 * * 0 /path/to/php -c /path/to/php.ini /path/to/script.php 2&gt; /tmp/errors_file 因此,您可以创建在第一个脚本之后运行的第二个脚本,以通过电子邮件通知 script.php 中的错误或....任何您喜欢的通知方式。我更喜欢register_shutdown_functions,它会检查error_file,如果它不为空,请通知您并在之后将其删除。

    只是我的看法,但我希望我的回答能有所帮助。

    【讨论】:

    • 谢谢,是的,这绝对有帮助。这是一个完全不同于我用来编写代码的环境,我按照你的链接访问了一些我以前从未使用过的有用的 php 错误处理函数。那么,使用 InnoDB,如果其中一个查询失败,我不必担心丢失优化的数据?它会自动回滚 TRUNCATE 和 INSERT 吗?另外,为什么还要将 sql 写入文件?数据将始终在原始表(或远程服务器)中,因此如果这是原因,我们不需要备份。
    • 好的。我没有从交易中得到你想要的。如果你有很多记录,你的事务会很慢,所以最好先创建一个现有的临时表 (CREATE TABLE 'tmp_table' LIKE 'table'; INSERT INTO 'tmp_table' SELECT * FROM 'table' ),然后 TRUNCATE 和 INSERT。如果出现问题,您只需删除表并临时重命名即可。如果您的表中没有太多行,您可以使用事务来完成。不要使用事务来恢复 HUGE 表中的数据。
    • 感谢您的时间 Nemoden,我想我只是需要一些批准来确认我已经相信的东西。例如:我认为给自己发送一封关于 cron 错误的电子邮件将是一种“菜鸟”的方法,但它似乎是一种常见的明智之举,除了正常的错误记录。感谢您提供有用的意见和临时表建议。
    猜你喜欢
    • 2021-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-03-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多