Объедините много запросов MySQL с логикой в ​​файл данных - PullRequest
1 голос
/ 22 декабря 2009

Справочная информация:

Я анализирую 330-мегабайтный XML-файл в БД (каталог netflix), используя скрипт PHP из консоли.

Я могу успешно добавлять около 1500 названий каждые 3 секунды до Я добавил логику для добавления актеров, жанров и форматов. Это отдельные таблицы, связанные ассоциативной таблицей.

прямо сейчас мне нужно выполнить много-много запросов для каждого заголовка , в этом порядке (сначала я усекаю все таблицы, чтобы исключить старые заголовки, жанры и т. Д.)

  1. добавить новый заголовок к заголовкам и захватить идентификатор вставки
  2. проверка таблицы актеров на наличие действующего актера
  3. если присутствует, получить идентификатор, если не вставить Актер и получить вставить идентификатор
  4. вставить идентификатор заголовка и идентификатор актера в ассоциативный стол

(шаги 2-4 повторяются и для жанров)

Это понизит мою скорость до 10 за 3 секунды. что заняло бы вечность, чтобы добавить ~ 250,00 названий.

так как бы я объединил 4 запроса в один запрос, не добавляя дублирующихся актеров или жанров

Моя цель - просто записать все запросы в файл данных и выполнить массовую вставку.

Я начал с записи всех ассоциативных запросов в файл данных, но это не сильно сказалось на производительности.


Я начинаю с добавления thitle и сохранения 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();
}

, который затем используется вместе с именем каждого актера для создания ассоциации

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

Ответы [ 3 ]

1 голос
/ 22 декабря 2009

Ваш спектакль очень медленный; что-то очень неправильно. Я предполагаю следующее

  • Вы используете свой выделенный, в противном случае бездействующий сервер базы данных на приличном оборудовании
  • Вы настроили его до некоторой степени (т.е., по крайней мере, сконфигурируйте его для правильного использования нескольких гигабайт оперативной памяти) - потребуется оптимизация для конкретного двигателя

Вы можете быть ужалены, выполняя множество крошечных операций с включенной автоматической фиксацией; это ошибка, поскольку она генерирует необоснованное количество операций ввода-вывода диска. Вы должны выполнить большой объем работы (100, 1000 записей и т. Д.) За одну транзакцию, а затем зафиксировать ее.

Поиски могут замедлять процесс из-за простых накладных расходов на выполнение запросов (сами запросы будут действительно простыми, так как у вас будет индекс имени актера).

Я также подвергаю сомнению ваш метод предположения, что ни у одного из двух актеров нет одинаковых имен - наверняка ваша исходная база данных содержит уникальный идентификатор актера, так что вы не перепутаете их?

1 голос
/ 22 декабря 2009

Это прекрасная возможность для использования подготовленных заявлений .
Также взгляните на советы на http://dev.mysql.com/doc/refman/5.0/en/insert-speed.html, например.

Чтобы ускорить операции INSERT, которые выполняются с несколькими операторами для нетранзакционных таблиц, заблокируйте ваши таблицы

Вы также можете уменьшить количество запросов. Например. Вы можете исключить SELECT...FROM persons_table для получения идентификатора, используя INSERT...ON DUPLICATE KEY UPDATE и LAST_INSERT_ID ( expr ) .

(извините, у меня не хватает времени для длинного описания, но я написал пример, прежде чем замечать время ;-) Если этот ответ не слишком обесценит, я могу передать его позже. )

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 или нет ... но не я, не сейчас ....)

0 голосов
/ 22 декабря 2009

Можете ли вы использовать язык, отличный от PHP? Если нет, вы запускаете это как отдельный скрипт PHP или через веб-сервер? Возможно, веб-сервер добавляет много служебных данных, которые вам не нужны.

Я делаю нечто очень похожее на работе, используя Python, и могу вставлять пару тысяч строк (с поиском ассоциативных таблиц) в секунду на вашем стандартном 3,4 ГГц, 3 ГБ ОЗУ, машине. База данных MySQL размещается не локально, а в локальной сети.

...