我正在开展一项研究项目,该项目要求我处理500,000多条记录的大型csv文件(~2-5 GB)。这些文件包含有关政府合同的信息(来自USASpending.gov)。到目前为止,我一直在使用PHP或Python脚本逐行攻击文件,解析它们,然后将信息插入相关表中。解析是中等复杂的。对于每条记录,脚本检查命名的实体是否已经在数据库中(使用字符串和正则表达式匹配的组合);如果不是,它首先将实体添加到实体表中,然后继续解析记录的其余部分并将信息插入到适当的表中。实体列表超过100,000。
以下是尝试将每条记录与任何现有实体进行匹配的基本功能(类的一部分):
private function _getOrg($data)
{
// if name of organization is null, skip it
if($data[44] == '') return null;
// use each of the possible names to check if organization exists
$names = array($data[44],$data[45],$data[46],$data[47]);
// cycle through the names
foreach($names as $name) {
// check to see if there is actually an entry here
if($name != '') {
if(($org_id = $this->_parseOrg($name)) != null) {
$this->update_org_meta($org_id,$data); // updates some information of existing entity based on record
return $org_id;
}
}
}
return $this->_addOrg($data);
}
private function _parseOrg($name)
{
// check to see if it matches any org names
// db class function, performs simple "like" match
$this->db->where('org_name',$name,'like');
$result = $this->db->get('orgs');
if(mysql_num_rows($result) == 1) {
$row = mysql_fetch_object($result);
return $row->org_id;
}
// check to see if matches any org aliases
$this->db->where('org_alias_name',$name,'like');
$result = $this->db->get('orgs_aliases');
if(mysql_num_rows($result) == 1) {
$row = mysql_fetch_object($result);
return $row->org_id;
}
return null; // no matches, have to add new entity
}
_addOrg函数将新实体的信息插入到数据库中,希望它能匹配后续记录。
问题在于:我只能获得这些脚本来解析大约10,000条记录/小时,考虑到大小,这意味着每个文件需要几天的时间。我的数据库结构的方式需要为每条记录更新几个不同的表,因为我正在编译多个外部数据集。因此,每条记录更新两个表,每个新实体更新三个表。我担心这会在MySQL服务器和我的脚本之间增加太多的延迟时间。
这是我的问题:有没有办法将文本文件导入临时MySQL表,然后使用内部MySQL函数(或PHP / Python包装器)来加速处理?
我在Mac OS 10.6上运行本地MySQL服务器。
答案 0 :(得分:1)
使用加载数据infile 将文件加载到临时/临时表中,然后使用存储过程处理数据 - 不应超过1-2分钟最完全加载和处理数据。
您可能还会找到我感兴趣的其他一些答案:
Optimal MySQL settings for queries that deliver large amounts of data?
MySQL and NoSQL: Help me to choose the right one
How to avoid "Using temporary" in many-to-many queries?
60 million entries, select entries from a certain month. How to optimize database?
有趣的演讲:
http://www.mysqlperformanceblog.com/2011/03/18/video-the-innodb-storage-engine-for-mysql/
示例代码(可能对您有用)
truncate table staging;
start transaction;
load data infile 'your_data.dat'
into table staging
fields terminated by ',' optionally enclosed by '"'
lines terminated by '\n'
(
org_name
...
)
set
org_name = nullif(org_name,'');
commit;
drop procedure if exists process_staging_data;
delimiter #
create procedure process_staging_data()
begin
insert ignore into organisations (org_name) select distinct org_name from staging;
update...
etc..
-- or use a cursor if you have to ??
end#
delimiter ;
call process_staging_data();
希望这有帮助
答案 1 :(得分:0)
听起来您从调优SQL查询中获益最多,这可能是您的脚本花费最多时间的地方。我不知道PHP MySQL客户端是如何执行的,但是用于Python的MySQLdb相当快。做天真的基准测试我可以轻松地在我的一个旧的四核上维持10k /秒的插入/选择查询。不是一个接一个SELECT
来测试组织是否存在,而是使用REGEXP
一次检查它们可能会更有效(在此讨论:MySQL LIKE IN()?)。 MySQLdb允许你使用executemany()
同时进行多次插入,你几乎可以肯定地利用它,也许你的PHP客户端可以让你做同样的事情?
要考虑的另一件事是,使用Python,您可以使用multiprocessing
并尽可能地尝试并行化。 PyMOTW has a good article about multiprocessing