LINUX.ORG.RU
решено ФорумTalks

Выдержит ли SQLite нагрузку уровня linux.org.ru?

 ,


1

3

всем привет я пишу сайт на пхп четыре (из-за pdo это пока не получается, поэтому если есть замена pdo для работы с различными бд — подскажите)

главная фича моего движка в простой кодовой базе, в которой разберётся любой начинающий программист на html, css и php

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

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

все сообщения на сайте — как статьи на википедии, или как сообщения на ЛОРе, могут редактироваться сколько угодно раз и хранить всю историю изменений. весь ключевой вопрос лишь в том, способен ли выдержать SQLite такую нагрузку, или же придётся смотреть в сторону другой базы данных???

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

у меня своя собственная реализация сессий, которая никак не связана со встроенными сессиями на пхп и никак их не использует. то есть session_*(); и $_SESSION не задействуются. моя реализация позволяет более тонко контролировать все нюансы, например, не создавать пустую сессию «в холостую», или например точно определить, что в папке на диске достаточно места для хранения данных сессии.

вот пример базы данных для сообщений. они хранят всю историю изменений.

CREATE TABLE IF NOT EXISTS 'post'
(
	'id' INTEGER PRIMARY KEY,
	'domain' NVARCHAR(255) DEFAULT NULL,
	'sub_reply' INTEGER DEFAULT NULL,
	'date_created' DATETIME DEFAULT CURRENT_TIMESTAMP,
	'date_modified' DATETIME DEFAULT NULL,
	'flags' NVARCHAR(200) DEFAULT NULL
);

CREATE TABLE IF NOT EXISTS 'post_history'
(
	'id' INTEGER PRIMARY KEY,
	'sub_post' INTEGER NOT NULL,
	'ref_text' INTEGER NOT NULL,
	'date_created' DATETIME DEFAULT CURRENT_TIMESTAMP,
	'date_modified' DATETIME DEFAULT NULL
);

CREATE TABLE IF NOT EXISTS 'post_text'
(
	'id' INTEGER PRIMARY KEY,
	'text' TEXT DEFAULT NULL,
	'text_headers' TEXT DEFAULT NULL
);

сам текст сообщений хранится отдельно в третьей таблице, это сделано потому, что у каждой базы данных (конкретно у MySQL и PostgreSQL) на этот счёт разное мнение. кто-то хранит TEXT и BLOB далеко за пределами основной таблицы, чтобы минимизировать нагрузку при выборке из базы, а кто-то хранит там же рядышком. правильнее будет хранить TEXT отдельно. поэтому храню.

я не осилил ООП и не смог написать на классах, поэтому я писал на функциях, и я их назвал неклассами.

в папочке ./src/noclass/ у меня лежат следующие неклассы.

database.noclass.php:

<?php

function db_directory_sqlite() {
    return dirname($_SERVER['DOCUMENT_ROOT']) . '/db';
}

function db_connect($db_dsn = null, $db_username = null, $db_password = null, $db_attributes = null) {

    $db = false;

    if (strpos($db_dsn, 'sqlite:') == 0) {
        $db_file = substr($db_dsn, strlen('sqlite:'));
        if ($db_file == ':memory:') {
            $db = true;
        }
        elseif (is_writeable(db_directory_sqlite())) {
            $db = true;
        }
    }

    if ($db == false) {
        return false;
    }

    $db = db_connect_retry($db_dsn, $db_username, $db_password, $db_attributes);

    return $db;

}

function db_connect_retry($db_dsn, $db_username, $db_password, $db_attributes) {

    $db = false;

    while ($db == false) {
        try {
            $db = new PDO($db_dsn, $db_username, $db_password, $db_attributes);
        }
        catch (Exception $e) {
            if (stripos($e->getMessage(), 'DATABASE IS LOCKED')) {
                usleep(50000);
                continue;
            }

            return false;
        }
    }

    return $db;

}

function db_open_sqlite_in_memory() {
    $db_file = false;
    $db_dsn = 'sqlite::memory:';

    $db = db_connect($db_dsn);

    return $db;
}

function db_open_sqlite($db_file) {

    if ($db_file == ':memory:') {
        $db = db_open_sqlite_in_memory();

        return $db;
    }

    $db_dsn = 'sqlite:' . $db_file;

    $db = db_connect($db_dsn);

    return $db;
}

function db_open($db_dsn) {
    $db = db_open_sqlite($db_dsn);

    return $db;
}

function db_exec($db, $query_string) {
    $query = $db->exec($query_string);

    return $query;
}

function db_query($db, $query_string) {
    $query = $db->query($query_string);

    return $query;
}

function db_run($db, $query_string, $query_args = false) {
    if ($query_args == false) {
        $query = db_query($db, $query_string);

        return $query;
    }

    $query = $db->prepare($query_string);
    $query->execute($query_args);

    return $query;
}

function db_begin_transaction($db) {
    $query = $db->beginTransaction();

    return $query;
}

function db_is_transaction($db) {
    $query = $db->inTransaction();

    return $query;
}

function db_rollback($db) {
    $query = $db->rollBack();

    return $query;
}

function db_commit($db) {
    $query = $db->commit();

    return $query;
}

function db_last_id($db) {
    $query = $db->lastInsertId();

    return $query;
}

function db_insert($db, $table, $values) {

    $keys = array_keys($values);

    $values = array_values($values);

    $columns = array();
    foreach ($keys as $item) {
        $columns[] = "'$item'";
    }
    $columns = implode(',', $columns);

    $placeholders = array();
    foreach ($keys as $item) {
        $placeholders[] = "?";
    }
    $placeholders = implode(',', $placeholders);

    $query = "INSERT INTO $table ($columns) VALUES ($placeholders);";

    $query = db_run($db, $query, $values);

    return $query;

}

function db_update($db, $table, $value, $where) {

    $collection = array_merge($value, $where);
    $collection = array_values($collection);

    $fields = array();
    foreach ($value as $item => $data) {
        $fields[] = "$item = ?";
    }
    $fields = implode(',', $fields);

    $places = array();
    foreach ($where as $item => $data) {
        $places[] = "$item = ?";
    }
    $places = implode(' AND ', $places);

    $query = "UPDATE $table SET $fields WHERE $places;";

    $query = db_run($db, $query, $collection);

    return $query;

}

function db($db_name) {
    $db_file = db_directory_sqlite() . DIRECTORY_SEPARATOR . $db_name;

    $db = db_open($db_file);

    return $db;
}

post.noclass.php:

<?php

function post_insert($text_headers, $text, $replyto = false) {

    $db = db('example.db');

    if ($db == false) {
        return false;
    }

    db_begin_transaction($db);

    if (db_post_insert($db, $text_headers, $text, $replyto)) {

        db_commit($db);

        return true;

    }

    db_rollback($db);

    return false;

}

function db_post_insert($db, $text_headers, $text, $replyto = false) {

    if ($replyto == false) {

        $id = db_post_insert_id($db);

        if ($id == false) {
            return false;
        }

    }
    else {

        $replyto = db_post_select_id_single($db, $replyto);

        if ($replyto == false) {
            return false;
        }
        else {

            $id = db_post_insert_id($db);

            if ($id == false) {
                return false;
            }

        }
 
    }

    if (db_post_insert_post($db, $id, $replyto)) {

        $ref_text = db_post_insert_post_text($db, $text_headers, $text);

        if ($ref_text == false) {
            return false;
        }

        if (db_post_insert_post_history($db, $id, $ref_text)) {
            return $id;
        }

    }

    return false;

}

function db_post_insert_id($db) {

    $value = array(
        'id' => null
    );
    
    db_insert($db, 'post', $value);

    return db_last_id($db);

}

function db_post_select_id_single($db, $id) {

    $value = array(
        'id' => $id
    );
    
    $query = 'SELECT id FROM post WHERE id = :id;';

    $query = db_run($db, $query, $value);

    $row = $query->fetch();

    return ($row == false) ? false : $row['id'];

}

function db_post_insert_post($db, $id, $replyto = false) {

    $date_created = date('Y-m-d H:i:s', time());
    $date_modified = null;

    $search = array(
        'id' => $id
    );
    
    $entry = array(
        'id' => null,
        'domain' => null,
        'sub_reply' => $replyto,
        'date_created' => $date_created,
        'date_modified' => $date_modified,
        'flags' => null
    );

    // remove false, null and other zero-values from entry
    $entry = array_filter($entry);

    if (db_update($db, 'post', $entry, $search)) {
        return $id;
    }

    return false;

}

function db_post_insert_post_text($db, $text_headers, $text) {

    if ($text_headers == false) {
        //nothing to do -- skip headers
    }
    else {
        $text_headers = serialize($text_headers);
    }

    $entry = array(
        'id' => null,
        'text' => $text,
        'text_headers' => $text_headers
    );

    // remove false, null and other zero-values from entry
    $entry = array_filter($entry);

    if (db_insert($db, 'post_text', $entry)) {
        return db_last_id($db);
    }

    return false;

}

function db_post_insert_post_history($db, $sub_post, $ref_text) {

    $date_created = date('Y-m-d H:i:s', time());
    $date_modified = null;

    $entry = array(
        'id' => null,
        'sub_post' => $sub_post,
        'ref_text' => $ref_text,
        'date_created' => $date_created,
        'date_modified' => $date_modified
    );

    // remove false, null and other zero-values from entry
    $entry = array_filter($entry);

    if (db_insert($db, 'post_history', $entry)) {
        return db_last_id($db);
    }

    return false;

}

function db_post_select_count($db) {

    $query = db_query($db, 'SELECT COUNT(*) as sizeof FROM post;');

    $row = $query->fetch();

    return $row['sizeof'];

}

function post_update($id, $text_headers, $text) {

    $db = db('example.db');

    if ($db == false) {
        return false;
    }

    db_begin_transaction($db);

    if (db_post_update($db, $id, $text_headers, $text)) {

        db_commit($db);

        return true;

    }

    db_rollback($db);

    return false;

}

function db_post_update($db, $id, $text_headers, $text) {

    $id = db_post_select_id_single($db, $id);

    if ($id == false) {
        return false;
    }

    if (db_post_update_post($db, $id)) {

        $ref_text = db_post_insert_post_text($db, $text_headers, $text);

        if ($ref_text == false) {
            return false;
        }

        if (db_post_insert_post_history($db, $id, $ref_text)) {
            return $id;
        }

    }

    return false;

}

function db_post_update_post($db, $id) {

    $date_created = null;
    $date_modified = date('Y-m-d H:i:s', time());

    $search = array(
        'id' => $id
    );
    
    $entry = array(
        'id' => null,
        'domain' => null,
        'sub_reply' => null,
        'date_created' => $date_created,
        'date_modified' => $date_modified,
        'flags' => null
    );

    // remove false, null and other zero-values from entry
    $entry = array_filter($entry);

    if (db_update($db, 'post', $entry, $search)) {
        return $id;
    }

    return false;

}

function db_post_select_id($db, $id = false) {

    if ($id == false) {
        return false;
    }

    $value = array(
        'id' => $id
    );

    $query = '
SELECT * FROM post
INNER JOIN post_history AS initial ON (initial.sub_post = post.id AND initial.id = (SELECT id FROM post_history WHERE sub_post = post.id ORDER BY id ASC LIMIT 1))
INNER JOIN post_history AS current ON (current.sub_post = post.id AND current.id = (SELECT id FROM post_history WHERE sub_post = post.id ORDER BY id DESC LIMIT 1))
INNER JOIN post_text ON post_text.id = current.ref_text
WHERE post.id = :id
';

    $query = db_run($db, $query, $value);

    $row = $query->fetch();

    $row = post_row($row);

    return $row;

}

function db_post_select_page($db, $page = false, $limit = 10) {

    $pages = (db_post_select_count($db) / $limit);
    $pages = ceil($pages);

    if ($page == false) {
        $page = $pages;
    }
    elseif ($page > $pages) {
        $page = $pages;
    }
    elseif ($page < 1) {
        $page = $pages;
    }

    $offset = ($page - 1) * $limit;

    // should I make it more stronger?
    // escape offset and limit
    $query = '
SELECT * FROM post
INNER JOIN post_history AS initial ON (initial.sub_post = post.id AND initial.id = (SELECT id FROM post_history WHERE sub_post = post.id ORDER BY id ASC LIMIT 1))
INNER JOIN post_history AS current ON (current.sub_post = post.id AND current.id = (SELECT id FROM post_history WHERE sub_post = post.id ORDER BY id DESC LIMIT 1))
INNER JOIN post_text ON post_text.id = current.ref_text
ORDER BY id DESC LIMIT ' . $limit . ' OFFSET ' . $offset . ';
';

    $query = db_query($db, $query);

    $array = array();

    while ($row = $query->fetch()) {

        $array[] = post_row($row);

    }

    return $array;

}

function post_row($row) {

    if ($row == false) {
        return false;
    }

    if ($row['date_created'] == null) {
        $row['date_created'] = '(unavailable)';
    }

    if ($row['date_modified'] == null) {
        $row['date_modified'] = '(unavailable)';
    }

    if (empty($row['text_headers'])) {
        $row['text_headers'] = array();
    }
    else {
        $row['text_headers'] = unserialize($row['text_headers']);
    }

    if (empty($row['text_headers']['title'])) {
        $row['text_headers']['title'] = '';
    }

    return $row;

}

function post_escape($text) {

    $text = htmlspecialchars($text, ENT_NOQUOTES, 'UTF-8');
    $text = nl2br($text);

    return $text;

}

function post_input_filtered($text) {

    $text = htmlspecialchars($text, ENT_QUOTES, 'UTF-8');

    return $text;

}

function post_text_filtered($text) {

    $text = htmlspecialchars($text, ENT_NOQUOTES, 'UTF-8');

    return $text;

}

session.noclass.php

<?php

function session_directory() {
    return dirname($_SERVER['DOCUMENT_ROOT']) . DIRECTORY_SEPARATOR . 'db' . DIRECTORY_SEPARATOR . 'sess';
}

function session_open($session_name = 'ident') {

    $session_id = session_open_if_cookie_is_set($session_name);

    if ($session_id == false) {
        $session_id = session_new($session_name);
    }

    return $session_id;

}

function session_open_if_cookie_is_set($session_name = 'ident') {

    if (isset($_COOKIE[$session_name])) {
        $session_id = $_COOKIE[$session_name];

        if (strlen(str_replace(array('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'), '', $session_id)) > 0) {
            $session_id = session_new($session_name);
        }

        return $session_id;
    }

    return false;

}

function session_load($session_id) {

    $session_file = session_directory() . DIRECTORY_SEPARATOR . $session_id;
    $session_data = false;

    if ($fp = @fopen($session_file, 'r')) {
        flock($fp, LOCK_SH);
        $session_data = fread($fp, filesize($session_file));
        $session_data = unserialize($session_data);
        flock($fp, LOCK_UN);
        fclose($fp);
    }

    if (is_array($session_data)) {
        return $session_data;
    }

    return array();

}

function session_save($session_id, $session_data = array()) {

    $session_file = session_directory() . DIRECTORY_SEPARATOR . $session_id;
    $session_data = serialize($session_data);

    if ($fp = @fopen($session_file, 'w+')) {
        flock($fp, LOCK_EX);
        $bytes_written = fwrite($fp, $session_data);
        flock($fp, LOCK_UN);
        fclose($fp);
    }

    return $bytes_written;

}

function session_new($session_name) {

    if (headers_sent()) {
        return false;
    }

    $session_id = bin2hex(session_random_bytes(8));

    $cookie_lifetime = 0;
    $cookie_path = '/';
    $cookie_domain = '';
    $cookie_secure = false;
    $cookie_httponly = false;

    if (setcookie($session_name, $session_id, $cookie_lifetime, $cookie_path, $cookie_domain, $cookie_secure, $cookie_httponly) == false) {
        return false;
    }

    return $session_id;

}

function session_random_bytes($length = 32) {
    
    $random_bytes = '';

    for ($i = 0; $i < $length; $i++) {
        $random_bytes .= chr(rand(0, 255));
    }

    return $random_bytes;

}

function session() {

    $id = session_open();

    if ($id == false) {
        return false;
    }

    $session = session_load($id);

    return $session;

}

вот вам небольшая инструкция как использовать сессии

вы просто делаете $session = session(); и создаётся новая сессия и в переменную $session загружается массив со всеми данными сессии.

если вы хотите что-то сохранить в сессию, то вы должны проделать все действия вручую:

// создаём новую сессию
// в $id помещается идентификатор сессии, ну типа PHPSESSID
$id = session_open();

// загружаем данные сессии в переменную $session
// можно для этого использовать $_SESSION но я не хочу и не буду
$session = session_load($id);

// создаём в $session приветствие
$session = array('greeting' => 'hello world!');

// сохраняем данные сессии, за вас это никто не сделает
session_save($id, $session);

есть такой забавный момент, когда мы не хотим создавать сессию, если у пользователя её нету. для этого есть функция session_open_if_cookie_is_set();, которая запускает сессию только при наличии куки.

в целом моя реализация сессий лучше пхпшной т.к. она не создаёт пустых файлов!!! каждый момент вы контролируете сами!!!

теперь давайте я вам расскажу про сообщения а-ля википедия или лор.

для отправки сообщения я делаю так:

$headers = array(
    'title' => 'заголовок письма'
);

$content = 'текст письма';

post_insert($headers, $content);

как вы знаете у сообщения есть не только его содержимое, не только сам текст сообщения. у сообщения есть мета-данные, такие как заголовок, тэги, ну ещё что-нибудь может быть. поэтому все эти мета-данные помещаются в отдельный массив.

затем при выборке сообщения из базы мы можем сравить, сделать diff не только на сам текст сообщения, но и на все заголовки тоже сделать diff и увидеть различия между двумя версиями сообщения включая всю мета-информацию, — заголовки, теги. теперь вы понимаете почему я решил так сделать.

функция post_insert(); вернёт просто true в случае узбека. иначе false.

для того, чтобы отредактировать сообщение, есть функция post_update();, но первым параметром ещё нужно указать ID сообщения.

например мы только что добавили сообщение, его ID 1, теперь мы хотим его отредактировать.

$id = '1';

$headers = array(
    'title' => 'заголовок письма (отредактировано)'
);

$content = 'исправленный текст письма';

post_update($id, $headers, $content);

и теперь в базу будет сохранена новая версия сообщения.

выполняем sqlite example.db .dump и смотрим

INSERT INTO post VALUES(1,NULL,NULL,'2022-07-17 06:24:55','2022-07-17 06:25:26',NULL);

INSERT INTO post_history VALUES(1,1,1,'2022-07-17 06:24:55',NULL);
INSERT INTO post_history VALUES(2,1,2,'2022-07-17 06:25:26',NULL);

INSERT INTO post_text VALUES(1,'текст письма','a:1:{s:5:"title";s:31:"заголовок письма";}');
INSERT INTO post_text VALUES(2,'исправленный текст письма','a:1:{s:5:"title";s:64:"заголовок письма (отредактировано)";}');

по факту сообщение одно, а ревизии у него две! так-то!

для того, чтобы прочитать сообщение в массив мы подключаемся к базе данных и выполняем одну функцию, указав ID сообщения

$db = db('example.db');

if ($db == false) {
    return false;
}

$post = db_post_select_id($db, $_GET['id']);

var_dump($post);

для того, чтобы вывести страницу со списком сообщений есть функция db_post_select_page($db, $_GET['page']);

в целом мой код будет очень хорошо документирован, но это чуть попозже, пока только реализация.

мой код написан очень качественно на совесть, писал для себя.

очень скоро будет релиз и я создаю отдельный сайт посвящённый своей цмс на пхп четыре. оцените качество кода, насколько он красив и хорош, и очень строгий!

главный вопрос — выдержит ли такая структура базы данных на SQLite нагрузку с бесконечным редактированием сообщений???

★★★★★

Ответ на: комментарий от crutch_master

Он просто кроме баша ничего не осиливает, к сожалению. А пхп это такой баш, только еще сайты можно делать.

untitl3d
()

На современном пхп нельзя что ли писать как на пхп4? Проясните, эксперты. А то вдруг Спуфи нас троллит. Не верю в это, но мало ли.

bread
()
Ответ на: комментарий от bread

На современном пхп нельзя что ли писать как на пхп4?

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

tiinn ★★★★★
()

Четвёртой версии PHP всего-навсего 22 года. Рекомендую дополнить проект скриптами на Perl 4, Python 1.4. Бизнес-логику для биллинга написать на КОБОЛ. Это всё очень нужные и востребованные языки. Изучив их, можно будет найти работу даже в разгар кризиса, который уже потихоньку идёт.

emorozov
()
Ответ на: комментарий от Spoofing

а девушки не хотят со мной встречаться

Найди не фуфлыжный кросс-фит зал. Так как там надо «раотать над собой», а также это позволяет упорным девушкам с проблемами придти в форму, то там ты и себе мозги вправишь, и нормальную девушку найдёшь.

https://yandex.ru/maps/213/moscow/search/кроссфит/filter/group_classes/crossf...

Shadow ★★★★★
()
Ответ на: комментарий от bread

На современном пхп нельзя что ли писать как на пхп4?

Можно, но Спуфи видимо хочет своему проекту фишечку, что он может работать на старых… эээ… мда…

goingUp ★★★★★
()
Ответ на: комментарий от Shadow

Найди не фуфлыжный кросс-фит зал. Так как там надо «раотать над собой»

Советчики фиговы. Если он есть майонез каждый день, то его сердце уже перегружено лишними жирами. Сначала нужно привести мысли в порядок, начать нормально есть и только потом идти в спортзал. Иначе будет двойная перегрузка сердца и вообще жить перехочется. Чем больше перегрузка сердца, тем больше депрессия. Проверено на себе.

xwicked ★★☆
()
Ответ на: комментарий от xwicked

Ну тогда к врачу! Но тут в контексте пхп4 уже советовали.

Shadow ★★★★★
()
Последнее исправление: Shadow (всего исправлений: 1)
Ответ на: комментарий от xwicked

Если он есть майонез каждый день, то его сердце уже перегружено лишними жирами.

Вот откуда мысли о пхп4. Майонез нашептал.

bread
()
Ответ на: комментарий от ox55ff

Не в смузихлеба же! Вот если бы он какое производство наладил…

dk__
()

Выдержит ли SQLite нагрузку уровня linux.org.ru?

Нагрузка на LOR: по сообщению раз в несколько минут. Это запись. Большая часть — чтение. Думаю, SQLite3 вполне себе выдержит. Вполне остаётся запас на всякую обработку статистики, начисления скора и тому подобное.

i-rinat ★★★★★
()
Последнее исправление: i-rinat (всего исправлений: 1)

Прогони нагрузочный тест и узнаешь

WindowsXP ★★
()
Ответ на: комментарий от crutch_master

Это сейчас по трекеру примерно такая скорость. Вполне похоже на пик. Если посчитать по последним 250 сообщениям, вообще выходит сообщение раз в 23 минуты. Примерно.

i-rinat ★★★★★
()
Ответ на: комментарий от i-rinat

Да.. херня это всё, на 3.5 человека. Он каждый запрос дрочит диск. Зачем? Ну, впрочем, ссд быстрый, чтобы не подрочить ссд. Можно вообще в фс дописывать посты в фаел, а разделы форума = каталоги и не делать могз. Что-то надо будет, посты прогрепал, спуфинг грепать уже умеет.

crutch_master ★★★★★
()
Последнее исправление: crutch_master (всего исправлений: 2)
Ответ на: комментарий от crutch_master

Он каждый запрос дрочит диск. Зачем?

Потому что Durability из ACID того требует. Вроде бы отключается. Не пробовал.

i-rinat ★★★★★
()

выдержит ли такая структура базы данных на SQLite нагрузку

Могу только дать совет в стиле Капитана - писать код так, чтобы настройка движка позволял задействовать разные СУБД. Так сделано, например, в OpenSimulator (но там не PHP, а C#).

Лично я делал проект, поддерживающий PostgreSQL и SQLite на выбор пользователя, у меня были C++ с QtSql. Работало успешно, хотя какие-то нюансы разных СУБД приходилось держать в голове при разработке.

P.S. Впрочем, судя по упоминанию PDO, мой совет уже запоздал…

hobbit ★★★★★
()
Последнее исправление: hobbit (всего исправлений: 1)
Ответ на: комментарий от crutch_master

Сейчас осознал, что криво посчитал. Смотрел по трекеру, а трекер не показывает всю историю сообщений. Он показывает темы. Так что за четверо суток не 250 сообщений, а 2929. В среднем по одному сообщению в 117 секунд. Ночью, очевидно, глушь, а днём всё веселее. И это ещё без учёта удалённых.

Но всё равно думаю, что SQLite3 справится, скорее всего.

i-rinat ★★★★★
()
Ответ на: комментарий от Shadow

Мужики, ели чего, без обид. Всю ночь работал, зашел почитать — не могу сдержаться.

Бар. Полночь. Идет важный разговор двух форумчан…

E: - Две тысячи двадцать второй год на дворе, а у многих дэ-йе нормальной поддержки вэйлэнд нет

S: - Двадцать второй год баб нет… Нормальных нет… баб… (опрокидывает стопку) во всем Мире ни одной…

E: - Да, бро, как я тебя понимаю! Нормальных совсем нет! Все на этих иксах сидят. Тормозят… мировой прогресс

S: - Во-во, всё это бабы виноваты! Нормальных нет, а чего взять с ненормальных. Только и могут… (опрокидывает еще стопку) тормозить… прогресс, дуры эдакие

Из-за соседнего столика подходит девушка

D: - Приветик мальчики! Я услышала вы в компьютерах разбираетесь. Ой, я тут, такой ролик обалденный видела… Там этот, ну как его, свен, ой, свэй показывали. Такой милашка и так быстро работает. А вы бы не могли ко мне прийти, я бы хотела чтобы вы мне вдвоем поставили… ну как его поставить показали, пожалуйста (облизывает губы)

S,E (в один голос): - Уйди женщина, не видишь мужчины серьезную тему обсуждают!!! Пристаешь со своими глупостями…

S: - Видал, дураков нашла! Ага, щас. Сама свои двадцать два года непонятно чем занималась… учиться нужно было!

E: - Ага, дура набитая! Такой разговор испортила. Ведь какие могут быть последствия! А если не услышат и не поймут??!! А если вдруг поймут и не так… нет в мире нормальных…

lnx4
()
Ответ на: комментарий от Spoofing

К психологу или психотерапевту пробовал ходить? Я просто не помню.

Вообще, если туго с офлайн знакомствами, могу посоветовать онлайн. Причём желательно, чтобы у тебя был один маленький недостаток. Например, чтобы вы жили в разных городах и ты по какой-то причине не мог приехать к ней. Ну и желательно одно небольшое достоинство привлекающее внимание.

Я так познакомился на дваче в soc с одной 20-летней девушкой. Всё хорошо, только мне что-то тревожно ездить в Россию (особенно теперь, но и тогда было). В итоге мы встречаемся на расстоянии уже год, несколько раз ездили вместе в другие страны (куда ей не нужна виза, до французской турвизы пока не созрела). Если тебя волнует постельная тема, то с ней всё хорошо.

Жениться и переезжать во Францию не горит желанием (но, мне кажется, такая возможность имеется в будущем), билеты сама себе покупает (при этом она небогатая), дарит подарки (например, подарила на мой день рождения смарт-часы от Samsung). Это на случай, если заподозришь корыстные мотивы (типа девушка хочет за счёт меня эмигрировать - увы, не очень хочет). Конечно же, я отвечаю ей взаимностью. Пытаюсь заботиться и поддерживать в её начинаниях и тоже дарить подарки (например, отправлял на её день рождения посылкой французские духи).

В таком формате знакомства главное уделять внимание собеседнику и давать ему возможность уделить внимание тебе.

KivApple ★★★★★
()
Последнее исправление: KivApple (всего исправлений: 2)
Ответ на: комментарий от i-rinat

Потому что Durability из ACID того требует.

Для чтения, когда туда не писали?

Вроде бы отключается. Не пробовал.

Так у него новый запрос - новая жизнь.

crutch_master ★★★★★
()
Последнее исправление: crutch_master (всего исправлений: 1)
Ответ на: комментарий от i-rinat

Но всё равно думаю, что SQLite3 справится, скорее всего.

Там кратно больше операций чтения, чем записей, а чтобы оно быстро читалось надо кэшировать, а на похапе это делать тупо забей. Из-за этого он и работал всегда в связке с mysql, т.к. там какой-никакой кэш в памяти, и то часто тупо рендерели хтмл и отдавали его статикой. Но технически он всё выдержит на 146%, т.к. кроме него и пары тролей туда заходить всё равно никто не будет.

crutch_master ★★★★★
()
Последнее исправление: crutch_master (всего исправлений: 2)
Ответ на: комментарий от dk__

Да ладна. ЛОР уже больше 20 лет работает — с чего бы ему помереть в одночасье?

hateWin ★☆
()
Ответ на: комментарий от crutch_master

Для чтения, когда туда не писали?

Как воспроизвести? Я пробовал на простых запросах на небольшой таблице. Единственный write(), который отловил strace, был связан с выводом результата в стандартный вывод.

Так у него новый запрос - новая жизнь.

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

И не обязательно базу открывать-закрывать на каждый запрос. Можно на том же php написать долгоживущий процесс, который обрабатывает запросы синхронно, принимая соединения по tcp локально. Будет один php процесс, который заведует делами с базой, и кучка процессов php, запускаемых на каждый запрос от пользователей.

i-rinat ★★★★★
()
Ответ на: комментарий от crutch_master

а чтобы оно быстро читалось надо кэшировать, а на похапе это делать тупо забей.

У операционной системы обычно есть копия недавно прочитанных данных в памяти.

i-rinat ★★★★★
()
Ответ на: комментарий от i-rinat

Можно на том же php написать долгоживущий процесс, который обрабатывает запросы синхронно, принимая соединения по tcp локально.

Можно, но он так делать не будет. Можно вообще писать не на пхп, а любом другом на нормальном языке.

crutch_master ★★★★★
()

Если будешь и дальше писать на этом говне мамонта, девушки у тебя ещё долго не будет.

Запишись и ходи в спортзал, найди какие-нибудь танцы. Там будет много девчонок, будет проще кого-то найти. И сразу общие интересы и т.д.

th3m3 ★★★★★
()
Последнее исправление: th3m3 (всего исправлений: 1)
Закрыто добавление комментариев для недавно зарегистрированных пользователей (со score < 50)