背景:
我正在使用控制台上的PHP脚本将330 meg xml文件解析为DB(netflix目录)。
我可以每3秒成功添加约1,500个标题直到我添加了添加演员,流派和格式的逻辑。这些是由关联表链接的单独表。
现在我必须按此顺序为每个标题运行许多查询(我首先截断所有表格,以消除旧标题,流派等)
(对于类型也重复步骤2-4)
这使我的速度降低到每3秒10左右。这将需要添加约250,00个标题。
所以如何将4个查询合并为一个查询,而不添加重复的演员或类型
我的目标是将所有查询都写入数据文件,并进行批量插入。
我首先将所有关联查询写入数据文件,但它对性能没有太大作用。
我首先插入etitle并保存ID
function insertTitle($nfid, $title, $year){
$query="INSERT INTO ".$this->titles_table." (nf_id, title, year ) VALUES ('$nfid','$title','$year')";
mysql_query($query);
$this->updatedTitleCount++;
return mysql_insert_id();
}
然后与每个actor的名称一起使用以创建关联
function linkActor($value, $title_id){
//check if we already know value
$query="SELECT * FROM ".$this->persons_table." WHERE person = '$value' LIMIT 0,1";
//echo "<br>".$query."<br>";
$result=mysql_query($query);
if($result && mysql_num_rows($result) != 0){
while ($row = mysql_fetch_assoc($result)) {
$value_id=$row['id'];
}
}else{
//no value known, add to persons table
$query="INSERT INTO ".$this->persons_table." (person) VALUES ('$value')";
mysql_query($query);
$value_id=mysql_insert_id();
}
//echo "linking title:".$title_id." with rel:".$value_id;
$query = " INSERT INTO ".$this->title_persons_table." (title_id,person_id) VALUE ('$title_id','$value_id');";
//mysql_query($query);
//write query to data file to be read in bulk style
fwrite($this->fh, $query);
}
答案 0 :(得分:1)
你的表现非常缓慢;事情是非常错误的。我假设以下
你可能会因为使用自动提交进行大量微小的操作而受到刺激;这是一个错误,因为它会产生不合理数量的光盘IO操作。你应该在一个事务中做大量的工作(100,1000条记录等)然后提交它。
查询可能会减慢速度,因为执行查询的开销很简单(查询本身非常简单,因为您将拥有对actor名称的索引)。
我还质疑你假设没有两个演员有相同名字的方法 - 你的原始数据库肯定包含一个独特的演员ID,所以你不要混淆它们吗?
答案 1 :(得分:1)
这是使用prepared statements的绝佳机会 另请查看http://dev.mysql.com/doc/refman/5.0/en/insert-speed.html上的提示,例如
要加快使用非事务表的多个语句执行的INSERT操作,请锁定表
您还可以减少查询次数。例如。您可以使用SELECT...FROM persons_table
和LAST_INSERT_ID(expr)来消除INSERT...ON DUPLICATE KEY UPDATE
以获取ID。
(对不起,没时间进行冗长的描述,但是在注意到时间之前我写了一个例子;-)如果这个答案没有过多投票,我可以在以后交出来。 )
class Foo {
protected $persons_table='personsTemp';
protected $pdo;
protected $stmts = array();
public function __construct($pdo) {
$this->pdo = $pdo;
$this->stmts['InsertPersons'] = $pdo->prepare('
INSERT INTO
'.$this->persons_table.'
(person)
VALUES
(:person)
ON DUPLICATE KEY UPDATE
id=LAST_INSERT_ID(id)
');
}
public function getActorId($name) {
$this->stmts['InsertPersons']->execute(array(':person'=>$name));
return $this->pdo->lastInsertId('id');
}
}
$pdo = new PDO("mysql:host=localhost;dbname=test", 'localonly', 'localonly');
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
// create a temporary/test table
$pdo->exec('CREATE TEMPORARY TABLE personsTemp (id int auto_increment, person varchar(32), primary key(id), unique key idxPerson(person))');
// and fill in some data
foreach(range('A', 'D') as $p) {
$pdo->exec("INSERT INTO personsTemp (person) VALUES ('Person $p')");
}
$foo = new Foo($pdo);
foreach( array('Person A', 'Person C', 'Person Z', 'Person B', 'Person Y', 'Person A', 'Person Z', 'Person A') as $name) {
echo $name, ' -> ', $foo->getActorId($name), "\n";
}
打印
Person A -> 1
Person C -> 3
Person Z -> 5
Person B -> 2
Person Y -> 6
Person A -> 1
Person Z -> 5
Person A -> 1
(有人可能想开始讨论getXYZ()函数是否应该执行INSERT ......但不是我,现在不是....)
答案 2 :(得分:0)
你能使用PHP以外的语言吗?如果没有,您是将其作为PHP独立脚本运行还是通过Web服务器运行?网络服务器可能会增加你不需要的大量开销。
我在工作中使用Python做了类似的事情,并且可以在标准的3.4 GHz,3GB RAM机器上每秒插入几千行(带有关联表查找)。 MySQL数据库不是在本地托管,而是在局域网内托管。