如何使用PHP和外键将“大量”数据导入MySQL?

时间:2013-07-22 17:04:44

标签: php mysql insert large-data

我有这些表格:

create table person (
    person_id int unsigned auto_increment, 
    person_key varchar(40) not null, 
    primary key (person_id), 
    constraint uc_person_key unique (person_key)
) 
-- person_key is a varchar(40) that identifies an individual, unique 
-- person in the initial data that is imported from a CSV file to this table

create table marathon (
    marathon_id int unsigned auto_increment,  
    marathon_name varchar(60) not null, 
    primary key (marathon_id) 
)

create table person_marathon (
    person_marathon _id int unsigned auto_increment,  

    person_id int unsigned, 
    marathon_id int unsigned,

    primary key (person_marathon_id),
    foreign key person_id references person (person_id), 
    foreign key marathon_id references person (marathon_id),

    constraint uc_marathon_person unique (person_id, marathon_id)  
)

人员表由一个包含大约130,000行的CSV填充。此CSV包含每个人的唯一varchar(40)和一些其他人员数据。 CSV中没有ID。

对于每次马拉松比赛,我都会获得一张包含1k-3k人名单的CSV。 CSV基本上只包含person_key值列表,显示哪些人参与了特定的马拉松比赛。

将数据导入person_marathon表以维持FK关系的最佳方法是什么?

这些是我目前可以想到的想法:

  • person_id + person_key信息从MySQL中拉出并合并PHP中的person_marathon数据以获取person_id,然后插入person_marathon

  • 使用临时表进行插入...但这是为了工作而我被要求永远不要在此特定数据库中使用临时表

  • 根本不要使用person_id而只使用person_key字段,但我必须加入varchar(40),这通常不是一件好事< / p>

  • 或者,对于插入,使它看起来像这样(我必须插入<hr>否则它不会将整个插入格式化为代码):

    insert  into person_marathon 
    
    select  p.person_id, m.marathon_id
    
    from    ( select 'person_a' as p_name, 'marathon_a' as m_name union 
              select 'person_b' as p_name, 'marathon_a' as m_name ) 
              as imported_marathon_person_list 
    
            join person p 
               on p.person_name = imported_marathon_person_list.p_name
    
            join marathon m 
               on m.marathon_name = imported_marathon_person_list.m_name
    

    该插入的问题是,要在PHP中构建它,imported_marathon_person_list将是巨大的,因为它可能很容易成为30,000 select union项。不过,我不知道怎么做。

1 个答案:

答案 0 :(得分:2)

我处理过类似的数据转换问题,但规模较小。如果我正确地理解你的问题(我不确定),听起来像你的情况具有挑战性的细节是这样的:你试图在同一步骤中做两件事:

  • 将CSV中的大量行导入mysql和
  • 进行转换,使人马拉松协会通过person_id和marathon_id工作,而不是(笨重且不受欢迎的)varchar personkey列。

简而言之,我会尽一切可能避免在同一步骤中完成这两件事。将其分解为这两个步骤 - 首先以可容忍的形式导入所有数据,然后再对其进行优化。 Mysql是进行此类转换的良好环境,因为当您将数据导入到人员和马拉松表中时,会为您设置ID。

第1步:导入数据

  • 我发现在mysql环境中比在它之外更容易执行数据转换。因此,将数据以一种保留人马拉松关联的形式存入mysql,即使它不是最优的,并且担心之后会改变关联方法。
  • 你提到临时表,但我认为你不需要。在persons_marathons表上设置临时列“personkey”。导入所有关联时,您现在将person_id留空,只需导入personkey。重要的是,确保personkey是关联表和人员表上的索引列。然后你可以稍后再为每个personkey填写正确的person_id,而不必担心mysql效率低下。
  • 我不清楚马拉松表数据的性质。你有成千上万的马拉松进入吗?如果是这样,我不羡慕你每次马拉松处理1个电子表格的工作。但如果它更少,那么你也可以手动设置马拉松表。让mysql为您生成马拉松ID。然后,当您为每个马拉松导入person_marathon CSV时,请务必在与该马拉松相关的每个关联中指定该马拉松ID。

完成导入数据后,您有三个表: *人 - 你有丑陋的人员钥匙,以及新生成的person_id,以及任何其他领域 *马拉松 - 此时你应该有一个marathon_id,对吗?要么是新生成的,要么是你从旧系统中带来的数字。 * persons_marathons - 此表应填写marathon_id&amp;指向马拉松表中的正确行,对吧?你也有personkey(丑陋但存在)和person_id(仍然是null)。

步骤2:使用personkey为关联表中的每一行填写person_id

然后你要么直接使用Mysql,要么写一个简单的PHP脚本,为persons_marathons表中的每一行填写person_id。如果我无法让mysql直接执行此操作,我会经常编写一个php脚本来一次处理一行。这里的步骤很简单:

  1. 查找person_id为null但personkey不为空的任何1行
  2. 查找personkey的person_id
  3. 将该person_id写入该行的关联表
  4. 你可以告诉PHP重复这个100次然后结束脚本,或1000次,如果你不断出现超时问题或类似taht。

    此转换涉及大量查找,但每次查找只需要一行。这很有吸引力,因为在任何时候你都不需要让mysql(或PHP)“将整个数据集保持在其头部”。

    此时,您的关联表应该为每一行填写person_id。删除personkey列现在是安全的,瞧,你有高效的外键。