Правильный ли я подход к работе с этими файлами? (CSV с PHP) - PullRequest
2 голосов
/ 04 июля 2011

Я студент, работаю над размещением на лето.Мне было поручено заняться вводом данных из Excel в базу данных SQL Server для опросов, которые проводились в течение нескольких лет.Задача описана ниже:

Существует три таблицы: главное событие, отдельное событие и отдельное лицо.У события есть много отдельных событий, у отдельного события есть много людей.Мой код касается только последних двух таблиц.

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

Мой код в основном читает отдельное событие, а затем просматривает второй файл для всех связанных лиц.Для каждой строки в файле индивидуумов, если она связана, она вставляется в соответствующую таблицу, иначе она записывается в новый файл.Как только весь файл пройден, новый файл копируется в старый файл, удаляя данные, уже введенные в базу данных.

Это копирование отбросило хорошие 3 минуты времени выполнения, просто перечитывая файл с отдельными лицами снова и снова.Но есть ли лучший подход к этому?Мое время выполнения для моих выборочных данных составляет ~ 47 секунд ... в идеале я бы хотел, чтобы это было меньше.

Любой совет, независимо от того, насколько тривиальным будет оценен.

РЕДАКТИРОВАТЬ: Это сокращениевниз код версии, которую я использую

<?php
//not shown:
//connect to database 
//input event data
//get the id of the event
//open files
$s_handle = fopen($_FILES['surveyfile']['tmp_name'],'r');//open survey file
copy($_FILES['cocklefile']['tmp_name'],'file1.csv');//make copy of the cockle file
//read files
$s_csv = fgetcsv($s_handle,'0',',');

//read lines and print lines
// then input data via sql

while (! feof($s_handle))
{
    $max_index = count($s_csv);
    $s_csv[$max_index]='';
    foreach($s_csv as $val)
    {
        if(!isset($val))
        $val = '';
    }
    $grid_no = $s_csv[0];
    $sub_loc = $s_csv[1];
    /*
    .define more variables
    .*/


    $sql = "INSERT INTO indipendant_event" 
        ."(parent_id,grid_number,sub_location,....)"
        ."VALUES ("
        ."'{$event_id}',"
        ."'{$grid_no}',"
        //...
        .");";

    if (!odbc_exec($con,$sql))
    {
        echo "WARNING: SQL INSERT INTO fssbur.cockle_quadrat FAILED. PHP.";
    }
    //get ID
    $sql = "SELECT MAX(ind_event_id)"
    ."FROM independant_event";
    $return =  odbc_exec($con,$sql);
    $ind_event_id = odbc_result($return, 1);

    //insert individuals
    $c_2 = fopen('file2.csv','w');//create file c_2 to write to 
    $c_1 = fopen('file1.csv','r');//open the data to read
    $c_csv = fgetcsv($c_1,'0',',');//get the first line of data
    while(! feof($c_1))
    {

        for($i=0;$i<9;$i++)//make sure theres a value in each column
        {
            if(!isset($c_csv[$i]))
            $c_csv[$i] = '';
        }
        //give values meaningful names
        $stat_no = $c_csv[0];
        $sample_method = $c_csv[1];
        //....

        //check whether the current line corresponds to the current station
        if (strcmp(strtolower($stat_no),strtolower($grid_no))==0)
        {
            $sql = "INSERT INTO fssbur2.cockle"
                ."(parent_id,sampling_method,shell_height,shell_width,age,weight,alive,discarded,damage)"
                ."VALUES("
                ."'{$ind_event_id}',"
                ."'{$sample_method}',"
                //...
                ."'{$damage}');";
            //write data if it corresponds
            if (!odbc_exec($con,$sql))
            {
                echo "WARNING: SQL INSERT INTO fssbur.cockle FAILED. PHP.";
            }     
            $c_csv = fgetcsv($c_1,'0',',');  
        }
        else//no correspondance
        {
            fputcsv($c_2,$c_csv);//write line to the new file
            $c_csv = fgetcsv($c_1,'0',',');//get new line
            continue;//rinse and repeat
        }
    }//end while, now gone through all individuals, and filled c_2 with the unused data
    fclose($c_1);//close files
    fclose($c_2);
    copy('file2.csv','file1.csv');//copy new file to old, removing used data
    $s_csv = fgetcsv($s_handle,'0',',');
}//end while

//close file
fclose($s_handle);
?>

Ответы [ 2 ]

3 голосов
/ 04 июля 2011

Возможно, я не полностью понял процесс, но почему бы просто не вставить весь CSV в таблицу базы данных. Это может показаться потраченной впустую работой, но, скорее всего, окупится. После того, как вы выполнили первоначальный импорт, поиск любого человека, связанного с событием, должен быть намного быстрее, поскольку СУБД сможет использовать индекс для ускорения этих поисков (по сравнению с вашим линейным обходом на основе файлов). Если быть точным: ваша "индивидуальная" таблица, вероятно, будет иметь внешний ключ в вашей таблице "Individual_event". Пока вы создаете индекс для этого внешнего ключа, поиск будет значительно быстрее (возможно, простое объявление этого поля внешним ключом приведет к тому, что SQL-сервер автоматически его индексирует, но я точно не могу сказать, я не я действительно использую MSSQL).

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

2 голосов
/ 04 июля 2011

Вы можете создать временную базу данных с данными из файлов, а затем использовать временную базу данных / таблицы для переноса данных в новую форму. Это, вероятно, работает быстрее, особенно если вам нужно выполнить поиск, и вам нужно пометить записи как обработанные.

...