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

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 = '';
  }
}
 
Автор оригинала: SiMM
zarus, а зачем fopen в цикле делать?
А зачем держать файл открытым? хз. Поясните, почему я "не прав"?
Просто у меня обычно буфер больше пары мегабайт, а эта пара мегабайт набегает несколько минут.
 
zarus
вся проблема в том, что мне нужно писать в файл по столбцам, а ты по строкам пишешь.
 
Автор оригинала: white phoenix
zarus
А почему \x09 а не \t?
А не все ли равно? :) все одно - символ табуляции...

-~{}~ 18.01.06 09:38:

Автор оригинала: Poltoraki
zarus
вся проблема в том, что мне нужно писать в файл по столбцам, а ты по строкам пишешь.
Вопрос: а зачем тебе писать в файл по столбцам? Что это тебе даст?
А еще лучше - сформулируй конечную цель твоих извращений.
 
а если массив со строками юзать вместо двухмерных массивов, типа:
PHP:
while ($row = mysql_fetch_row($result)) 
{ 
    for ($i=0; $i < $count_arrOPColumns; $i++) 
    { 
        $TransposedData[$i] .= $row[$i] . ', '; 
    } 
}
ИМХО, должно быть быстрее...
 
zarus
это давт мне требуемую структуру файла. Посмотри изначальный пост я там писал об этом. Если более детально, то мне надо сформировать cdl файл, чтобы потом из него получить NetCDF файл :)


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

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

-~{}~ 18.01.06 17:14:

Дошло, что ему нужно повернуть таблицу на 90 градусов... ну-ну...
 
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:

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

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

Код:
a1 a2 a3 a4
b1 b2 b3 b4
c1 c2 c3 c4

MySQL в любом случае возвражает результат именно по строкам, твоя задача за минимальное число проходов (в идеале за один проход) обработать то что вернул MySQL.

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

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

Если я правильно понял, что тебе нужно, то как раз приведенный мною выше код это и делает. Там потом только нужно будет последовательно в цикле вывести все строки из массива в файл заменив последнюю запятую в каждой строке, на точку с запятой и приблудами.
Если неправильно понял то опиши на примере, что у тебя есть и что тебе нужно получить в итоге в файле.
 
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);
	}
 
Внимательнее присмотрись к
PHP:
$TransposedData[$i] .= $row[$i] . ', ';
У тебя в результате будет массив вида
0 => a0, a1, a2,
1 => b0, b1, b2,
.....

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