为什么SQLite在特定机器上如此慢(~2 q/s)?

Udo*_*o G 14 php sqlite performance

在我的一台服务器上(i7 Ivy Core,32 GB RAM,Debian 6 @ 64bit,PHP 5.4.10)我遇到了非常慢的SQLite插入.以下测试程序仅报告2.2次插入/秒(插入30行时为14秒).

unlink("test.db");

$db = new PDO('sqlite:test.db');

$db->exec("CREATE TABLE test (dummy INT)");

$count = 30;

$t = microtime(true);
for ($i=0; $i<$count; $i++) {
  $db->exec("INSERT INTO test VALUES ($i)")
   or die("SQLite error: ".$db->errorInfo()[2]."\n");
}
$elapsed = microtime(true)-$t;
echo sprintf("%d inserts in %.3f secs (%.1f q/s)\n", 
  $count, $elapsed, $count/$elapsed);
Run Code Online (Sandbox Code Playgroud)

输出:

$ time php test.php
30 inserts in 13.911 secs (2.2 q/s)

real    0m14.634s
user    0m0.004s
sys     0m0.016s
Run Code Online (Sandbox Code Playgroud)

我知道我可以通过包装加快这一BEGIN/ END周围的INSERT语句(这给了我20万Q/S),但即使没有交易,这应该是快.在其他(较旧的)机器上(相同的PHP版本),我在没有显式事务的情况下达到300多个查询/秒.

可能是什么原因造成的?我是否需要调整Sqlite或O/S?

LSe*_*rni 35

我已经在Linux 64位机器上进行了类似的测试,以strace -C -tt了解SQLite3在哪里花时间.

% time     seconds  usecs/call     calls    errors syscall
------ ----------- ----------- --------- --------- ----------------
 99.03    0.004000          32       124           fsync
  0.64    0.000026           0       222           mprotect
  0.32    0.000013           0       216           munmap
Run Code Online (Sandbox Code Playgroud)

明显的延迟在于fsync函数,即:

  • 配置
  • 依赖于一般的磁盘I/O(退房iotop,iostat)
  • 在很大程度上取决于IOSS(因此,文件系统和磁盘分配 - 你可能在ext3上获得一个值,在xfs上获得一个值,在btrfs上获得第三个值)
  • 当然,间接地取决于底层硬件及其怪癖或调整.

通过关闭同步,我的SQLite3性能提高了大约三千倍:

$db = new PDO('sqlite:test.db');

$db->exec('pragma synchronous = off;');
Run Code Online (Sandbox Code Playgroud)

我在两台非常相似的机器上也有两个不同的值(一个有ext4,另一个有XFS,但我不肯定这是主要原因 - 它们的负载配置文件也不同).

顺便说一下,使用准备好的语句可以将执行速度提高一倍(从45k到110k INSERT,从3000个批量生成,因为在那个速度下30个INSERT必然会产生虚假时间),并从最低速度提高最低速度大约150.

因此,这(使用准备好的语句)可能是一个很好的解决方案,可以在不触及文件同步的情况下改进重复操作,即,同时仍然可以确定数据风险级别保持不变.之后我会尝试事务或fsync(甚至可能是内存日志),具体取决于数据中断的风险和价值.

在从头开始设计系统时,肯定建议对不同FS进行一些测试.

测试不同的文件系统(同一台机器)

ext4 (acl,user_xattr,data=order)         5.5 queries/s
using transactions                       170 queries/s
disabling fsync                        16000 queries/s
using transactions and disabling fsync 47200 queries/s
Run Code Online (Sandbox Code Playgroud)

临时文件系统上,fsync价格便宜,因此将其关闭几乎没有任何好处.大部分时间都用于保护,因此交易是关键.

tmpfs                                  13700 queries/s
disabling fsync                        15350 queries/s
enabling transactions                  47900 queries/s
using transactions and disabling fsync 48200 queries/s
Run Code Online (Sandbox Code Playgroud)

当然,必须考虑适当的数据组织和索引,对于大型数据集,可能会变得更加重要.


更新:为了挤出更多性能,还可以将SQLite日志放入内存中pragma journal_mode=MEMORY;

  • 很难说.`fsync`只能保证IOSS的完整性,**不能保证数据的完整性.为此,您需要事务和完全提交(即,磁盘物理信息必须*始终*处于一致,可恢复的状态).它可能不是:如果你有磁盘缓存和没有屏障的FS,*那么fsync无法在断电时保存你*.因此,完全删除`fsync`并不会显着增加现有风险,这非常接近功率损耗.什么*是那个风险?我不能说.在考虑FS或fsync之前,我认为*UPS和优质硬件*虽然:-) (2认同)