Хранить кэш в БД или в файлах (часть 2) ?

программирование php базы данных быстродействие производительность

Начало темы тут
http://otvety.google.ru/otvety/thread?fid=1087e401a3de8214000494ed0f616379&source=email&tid=1087e401a3de8214

Напомню - вопрос был в том, где оптимальнее по скорости хранить кэш шаблонов - в файлах или в БД.
На днях я провёл тестирование, а по сути простое считывание содержимого всего кэша из файлов и из БД, после чего сравнил затраченное время. Так вот. Общее количество файлов составило 173 штуки, суммарная длина их примерно 450 кБ.

Время, потраченное на считывание шаблонов из файлов составило ~ 0.08 секунд;
Время, потраченное на считывание шаблонов из БД составило ~ 0.001 секунд.

Таким образом, в моём опыте время доступа и считывания шаблонов из БД в 80 (!) раз меньше, чем время доступа и считывания из файлов.

Кто-то может это объяснить ?


Примечание:
К_АНТОН:
Я понимаю Вашу логику и в принципе с ней согласен, но факты говорят об обратном.
И одно из объяснений, как мне кажется, заключается в том, что если из файлов приходится считывать всякий раз заново, то таблица БД (однажды считанная из файла) хранится целиком в памяти и, таким образом, доступ к ней намного быстрее, чем к файлу.
И похоже на то, что кэш MySQL не стирается из ОЗУ между запросами PHP.

Примечание:
Хорошо, вечером я кину сюда свой тестовый код, а также повторю опыт на внешнем хостинге.

Примечание:
Добрый вечер. Сперва приведу тестовый код, затем напишу результаты тестирования на реальном хостинге.

class upgTest extends uCustomObject {

function onAfterChild() {

$t1 = microtime(true);

$i = 0;
$this->getDv($_SERVER['DOCUMENT_ROOT'].'/testt/', $i); // В этой папке свалены все файлы шаблонов проекта

$t2 = microtime(true);

echo 'FILESYSTEM = '.($t2 - $t1).'<br>'; // Выводим сколько времени потратили на перебор всех файлов

$q = 'select id from `testtab`';
$res = $this->sql($q);

foreach ($res as $d) {
$q = 'select txt from `testtab` where id = "'.addslashes($d['id']).'"';
$rr = $this->sql($q);

$this->testWork($rr[0]['txt']);
}

$t3 = microtime(true);

echo 'MYSQL = '.($t3 - $t2).'<br>';
}

function getDv($dirpath, &$i) {
$dir = new RecursiveDirectoryIterator($dirpath);
while ($dir->valid()) {
$file = $dir->getFilename();

if (($file != '.') && ($file != '..')) {

if (is_dir($dirpath.'/'.$file)) {
$this->getDv($dirpath.'/'.$file, $i);
} else {
$pfile = $dirpath.'/'.$file;

// Load file and process
$str = file_get_contents($pfile);
$this->testWork($str);
}
}
$dir->next();
}
}

function testWork($str) {
echo strlen($str).'<br>';
}
}

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

Те же самые файлы записаны в таблице testtab: id, path, txt; в txt хранится полное содержимое каждого файла. Сперва мы читаем список id-шников, затем перебираем в цикле все id-шники, вытаскиваем содержимое и точно так же выводим длину содержимого.

Хочу сказать, что при тестировании на локалхосте я накосячил в прошлый раз, поэтому скорость MySQL была "слегка" завышена. Реальные данные для локалхоста таковы

LOCALHOST test
----------------------
FS MySQL
0,080 0,045
0,079 0,042
0,080 0,037
0,081 0,046

то есть всегда имеем скорость с БД почти в 2 раза выше, чем с FS.

Теперь аналогичные данные с реального виртуального хостинга.

VIRTUAL HOSTING
-----------------------------
FS MySQL
0,028 0,055
0,029 0,012
0,027 0,012
0,057 0,016
0,040 0,007
0,028 0,015

Как мы видим, зависимость приблизительно сохраняется - в подавляющем большинстве случаев MySQL в два раза быстрее FS.

Отсюда я делаю вывод:
чтение файлов шаблонов из MySQL в испытуемых системах как правило в 2 раза быстрее, чем чтение из файловой системы. Однако, в других случаях (например, когда БД находится на другом физическом компе) возможна обратная ситуация.

Кажется, для себя я обрисовал следующий план действий:
1. Делаю кэширование шаблонов в БД.
2. Делаю флаг, переключив который в конфиге можно сделать кэширование в файловой системе.

Какие будут комментарии, уважаемые программеры ?

Примечание:
2 Yorie:

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

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

http://otvety.google.ru/otvety/thread?tid=457115638a48ba60&table=%2Fotvety%2Fuser%3Fsort%3Dwsmopts%26order%3Dwsnod%26start%3D0%26userid%3D06573115922173826867%26tab%3Dwtmtoa

как мы выяснили в итоге, лучше всего хранить не код, который deeval'ить потом, а сериализованный массив. Именно так я и буду делать.

Примечание:
2 Yorie:
Возможно, результаты тестов в вашем случае обусловлены тем, что вы читаете из файла не всё содержимое, а только первую строку (используя fgets() ). Попробуйте считывать файл в строку функцией file_get_contents().

P.S. Отчасти этим может объясняться и такая разница по памяти.

Примечание:
2 NetRain:
Загрузить, конечно, можно. Вот только тонкость в том, что загрузка может пагубно повлиять и на файловую систему и на MySQL-сервер. И предсказать какие реальные условия будут, наверное, невозможно....
Насчёт memcache - идея отличная, я её уже думал, просто на виртуальных хостингах оно обычно отсутствует.
Ответы:
БД хороша в случае поиска и сортировки. (собственно она именно для этого) А вот хранить в ней файлы не есть гуд.
Сами подумайте что БД в итоге теже файлы на диске только индексированные.
Получается вам его надо найти и потом извлечь.
Считывание из бд может быть быстрее чем работа с файловой системой. Не стоит забывать про то что mysql использует кеширование (http://habrahabr.ru/blogs/mysql/41166/). Т.е. делая запрос к базе данных не факт что будут задействована файловая система.
Если проанализировать то на что mysql тратит время при выполнение запроса то несложно увидеть что много ресурсов тратятся на работу с временными таблицами. Если создать диск в оперативке и настроить mysql так что бы он хранил временные таблицы на этом диске, то скорость работы с базой данных значительно увеличивается.
Наши японские друзья пошли еще дальше и написали плагин для mysql который позволяет работать с базой данных по протоколу NoSql - напоминающему протокол взаимодействия с memcache, о результатах можно почитать тут - http://l-o-n-g.livejournal.com/153756.html .
Да, MySQL хранит кеш таблиц в оперативной памяти, как и кеширует результаты отдельных запросов. Но в отличие от файловой системы скорость получения данных из БД зависит от очень многих составляющих. Чтобы рассуждать далее о причинах такой разницы во времени выполнения и проводить какие-либо тесты/сравнения, хотелось бы узнать способ получения данных (по одному шаблону за запрос, количество получаемых шаблонов за время работы скрипта, проводилось ли нагрузочное тестирование или результаты получены просто на локалхосте при единственном клиенте, размер оперативной памяти и максимально доступный ее объем для БД, наличие одновременных выборок других данных и количество/сложность/объем данных этих выборок и т. д.).
По сути, если вы получаете 450 килобайт текста, хранящегося в 173 файлах, вполне возможно, что СУБД будет выигрывать, поскольку она хранит все 173 записи в единственном файле, а при наличии достаточного количества памяти и небольшого количества запросов других данных она просто может закешировать либо таблицу целиком либо несколько результатов запросов, которые и содержат получаемые вами данные. При отсутствии потерь времени на передачу данных по сети (если СУБД стоит на той же системе, что и интерпретатор) время выполнения сводится по большому счету к времени обращения к оперативной памяти и нескольким системным вызовам + обработка loopback-соединения сетевым драйвером.
В случае, если шаблоны получаются из БД несколькими запросами, а нагрузка и/или количество других запросов и объем их результирующих данных значительно превышает количество запросов на получение шаблонов - скорее всего где-то ошибка или же проблема в файловой системе данной конкретной машины (излишне медленный драйвер ФС или большое количество одновременных операций чтения-записи).
Но, повторяюсь, для более точных и конкретных суждений нужно знать, каким образом получены данные результаты и в каких условиях.
Хм.. Я провел тесты и почему-то получил совсем противоположные показатели, нежели у Вас:
FS test done.
Time estimated: 0.0037
Memory used: 6816 bytes
Чтобы забить кеш другими данными просто походить по другим страничкам и подождать может быть недостаточно. Сделайте SQL_NO_CACHE в запросах - это гарантирует отключение кеша при выполнении запроса и вы увидите худшие показатели из возможных в тех условиях, в которых работал в сервер в момент тестирования. Остается вопрос как поведет себя этот механизм под нагрузкой. Если по сути скорость БД обусловлена ее работой на той же системе, что и интерпретатор, плюс кешем запросов, то под нагрузкой ситуация может кардинально поменяться (как в случае просто большого количества запросов пользователей, так и в случае дальнейшего переноса СУБД на отдельный сервер при расширении проекта). Может быть, стоит присмотреться к memcache? То же кеширование в памяти, но значительно меньше оверхэд на функции специфические для СУБД - почти чистая работа с данными.
Да, Вы правы, fgets() - плохо, упустил я момент. Заменил на file_get_contents() и вот результат:
FS test done.
Time estimated: 0.0076
Memory used: 224312 bytes
Предлагаю создать рамдиск и его тоже погонять в тестах.
Во-первых есть такая штука как кэш запросов. Это обясняет скорость. Во-вторых, БД находился в одном файле а много файлов - это много файлов, получаем экономию на файловых операциях. Ну и в третьих, даже доступ к кэшу в БД можно ускорить на порядки используя HandlerSocket.


14 лет назад

RPI.su - самая большая русскоязычная база вопросов и ответов. Наш проект был реализован как продолжение популярного сервиса otvety.google.ru, который был закрыт и удален 30 апреля 2015 года. Мы решили воскресить полезный сервис Ответы Гугл, чтобы любой человек смог публично узнать ответ на свой вопрос у интернет сообщества.

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

Чтобы связаться с нами по любому вопросу О САЙТЕ (реклама, сотрудничество, отзыв о сервисе), пишите на почту [email protected]. Только все общие вопросы размещайте на сайте, на них ответ по почте не предоставляется.