在两个表中插入行的最快方法是什么

时间:2014-07-23 08:05:23

标签: php mysql sql

我有两个mysql表,我想在两个表中插入一封电子邮件。

我需要将电子邮件拆分为namedomain name,然后将其中的每一部分插入一个表格。

我的domain表格如下:

+----+--------+
| id | domain | primary(id)
+----+--------+

和我的email表是:

+-------+----------+
| eMail | domainId | primary key(eMail, domainId)
+-------+----------+

即:info@example.com> example.com必须在domain表中插入 info必须在email表中添加domainId。

域必须是唯一的。

我的尝试:

foreach($emails as $email)
{
    list($account,$hostname) = explode('@',$email,2);

    $query = $dbh->prepare("SELECT id FROM domain WHERE domain LIKE :domain LIMIT 0,1");
    $query->execute(array(':domain'=>trim($hostname)));

    if($query->rowCount())
    {
        $id = $query->fetch();
        $id = $id['id'];
    }else{
        $insert = $dbh->prepare("INSERT INTO domain (domain) VALUES (:domain)");
        $insert->execute(array(':domain'=>trim($hostname)));
        $id = $dbh->lastInsertId();
    }

    $name = $dbh->prepare("INSERT INTO email (eMail, domainId) VALUES (:eMail, :domainId)");
    $name->execute(array(':eMail'=>trim($account),':domainId'=>$id));
}

但是当我想添加批量电子邮件时,这种方式非常慢:

有没有更快的方法,或者我可以在单个查询中执行此操作..?

3 个答案:

答案 0 :(得分:3)

仅插入电子邮件并向email表添加触发器,以提取域名并自动将其插入domain

DELIMITER |
CREATE TRIGGER insert_domain_trigger BEFORE INSERT ON email 
FOR EACH ROW 
begin
  set @domainname = substring(NEW.email, instr(NEW.email, '@') + 1);
  if(select count(*) from domain where domain = @domainname) = 0
  then
     insert into domain (domain) values (@domainname);
  end if;
end
|

答案 1 :(得分:1)

由于您有来自同一域的大量电子邮件,因此您可以尝试在本地php变量中缓存域ID,以减少对db的查询数。

此外,您应该在循环之外准备$insert$name语句。

$domains = array();

foreach($dbh->query("SELECT id, domain FROM domain") as $domain) {
    $domains[$domain['domain']] = $domain['id'];
}

$insert = $dbh->prepare("INSERT INTO domain (domain) VALUES (:domain)");
$name = $dbh->prepare("INSERT INTO email (eMail, domainId) VALUES (:eMail,:domainId)");

foreach($emails as $email)
{
    list($account,$hostname) = explode('@',$email,2);
    $hostname = trim($hostname);

    if(!isset($domains[$hostname])) {
        $insert->execute(array(':domain'=>$hostname));
        $id = $dbh->lastInsertId();
        $domains[$hostname] = $id;
    }
    else {
        $id = $domains[$hostname];
    }    

    $name->execute(array(':eMail'=>trim($account),':domainId'=>$id));
}

答案 2 :(得分:1)

也许一个简单的程序可以解决这个问题?

这需要数据库中的字段域为UNIQUE语法的INSERT IGNORE INTO类型。

DELIMITER $$

CREATE PROCEDURE `sp_InsertEmail`(IN p_Email VARCHAR(100))
BEGIN

-- Declare variables
DECLARE v_Email VARCHAR(100);
DECLARE v_Domain VARCHAR(100);

-- Set the variables
SET v_Email = SUBSTRING(p_Email,1,INSTR(p_email,'@')-1);
SET v_Domain =SUBSTRING(p_Email,INSTR(p_Email,'@'));

-- Now insert ignore into domain table

INSERT IGNORE INTO db.domain (domain) VALUES(v_Domain);

-- Then insert like this.

INSERT IGNORE INTO db.email SELECT v_Email,DomainId FROM domain WHERE domain=v_Domain;

END

然后只需调用程序

CALL db.sp_InsertEmail('name@domain.com')