
Предыстория
Ожидая на одном из поддерживаемых сайтов окончания импортирования очередного каталога от поставщиков, задумался, как можно было бы ускорить процесс.
А то ситуация и вправду какая-то нездоровая, да, публичный хостинг с PHP и MySQL, ну так и задачи ведь не космического масштаба, и ожидать по несколько минут, пока сайт переваривает не такой уж и большой поток входной информации, как-то напрягает.
Сама задачка не такая и сложная, идет обработка импорта по API поставщика и далее INSERT-ами и UPDATE-ами все это закачивается уже в БД сайта.
Но этих INSERT-ов и UPDATE-ов довольно много.
И тут я вспомнил, что уже много лет назад копался с SQLite, но в рабочие проекты она не пошла, потому что все говорили: "Фу, производительность никакая, при параллельных запросах все упадет, и тд и тп.", да и с синтаксисом запросов там проблемы были, на тот же MySQL просто перейти было нельзя, надо было бы много чего переписывать, а с учетом того, что все проекты верят, что в будущем они станут как минимум Амазонами с Фейсбуками, то вначале сразу отрубать такую возможность в будущем не хотелось.
Но повзрослев и помудрев(надеюсь), я сейчас выбираю под текущие задачи те инструменты, которые удобнее сейчас, а не в прекрасном возможном будущем.
И вспомнив об этом, я решил затестить, как справится SQLite с волнующей меня проблемой.
И что же, забегая вперед, скажу, что я оказался поражен результатом.
Итак
Я быстро набросал код, который нагружает БД аналогично вышеописанной задачке, соответственно для MySQL и SQLite БД.
Получилось так:
// MySQL
$db = new PDO('mysql:dbname=vashwind;host=localhost;charset=UTF8', 'vashwind', 'очень сложный пароль');
$db->exec("
SET AUTOCOMMIT = 0;
DROP TABLE IF EXISTS `foo`;
CREATE TABLE `foo` (
`id` int(11) PRIMARY KEY AUTO_INCREMENT,
`name` varchar(255) DEFAULT NULL
) ENGINE=InnoDB;
");
$time_start = microtime(true);
$db->beginTransaction();
for($i=1;$i<500000;$i++){
$db->exec("insert into foo (name) values ('".md5(rand())."') ");
}
for($i=1;$i<500000;$i++){
$db->exec("update foo set name = '".md5(rand())."' where id=$i");
}
$db->commit();
$time_end = microtime(true);
$time = $time_end - $time_start;
echo "Время выполнения mysql: $time секунд <br>";
// sqlite
$db = new PDO('sqlite:db.sqlite');
$db->exec("
DROP TABLE IF EXISTS 'foo';
CREATE TABLE foo(id INTEGER PRIMARY KEY, name TEXT, text TEXT);
");
$time_start = microtime(true);
$db->beginTransaction();
for($i=1;$i<500000;$i++){
$db->exec("insert into foo (name) values ('".md5(rand())."') ");
}
for($i=1;$i<500000;$i++){
$db->exec("update foo set name = '".md5(rand())."' where id=$i");
}
$db->commit();
$time_end = microtime(true);
$time = $time_end - $time_start;
echo "Время выполнения sqlite: $time секунд";
И что же я получаю в итоге?
А вот что:
Время выполнения mysql: 31.970330953598 секунд
Время выполнения sqlite: 4.4192090034485 секунд
То бишь аналогичную задачку SQLite решает в 8 раз быстрее, чем MySQL.
Не поверив своим глазам, подумав, что на конкретном хостинге возможно MySQL плохо настроили, перепроверил результаты еще на двух альтернативных хостингах.
Везде SQLite отработала быстрее от 8 до 15 раз.
Однако..
На текущем проекте с долгим импортом каталогов я SQLite внедрять уже не буду, слишком там много всего уже написано под MySQL, но на будущих проектах присмотрюсь точно.
И да, я полностью отдаю себе отчет, что для высоконагруженных проектов с огромным количеством одновременных пользователей SQLite подходит слабо, но для задач, подобных вышеописанной, она явно достойна рассмотрения.