Почему такая разница в производительности SQLite в PHP и Delphi?
Есть база SQLite размером в пару Гигов. Компьютер имеет 32 Гига оперативки, большая часть свободна, т.е. рано или поздно база оказывается в файловом кеше. База используется в качестве словаря, никаких операций по изменению, удалению или вставки нет, одни селекты. Делаю выборку с помощью PHP. На каждый запрос получаю в ответ запись с двумя полями. Производительность порядка 15 000 запросов в секунду. Если делать это первый раз, то в разы меньше, порядка 5 000 запросов в секунду, но потом, видимо, база попадает в файловый кеш и операции идут с более высокой скоростью, которая более менее стабильна. То же самое пытаюсь сделать на Delphi, точнее на C++ Builder'е. Скорость порядка 200 селектов в секунду. Разница почти на 2 порядка! Хотя, казалось бы, скомпиленное приложение должно выполняться чуть быстрее, но результат прямо противоположный. В чём прикол?
1. Есть подозрение, что вы по какой-то причине в C++-версии не предкомпилируете запросы. Запрос компилируется каждый раз, когда вы его исполняете. Хотя это зависит от обёртки — простыми Си’шными функциями работать с SQLite ой как тяжко, все используют обёртки.
2. Если компилируете SQLite классическим компилятором Embarcadero — он в несколько раз медленнее других. Хотя разницу в несколько порядков давать не может. Кстати, столь большие Си-файлы быстро заглючивают Embarcadero, и лучше SQLite отправить в статическую или динамическую библиотеку.
1. Точно. Разобрался, исправил этот момент. Теперь код выглядит так:
// Где то в самом начале
SQLQuery1->CommandText="select props from forms where id=:WORD";
SQLQuery1->Prepared=true;
// Внутри рабочего цикла
SQLQuery1->ParamByName("WORD")->AsString=w;
SQLQuery1->Open();
if (!SQLQuery1->IsEmpty()) {
SQLQuery1->First();
while (!SQLQuery1->Eof) {
ts->Add(SQLQuery1->FieldByName("props")->AsString);
k++;
SQLQuery1->Next();
}
}
SQLQuery1->Close();
Скорость возросла раза в 3. Но разница с PHP всё ещё огромна!
Вот PHP код:
<?php
$db=new SQLite3("words.db");
// Открываем файл
$fd=fopen("test-words.txt","r");
$res=fopen("test-words-sqlite.res","w");
$count=0; $notfound=0;
// Читаем строку
while (($s=fgets($fd))!==false) {
$s=str_replace("\r","",$s);
$s=str_replace("\n","",$s);
$result=$db->query("select initform_id,props from forms where word='".$s."';");
$count++;
if ($row=$result->fetchArray()) {
fwrite($res,$s."\t".$row["initform_id"]."\t".$row["props"]."\n");
}
else {
fwrite($res,$s."\tNot found!\n");
$notfound++;
}
}
fclose($fd);
fclose($res);
echo "All: ".$count."\tNot found: ".$notfound."\n";
?>
sqlite3.dll - 3.8.8.3 - 25.02.2015 (C++ Builder)
php_sqlite3.dll - 5.5.14.0 - 25.06.2014 (PHP)
Т.е. версия SQLite для PHP более древняя, а производительность выше. Я правда грешу на dbExpress в C++ Builder. Может там что надо подправить?
Александр Алексеев: 5.5.14.0 это версия PHP, посмотрите phpinfo(), какая там версия SQLite? Хотя в любом случае там будет что-то из 3.7+, что не объясняет такую катастрофическую разницу в производительности.
Возможно, PHP версия использует промежуточный буффер, а C++ версия у вас на каждый запрос делает физический поиск по диску, можно понаблюдать.
По C++ части ничего не подскажу, к сожалению.