在 MySQL 中导入和处理文本文件


Import and process text file within MySQL

我正在从事一个研究项目,该项目要求我处理具有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包装器)来加快处理速度?

我正在使用本地MySQL服务器在我的Mac OS 10.6上运行它。

使用加载数据infile将文件加载到临时/临时表中,然后使用存储过程处理数据 - 最多不应超过1-2分钟才能完全加载和处理数据。

您可能还会发现我感兴趣的其他一些答案:

提供大量数据的查询的最佳 MySQL 设置?

MySQL 和 NoSQL:帮助我选择合适的

如何避免在多对多查询中"使用临时"?

6000 万个条目,选择某个月份的条目。如何优化数据库?

有趣的介绍:

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();

希望这有帮助

听起来你会

从调整SQL查询中受益最大,这可能是你的脚本花费最多时间的地方。我不知道PHP MySQL客户端的性能如何,但MySQLdb for Python相当快。进行朴素的基准测试,我可以轻松地在我的一个较旧的四核上维持 10k/秒的插入/选择查询。与其一个接一个地SELECT来测试组织是否存在,不如使用REGEXP一次检查它们可能更有效(在这里讨论:MySQL LIKE IN()?)。MySQLdb 允许您使用 executemany() 同时进行多次插入,您几乎可以肯定地利用这一点来发挥自己的优势,也许您的 PHP 客户端允许您做同样的事情?

另一件需要考虑的事情是,使用 Python,您可以使用multiprocessing并尝试尽可能多地并行化。PyMOTW有一篇关于多处理的好文章。