Оптимизация парсинга очень большой выборки из БД

zarus

Хитрожопый макак
PHP:
...
$file_out = fopen('somefile.dat','w');
while (false !== ($row = mysql_fetch_row($result))) {
  fwrite($file_out,$some_info."\x09".implode("\x09",$row));
}
fclose($file_out);
Минимум памяти сжирает.
Можно еще и на файловую систему нагрузку уменьшить.
PHP:
...
$buffer = '';
while ($row = mysql_fetch_row($result))
{
  $buffer .= $some_info."\t".implode("\t",$row."\n\r");
  if (strlen($buffer) > 8096) {
    $file_out = fopen('somefile.dat','a');
    fwrite($file_out,$buffer);
    fclose($file_out);
    $buffer = '';
  }
}
 

zarus

Хитрожопый макак
Автор оригинала: SiMM
zarus, а зачем fopen в цикле делать?
А зачем держать файл открытым? хз. Поясните, почему я "не прав"?
Просто у меня обычно буфер больше пары мегабайт, а эта пара мегабайт набегает несколько минут.
 

Poltoraki

Новичок
zarus
вся проблема в том, что мне нужно писать в файл по столбцам, а ты по строкам пишешь.
 

zarus

Хитрожопый макак
Автор оригинала: white phoenix
zarus
А почему \x09 а не \t?
А не все ли равно? :) все одно - символ табуляции...

-~{}~ 18.01.06 09:38:

Автор оригинала: Poltoraki
zarus
вся проблема в том, что мне нужно писать в файл по столбцам, а ты по строкам пишешь.
Вопрос: а зачем тебе писать в файл по столбцам? Что это тебе даст?
А еще лучше - сформулируй конечную цель твоих извращений.
 

vovanium

Новичок
а если массив со строками юзать вместо двухмерных массивов, типа:
PHP:
while ($row = mysql_fetch_row($result)) 
{ 
    for ($i=0; $i < $count_arrOPColumns; $i++) 
    { 
        $TransposedData[$i] .= $row[$i] . ', '; 
    } 
}
ИМХО, должно быть быстрее...
 

Poltoraki

Новичок
zarus
это давт мне требуемую структуру файла. Посмотри изначальный пост я там писал об этом. Если более детально, то мне надо сформировать cdl файл, чтобы потом из него получить NetCDF файл :)


vovanium
да, это именно тот вариант "по частям" на котором я и остановился, и который упоминал _RVK_. Только я реализовал его не через mysql_fetch_row, а через mysql_result просто чтобы меньше данных гонять. И опять-таки: ты по строкам читаешь, а мне по столбцам надо. Именно из-за этого вся головная боль.
 

zarus

Хитрожопый макак
Автор оригинала: Poltoraki
да, это именно тот вариант "по частям" на котором я и остановился, и который упоминал _RVK_. Только я реализовал его не через mysql_fetch_row, а через mysql_result просто чтобы меньше данных гонять. И опять-таки: ты по строкам читаешь, а мне по столбцам надо. Именно из-за этого вся головная боль.
Головная боль у тебя от того, что ты не можешь понять, что в файл можно писать только построчно.
Но тебе надо писать по столбцам. А по диагонали не пробовал? Вроде быстрее работает.
Вот когда просветлеешь до состояния понимания что для записи в файл тебе нужно сформировать строку - приходи и задавай вопросы.

з.ы. Я даже знаю, как решить задачу твоим извращенным способом, но решение выкладывать не буду. Потому что оно "неправильное".

-~{}~ 18.01.06 17:14:

Дошло, что ему нужно повернуть таблицу на 90 градусов... ну-ну...
 

Poltoraki

Новичок
zarus
мне не писать по столбцам, а читать рекордсет по столбцам надо. Пожалуйста, прочитай еще раз все внимательно :)
 

zarus

Хитрожопый макак
хз, скорее всего велосипед изобрел
PHP:
function transpond_matrix(&$matrix) {
  if (!is_array($matrix)) {
    echo "Input error on line ".__LINE__.": not a Matrix!<br />";
    return false;
  }
  $array_data['columns_key'] = array_keys($matrix);
  $array_data['columns_cnt'] = count($array_data['columns_key']);
  $row = $matrix[$array_data['columns_key'][0]];
  $single_row = false;
  if (!is_array($row)) {
    $single_row = true;
    $array_data['rows_key'] = array('a');
    $array_data['rows_cnt'] = 1;
  } elseif (!empty($row)) {
    $array_data['rows_key'] = array_keys($row);
    $array_data['rows_cnt'] = count($array_data['rows_key']);
  } else {
    echo "Input error on line ".__LINE__.": not a Matrix!<br />";
    return false;
  }
  $new_matrix = array();
  reset($matrix);
  for ($i = 0; $i < $array_data['columns_cnt']; $i++) {
    $row_key = $array_data['columns_key'][$i];
    for ($j = 0; $j < $array_data['rows_cnt']; $j++) {
      $col_key = $array_data['rows_key'][$j];
      $new_matrix[$col_key][$row_key] = !$single_row ? $matrix[$row_key][$col_key] : $matrix[$row_key];
    }
  }
  return $new_matrix;
}
$test_array = ''; // Empty rowset - not a Matrix
print_r(transpond_matrix($test_array));
echo '<hr />';
$test_array = array(array()); // Empty colset - not a Matrix
print_r(transpond_matrix($test_array));
echo '<hr />';
$test_array = array(1,2,3);
print_r($test_array);
echo '<br />';
print_r(transpond_matrix($test_array));
-~{}~ 18.01.06 17:59:

Автор оригинала: Poltoraki
zarus
мне не писать по столбцам, а читать рекордсет по столбцам надо. Пожалуйста, прочитай еще раз все внимательно :)
А не все ли равно, как читать? Тебе шашечки, или доехать?

-~{}~ 18.01.06 18:02:

з.ы. Сам придумай, куда функцию применить.
 

vovanium

Новичок
Poltoraki
И опять-таки: ты по строкам читаешь, а мне по столбцам надо.
Что-то я не пойму тебе важен процесс чтения запроса или формат итогового файла? :)

Смотри, например, у тебя есть таблица

Код:
a1 a2 a3 a4
b1 b2 b3 b4
c1 c2 c3 c4
MySQL в любом случае возвражает результат именно по строкам, твоя задача за минимальное число проходов (в идеале за один проход) обработать то что вернул MySQL.

Тебе насколько можно понять из твоего кода нужно сделать что-то типа ini-файла в котором данные будут записываться в виде:

ИмяСтолбика_№1 = a1, b1, c1;
...
ИмяСтолбика_№4 = a4, b4, c4;

Если я правильно понял, что тебе нужно, то как раз приведенный мною выше код это и делает. Там потом только нужно будет последовательно в цикле вывести все строки из массива в файл заменив последнюю запятую в каждой строке, на точку с запятой и приблудами.
Если неправильно понял то опиши на примере, что у тебя есть и что тебе нужно получить в итоге в файле.
 

Poltoraki

Новичок
vovanium
мы тут наверное запутались немного. Давай сначала.
Как я понимаю MySQL возвращает рекордсет в таком виде:
a0, b0, c0 ...
a1, b1, c1 ...
a2, b2, c2 ...
где a,b,c имена соответствущих столбцов в таблице базы данных.
Теперь мне надо рекордсет записать в файл в виде
a = все значения а
b = все значения b
......
n = все значения n
PHP:
//твой код:
while ($row = mysql_fetch_row($result)) // скажем в $row имеем: a0, b0, c0 ...  n0.
{  
    for ($i=0; $i < $count_arrOPColumns; $i++)  
    {  
        $TransposedData[$i] .= $row[$i] . ', ';  // в $TransposedData  после завершения for имеем: a0, b0, c0 ...  n0
    }  
}
а мне надо чтобы там было а0, а1, а2....
На чем остановился я:
PHP:
for ($i = 0; $i < $count_arrOPColumns; $i++)
{
	fwrite ($fp, "{$_SESSION['arrOPColumns'][$i]} = ");
	for ($j = 0; $j < $_SESSION['totalrows']; $j++)
	{
		$r[] = mysql_result($result, $j, $i);
	}
 

vovanium

Новичок
Внимательнее присмотрись к
PHP:
$TransposedData[$i] .= $row[$i] . ', ';
У тебя в результате будет массив вида
0 => a0, a1, a2,
1 => b0, b1, b2,
.....

Так у тебя значения из столбика $i записывается в массив $TransposedData с ключом $i. И в итоге у тебя получится массив с количеством элементов равным количеству столбцов.
Ты что колоду карт никогда по мастям не раскладывал? Ты не выбираешь сначала все пиковые карты, потом по-второму кругу перебираешь карты откладывешь бубновые и т.п. Проще сразу раскладывать их на 4 кучки :)
 

Poltoraki

Новичок
Все, понял, сорри за тормоз :) Я и так тоже пробовал уже, только написав чуть по-другому. Но это уже детали и личные преференции как писать. Сермяжная правда найдена, думаю что тему можно закрывать:)
 

vovanium

Новичок
Ты приводил код с двухмерным массивом, а тут обычный массив со строками, он должен быть быстрее. Так что пробуй :)
 
Сверху