16

サーバーの 1 つ (i7 Ivy Core、32 GB RAM、Debian 6 @ 64 ビット、PHP 5.4.10) で、SQLite の挿入が非常に遅くなります。次のテスト プログラムでは、1 秒あたりわずか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);

出力:

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

real    0m14.634s
user    0m0.004s
sys     0m0.016s

BEGIN挿入ステートメントをラップ/アラウンドすることでこれを加速できることはわかっていますが(これにより、200000 q / sが得られます)、トランザクションがなくても、これははるかに高速ENDになるはずです。他の (古い) マシン (同じ PHP バージョン) では、明示的なトランザクションなしで毎秒 300 以上のクエリに達します。

これの原因は何ですか?Sqlite または O/S を調整する必要がありますか?

4

1 に答える 1

38

strace -C -ttSQLite3 がどこで時間を取っているかを把握するために、Linux 64 ビット マシンで同様のテストを行いました。

% 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

明らかな遅延は次のfsync関数にあります。

  • 設定可能
  • 一般的なディスク I/O に依存します ( を確認してくださいiotop) iostat
  • IOSS に大きく依存します (したがって、ファイル システムとディスクの割り当て - ext3 で 1 つの値、xfs で別の値、btrfs で 3 番目の値が得られる場合があります)。
  • もちろん、基礎となるハードウェアとその癖やチューニングに間接的に依存します。

同期をオフにすると、SQLite3 のパフォーマンスが約 3,000 倍向上します。

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

$db->exec('pragma synchronous = off;');

私も非常によく似た2台のマシンで2つの異なる値を持っています(1台にはext4があり、もう1台にはXFSがありますが、これが主な理由であるとは確信していません-それらの負荷プロファイルも異なります)。

ちなみに、プリペアド ステートメントを使用すると、最速レベルで実行速度が約 2 倍になり (45k から 110k の INSERT、3000 のバッチで、その速度では 30 個の INSERT が誤ったタイミングを与えることにバインドされているため)、最低速度は約 6 から上昇します。約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

一時ファイル システムでは は安価なので、fsyncオフにしてもほとんどメリットがありません。ほとんどの時間はガードに費やされるため、トランザクションが重要です。

tmpfs                                  13700 queries/s
disabling fsync                        15350 queries/s
enabling transactions                  47900 queries/s
using transactions and disabling fsync 48200 queries/s

もちろん、適切なデータ編成とインデックス作成を考慮する必要があり、大規模なデータ セットの場合は、より重要になる可能性があります。


UPDATE : パフォーマンスを向上させるために、SQLite ジャーナルをメモリに入れることもできます。pragma journal_mode=MEMORY;

また、SQLite データベースで atime をわざわざ更新しないように ext3/4 に指示することもできます (ただし、これは実装に大きく依存します)。noatimeデータベースが存在するファイルシステムへの追加を試すことができます。それが機能する場合は、それを配置できます(より極端な代わりに/etc/fstab使用することもできます:relatimenoatime

sudo mount /var -o remount,noatime
于 2013-03-14T15:47:22.233 に答える