使用php在cron中的“原始”表中将数据传输到优化的MySQL表中

时间:2011-04-20 00:32:51

标签: php mysql cron

我正在与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脚本中可能出现的错误?
  7. 如果我不使用正确的cron术语,请道歉,这对我来说是新的。

1 个答案:

答案 0 :(得分:1)

保持简单。 ORM会因此而膨胀。

数目:

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