Импорт и обработка текстового файла в MySQL - PullRequest
3 голосов
/ 12 мая 2011

Я работаю над исследовательским проектом, который требует от меня обработки больших файлов CSV (~ 2-5 ГБ) с 500 000 записей.Эти файлы содержат информацию о государственных контрактах (от USASpending.gov ).До сих пор я использовал скрипты PHP или Python, чтобы атаковать файлы построчно, анализировать их, а затем вставлять информацию в соответствующие таблицы.Разбор в меру сложный.Для каждой записи сценарий проверяет, находится ли названная сущность в базе данных (используя комбинацию сопоставления строк и регулярных выражений);если это не так, он сначала добавляет объект в таблицу объектов, а затем переходит к анализу оставшейся части записи и вставляет информацию в соответствующие таблицы.Список сущностей превышает 100 000.

Вот основные функции (часть класса), которые пытаются сопоставить каждую запись с любыми существующими сущностями:

private function _getOrg($data)
{
    // if name of organization is null, skip it
    if($data[44] == '') return null;

    // use each of the possible names to check if organization exists
    $names = array($data[44],$data[45],$data[46],$data[47]);

    // cycle through the names
    foreach($names as $name) {
        // check to see if there is actually an entry here
        if($name != '') {
            if(($org_id = $this->_parseOrg($name)) != null) {
                $this->update_org_meta($org_id,$data); // updates some information of existing entity based on record
                return $org_id;
            }
        }
    }

    return $this->_addOrg($data);
}

private function _parseOrg($name)
{
    // check to see if it matches any org names
    // db class function, performs simple "like" match
    $this->db->where('org_name',$name,'like');

    $result = $this->db->get('orgs');

    if(mysql_num_rows($result) == 1) {
        $row = mysql_fetch_object($result);
        return $row->org_id;
    }

    // check to see if matches any org aliases
    $this->db->where('org_alias_name',$name,'like');

    $result = $this->db->get('orgs_aliases');

    if(mysql_num_rows($result) == 1) {
        $row = mysql_fetch_object($result);
        return $row->org_id;
    }
    return null; // no matches, have to add new entity
 }

Функция _addOrg вставляетинформация о новой сущности в БД, где, как мы надеемся, она будет соответствовать последующим записямдля каждого файла.Структура моей базы данных требует обновления нескольких разных таблиц для каждой записи, потому что я собираю несколько внешних наборов данных.Итак, каждая запись обновляет две таблицы, а каждая новая сущность обновляет три таблицы.Я беспокоюсь, что это добавляет слишком много времени между сервером MySQL и моим скриптом.

Вот мой вопрос: есть ли способ импортировать текстовый файл во временную таблицу MySQL, а затем использовать внутренние функции MySQL (илиОболочка PHP / Python) ускорить обработку?

Я запускаю это на моей Mac OS 10.6 с локальным сервером MySQL.

Ответы [ 2 ]

1 голос
/ 12 мая 2011

загрузить файл во временную / промежуточную таблицу, используя загрузить данные infile , а затем использовать хранимую процедуру для обработки данных - не должно занимать более 1-2 минут максимумчтобы полностью загрузить и обработать данные.

Вы также можете найти некоторые другие мои интересные ответы:

Оптимальные настройки MySQL для запросов, которые доставляют большие объемы данных?

MySQL и NoSQL: помогите мне выбрать правильный

Как избежать "использования временных" в запросах "многие ко многим"?

60 миллионов записей, выберите записи за определенный месяц.Как оптимизировать базу данных?

Интересная презентация:

http://www.mysqlperformanceblog.com/2011/03/18/video-the-innodb-storage-engine-for-mysql/

пример кода (может быть полезным для вас)

truncate table staging;

start transaction;

load data infile 'your_data.dat' 
into table staging
fields terminated by ',' optionally enclosed by '"'
lines terminated by '\n'
(
org_name
...
)
set
org_name = nullif(org_name,'');

commit;

drop procedure if exists process_staging_data;

delimiter #

create procedure process_staging_data()
begin

    insert ignore into organisations (org_name) select distinct org_name from staging;

    update...

    etc.. 

    -- or use a cursor if you have to ??

end#

delimiter ;

call  process_staging_data();

Надеюсь, это поможет

0 голосов
/ 12 мая 2011

Похоже, что вам больше всего пригодится настройка ваших SQL-запросов, и, вероятно, именно там ваш скрипт тратит больше всего времени. Я не знаю, как работает клиент PHP MySQL, но MySQLdb для Python работает довольно быстро. Выполняя наивные тесты производительности, я могу легко поддерживать запросы вставки / выбора со скоростью 10 к / с на одном из моих старых четырехъядерных процессоров. Вместо того, чтобы делать один SELECT за другим, чтобы проверить, существует ли организация, использование REGEXP для одновременной проверки их всех может быть более эффективным (обсуждается здесь: MySQL LIKE IN () ). MySQLdb позволяет вам использовать executemany() для одновременного выполнения нескольких вставок, вы почти наверняка можете использовать это в своих интересах, возможно, ваш PHP-клиент позволяет вам делать то же самое?

Еще одна вещь, которую стоит учесть, с Python вы можете использовать multiprocessing и пытаться распараллелить как можно больше. В PyMOTW есть хорошая статья о многопроцессорности .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...