Veri dosyası içine mantığı ile birçok MySQL sorguları birleştirmek

3 Cevap php

Arka plan:

Ben konsoldan PHP komut dosyası kullanarak bir DB (netflix katalog) içine 330 meg xml dosyası ayrıştırma duyuyorum.

Başarıyla yaklaşık 1.500 başlıkları ekleyebilirsiniz her 3 saniyede until i aktörler, tür ve biçimleri eklemek için mantığı addd. Bunlar ilişkisel tablo ile bağlantılı ayrı tablolar vardır.

right now I have to run many, many queries for each title, bu sırayla (i eski başlıkları, türler, vb ortadan kaldırmak için, her şeyden önce tablo kesecek)

  1. 'başlıkları' yeni başlık eklemek ve insert id yakalama
  2. aktör exising için aktör tablosunu kontrol edin
  3. if present, get id, if not insert actor and get insert id
  4. insert title id and actor id into associative table

(2-4 adımlar çok türler için tekrarlanır)

Bu yaklaşık 10 3 saniyede benim hız don düşer. ~ 250,00 başlık eklemek için eternitty alacağını.

so how would I combine the 4 queries into a single query, without adding duplicate actors or genres

Amacım sadece bir veri dosyası içine tüm sorguları yazmak, ve bir toplu ekleme yapmaktır.

Ben bir veri dosyası içine tüm ilişkisel sorguları yazarak başladı, ama o performans için çok yapmadım.


Ben etitle inci ekleme ve kimliği kaydederek başlayın

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

o zaman dernek oluşturmak için her aktörün ismi ile birlikte kullanılır

function linkActor($değer, $title_id){
    //check if we already know değer
    $query="SELECT * FROM ".$this->persons_table." WHERE person = '$değer' LIMIT 0,1";
    //echo "<br>".$query."<br>";
    $result=mysql_query($query);
    if($result && mysql_num_rows($result) != 0){
    	while ($row = mysql_fetch_assoc($result)) {
    		$değer_id=$row['id'];
    	}
    }else{
    	//no değer known, add to persons table
    	$query="INSERT INTO ".$this->persons_table." (person) VALUES ('$değer')";
    	mysql_query($query);
    	$değer_id=mysql_insert_id();

    }	
    //echo "linking title:".$title_id." with rel:".$değer_id;
    $query = " INSERT INTO ".$this->title_persons_table." (title_id,person_id) VALUE ('$title_id','$değer_id');";
    //mysql_query($query);
    //write query to data file to be read in bulk style
    fwrite($this->fh, $query);
}

3 Cevap

This is a perfect opportunity for using prepared statements.
Also take a look at the tips at http://dev.mysql.com/doc/refman/5.0/en/insert-speed.html, e.g.

To speed up INSERT operations that are performed with multiple statements for nontransactional tables, lock your tables

Ayrıca sorgu sayısını azaltabilirsiniz. Örneğin Eğer INSERT...ON DUPLICATE KEY UPDATE ve LAST_INSERT_ID(expr) kullanarak kimliği elde etmek SELECT...FROM persons_table ortadan kaldırabilir.

(Üzgünüm, uzun bir açıklama için zaman tükeniyor, ama ben zaman fark etmeden önce bir örnek yazdı ;-) Bu cevap çok downvoted değilse ben daha sonra teslim edebilirsiniz. )

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";
}

baskılar

Person A -> 1
Person C -> 3
Person Z -> 5
Person B -> 2
Person Y -> 6
Person A -> 1
Person Z -> 5
Person A -> 1

(Birisi getXYZ () fonksiyonu INSERT gerçekleştirmek yapıp yapmamasına bir tartışma başlatmak istiyorum ... ama belki ben değil, şimdi değil ....)

Sizin performans buzul yavaş; bir şey çok yanlış olduğunu. Ben şu varsayalım

  • Sen saygın donanım adanmış, aksi boşta veritabanı sunucusu çalıştırmak
  • (Yani en azından düzgün ram bir kaç konser kullanmak üzere yapılandırmak) bir ölçüde bunu ayarlı var - motor özel optimizasyon gerekli olacaktır

Sen üzerine Autocommit ile minik işlemleri çok yaparak sokuldu olabilir; Bu disk IO işlemleri mantıksız bir sayıda üretir gibi bu bir hatadır. Bunu taahhüt sonra tek bir işlemde çalışma büyük miktarda (100, 1000 kayıt vb) yapmalıdır.

Aramaları nedeniyle sorguları yapmanın basit yükü (sorgular kendilerini size aktör adı üzerinde bir dizin olacak gibi gerçekten kolay olacaktır) şeyler aşağı yavaşlama olabilir.

Kesinlikle orijinal veritabanı benzersiz bir aktör kimliğini içerir, böylece onları karışık alamadım - Ben de hiçbir iki aktör aynı ada sahip olduğunu varsayarak yönteminizi soru?

PHP dışında bir dil kullanabilir miyim? Eğer değilse, bir PHP tek başına bir betik olarak veya bir web sunucusu üzerinden bu çalıştırıyorsunuz? Webserver muhtemelen gerekmez yükü bir sürü ekliyor.

Python kullanarak, iş yerinde çok benzer bir şey yapmak ve standart 3.4 GHz, 3GB RAM, makinede saniyede (birleştirici tablo aramalarını) bir kaç bin satır ekleyebilirsiniz. MySQL veritabanı ancak LAN içinde yerel olarak barındırılan değildir.