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