woonem
@woonem

Насколько эффективен скрипт↓?

Вот примитивный скрипт БД для хранения ссылок для индексации:
<?php

define('xreservedmaxstrings', 1000000); //кол-во строк в списке
define('xreservedsize', 128); //длинна строки в списке

function mkfile($path){
    fclose(fopen($path, 'a'));
}

function putdata($data){

    $lock=fopen(__FILE__.'.1.lock', 'w+');
    flock($lock, LOCK_EX); //блокируем файл lock для избежания коллизий

    $i=1;
    while(true){
        if($i<16)
            $pre=0; //ведущий ноль

        $dir='./list/';
        $list=$dir.$pre.dechex($i).'.list'; //путь к списку

        if(!file_exists($dir))
            mkdir($dir); //если нет папки, создать

        if(!file_exists($list))
            mkfile($list); //если нет списка, создать

        if($i>255){
            $r=false;
            echo '<t>[u01] Lists are full.</t>'."\n";
            break;
        } //если заполнены 255 списков, выдать ошибку

        if(filesize($list)<(xreservedmaxstrings*(xreservedsize+1))){ //если список не заполнен
            $data.=str_repeat(' ', xreservedsize);
            $data=substr($data, 0, xreservedsize);
            file_put_contents($list, $data."\n", LOCK_EX|FILE_APPEND);
            $r=true;
            break;
        } //записать data в список, дополнив пробелами и обрезав, чтобы data весил xreservedsize байт

        $i++;
        $pre='';

    }

    flock($lock, LOCK_UN);
    fclose($lock);

    return $r;
}

function getdata($index){

    $lock=fopen(__FILE__.'.1.lock', 'w+');
    flock($lock, LOCK_EX); //блокируем файл lock для избежания коллизий

    $listindex=ceil($index/xreservedmaxstrings); //вычисляем номер списка
    $liststring=($index-($listindex-1)*xreservedmaxstrings); //вычисляем номер строки
    $pre='';
    if($listindex<16)
        $pre=0; //ведущий ноль

    $list='./list/'.$pre.dechex($listindex).'.list'; //путь к списку

    if(!file_exists($list)){
        echo '<t>[u02] Requested list is not exists.</t>'."\n";
        $r=false;
    } //если нет нужного списка, выдать ошибку
    elseif(filesize($list)<($liststring*(xreservedsize+1))){
        echo '<t>[u03] Requested string is not exists.</t>'."\n";
        $r=false;
    } //если нет нужной строки, выдать ошибку
    else{
        $listf=fopen($list, 'r');
        fseek($listf, (($liststring-1)*(xreservedsize+1)));
        $string=fgets($listf, xreservedsize);
        $r=rtrim($string, ' ');
    } //выдать строку, убрав лишние пробелы

    flock($lock, LOCK_UN);
    fclose($lock);

    return $r;
}

Насколько эффективно его использовать при общем объёме данных около 3 ГБ (xreservedmaxstrings будет больше)?
Может посоветуете какие-то технологии для более быстрой выборки, меньшего потребления памяти, а то я в БД ноль?
  • Вопрос задан
  • 484 просмотра
Решения вопроса 1
elevenelven
@elevenelven
Php Dev @ Amadeus
У вас непарное количество открывающих и закрывающих фигурных скобок.

xreservederror - это константа? А это $GLOBALS[xreservederror] что такое?

hexdec($i) я бы заменил на intval($i,16). Но hexdec('ff') вообще заменил бы на 255.

Создали бы переменную
$fileName = './db/'.$pre.dechex($i).'.list'

Вот этот кусок:
if($i<16)
      $pre=0;

    if(!file_exists('./db/'.$pre.dechex($i).'.list'))
      mkfile('./db/'.$pre.dechex($i).'.list');

Если $i>=16, то переменной $pre не будет.

Как указал 27cm, это что-то странненькое.
if($i>hexdec('ff')){
      return false;
      $GLOBALS[xreservederror].='<t>[u01] Database is full.</t>';
      break;
    }


Вот этот кусок:
$data.=str_repeat(' ', $size);
$data=substr($data, $size);

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

Было бы легче вам подсказать по коду, если бы вы объяснили что он делает, написали комментарии к некоторым мутным кускам кода, а также объяснили к чему в вашем вопросе тэг Базы данных.

---------------
UPD

О! Спасибо что откомментировали код, и стало немного яснее. Я понял ваш вопрос.
Вы хотите забабахать свое хранилище данных, на файловой системе. Объемы будут в районе 3ГБ.
---------
Я вам сейчас скажу крамольную вещь, но вроде очевидную. Файловая система, это не самый лучший вариант по быстродействию. А ваш код не предусматривает никакого кеширования.

Я бы отошел от идеи использовать свой велосипед. Индустрия изобрела для вас кучу различных хранилищ. Sql, NoSql, ключ-значение, хеш-таблицы. Вы хотите что-то хранить на диске?!
MySQL и Redis хранят данные на диске, но в то же время у них есть кеширование и механизмы оптимизации, выгрузка в RAM.

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

что на счёт быстродействия?
Быстродействие будет посредственное, а главное с коллизиями.

не нагнётся ничего при 3 ГБ данных?
Вы будете создавать излишнюю нагрузку на диск.
Вопрос надо ставить не в гигабайтах, а в обращениях в секунду. Диск захлебнется.
Ответ написан
Пригласить эксперта
Ответы на вопрос 1
27cm
@27cm
TODO: Написать статус
Хоть я и без приглашения, но кажется что-то тут не так:
if($i>hexdec('ff')){  // $i > 0xFF
    return false;

    // Сюда никогда не попадём =(

    // А тут ещё и undefined константа
    $GLOBALS[xreservederror].='<t>[u01] Database is full.</t>';
    break;
}


Неиспользуемая переменная:
$xreserveddbstrings=1000;


примитивный скрипт БД для хранения ссылок

Если вы что-то пишете и читаете из файла, файл от этого не становится базой данных.

В целом это говнокод, потому что:
  • Нет комментариев
  • Нет форматирования
  • Использование $GLOBALS для сохранения сообщений об ошибках, хотя для этого есть исключения
  • Fatal error, warning'и, ...
  • Дублирование кода видно невооруженным глазом:
    if(!file_exists('./db/'.$pre.dechex($listindex).'.list')){
        // ...
    }elseif(filesize('./db/'.$pre.dechex($listindex).'.list')<($liststring*($size+1))){
        // ...
    }else{
        $listf=fopen('./db/'.$pre.dechex($listindex).'.list', 'r');
        fseek($listf, ($liststring*($size+1)));
        // ...
    }



Насколько эффективно его использовать при общем объёме данных около 3 ГБ (xreservedmaxstrings будет больше)?

Что мешает, сгенерировать 3Гб данных и проверить, замерить время и память?
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы