最近我的任务是做一些速度检查,所以我可以判断是否更快使用php / php-cli或c将一定数量的行插入数据库.
在开始之前,让我告诉你一些细节,以便一切都清楚:
> php部分通过Apache运行,直接在浏览器中请求.
>正在运行的硬盘驱动器测试是SSD驱动器.我猜常规驱动器的速度会慢一些.这台机器本身并不特别,六年左右.
>所有插入都是通过准备好的声明完成的.我们在php和mysqlcppconn(由Oracle提供的mysql c连接器)上使用mysqli.
>所有插入都是通过输入完成的.我知道我们可以叠加它们,但我们正在这里进行测试.
>时间通过PHP中的microtime和c中的标题显示.
>当然,代码本身并不等同.稍后会详细介绍.
>所有文本都是UTF-8.那里有俄语,中文,阿拉伯语,西班牙语,英语和各种疯狂的东西. mysql表位于utf8_4mb中.
> c代码的数字是使用std :: vector和-O2级别用g编译的结果(向量优于map,unordered_maps和std :: arrays).
所以,这是一个过程:
>连接到数据库.
>打开包含N行的文本文件.
>读取文件的一行.
>拆分分隔符上的行.
>使用分割线的某些部分来获取插入值(例如,第0个,第1个和第3个索引).
>将这些部分发送到准备好的声明中以插入它们.
>重复,直到完全读取文件.
两个代码都完全按预期工作.以下是结果数字:
PHP:
> 5000个条目:1.42 – 1.27秒.
> 20000个条目:5.53 – 6.18秒.
> 50000个参赛作品:14.43 – 15.69秒.
C :
> 5000个条目:1.78 – 1.81秒.
> 20000个条目:7.19 – 7.22秒.
> 50000个参赛作品:18.52 – 18.84秒.
php优于c,因为文件中的行增加…首先,我怀疑行拆分功能:php中的拆分是用“爆炸”完成的.算法和c一样天真……容器通过引用传递,其内容在运行中更改.容器只遍历一次.我确保容器“reserve()”所有必要的空间(记住,我最终选择向量)是固定的.容器在main函数上创建,然后通过代码通过引用传递.它永远不会被清空或调整大小:只有它的内容会改变.
template void explode(const std::string& p_string, const char p_delimiter, container& p_result)
{
auto it=p_result.begin();
std::string::const_iterator beg=p_string.begin(), end=p_string.end();
std::string temp;
while(beg < end)
{
if( (*beg)==p_delimiter)
{
*(it)=temp;
++it;
temp="";
}
else
{
temp+=*beg;
}
++beg;
}
*(it)=temp;
}
如前所述,执行的任务是等效的,但生成它的代码不是. C代码具有通常的try-catch块来控制mysql交互.至于其余部分,主循环运行直到达到EOF并且每次迭代检查插入是否失败(在c和php中).
我已经看到c在处理文件及其内容时大大优于php,所以我希望在这里适用.不知怎的,我怀疑分裂算法,但也许只是数据库连接器速度较慢(仍然,当我禁用数据库交互时php仍然处理得更快)或者我的代码是低于…
对于分析,gprof对c代码进行了讨论:
Each sample counts as 0.01 seconds.
% cumulative self self total
time seconds seconds calls ns/call ns/call name
60.00 0.03 0.03 50000 600.00 600.00 void anc_str::explotar_cadena<:vector std::allocator> > >(std::string const&, char, std::vector<:string std::allocator> >&)
40.00 0.05 0.02 insertar(sql::PreparedStatement*, std::string const&, std::vector<:string std::allocator> >&)
0.00 0.05 0.00 1 0.00 0.00 _GLOBAL__sub_I__ZN7anc_str21obtener_linea_archivoERSt14basic_ifstreamIcSt11char_traitsIcEE
其中“explotar_cadena”是“爆炸”而“insertar”是“拆分此行并将准备好的声明设置为”.正如你所看到的那样,60%的时间都花在那里(这并不奇怪…它运行了50000次并且做了这个疯狂的分裂事情). “obtener_linea_archivo”只是“请将下一行转储到字符串中”.
没有mysql交互(只需加载文件,读取行并拆分它们)我得到这些测量结果:
PHP
> 5000个条目:0.019 – 0.036秒.
> 20000个条目:0.09 – 0.10秒.
> 50000个条目:0.14 – 0.17秒.
C
> 5000个条目:0.07 – 0.10秒.
> 20000个条目:0.25 – 0.26秒.
> 50000个条目:0.49 – 0.55秒.
好吧,两次都是好的,现实生活条件几乎不引人注意,我很惊讶……所以这里的问题是:我应该期待这个吗?任何有经验的人都愿意伸出援手吗?
提前致谢.
编辑:这是一个包含输入文件,C代码和PHP代码的精简版本的快速链接[http://www.datafilehost.com/d/d31034d6].请注意,没有sql交互:只有文件打开,字符串拆分和时间测量.请原谅屠宰代码和半西班牙语评论和变量名称,因为这是匆忙完成的.另外,请注意上面的gprof结果:我不是专家,但我认为我们正试图找到一种更好的方法来分割字符串.