2017-02-03 17 views
5

私の質問はthisから直接届きますが、私はUPDATEにしか興味がありません。SQLiteのUPDATE-per-secondパフォーマンスを改善しますか?

私は非常に頻繁間隔でSQLiteを多用してC/C++で書かれたアプリケーション、主にSELECT/UPDATE(約20クエリごとに0.5〜1秒)を持つ

私のデータベースは、およそ大きくはありません2500瞬間にレコードが、ここではテーブル構造である:私はコードを向上したためtransactionsを使用して刺しを望んでいたしませんでした。この時点まで

CREATE TABLE player (
    id INTEGER PRIMARY KEY AUTOINCREMENT, 
    name VARCHAR(64) UNIQUE, 
    stats VARBINARY, 
    rules VARBINARY 
); 

パフォーマンスよりもむしろ。

そしてIは、(異なる値のループで)以下、単に10 updateクエリを実行することにより、自分のデータベースのパフォーマンスを測定した:

statsが正確に150文字のJSONと nameが5~10である
// 10 times execution of this 
UPDATE player SET stats = ? WHERE (name = ?) 

文字。トランザクションなし

は、結果が許容できない: - :約0.11 - - 0.16秒(0.013それぞれ)約1フル秒(0.096それぞれ)取引に

、時間がx7.5時間をドロップ

データベースの大部分を削除したり、列の順序を変更/削除して変更があったかどうかを確認しようとしましたが、変更しませんでした。データベースに100レコード(テスト済み)が含まれていても上記の数値が得られます。

私はその後、PRAGMAオプションで遊んでみました:

PRAGMA synchronous = NORMAL 
PRAGMA journal_mode = MEMORY 

は私に小さな回を与えた常にではないが、より多くのようなおよそ0.08から0.14秒

PRAGMA synchronous = OFF 
PRAGMA journal_mode = MEMORY 

が最後に私に与えた非常に小さい回約0.002 - 0.003秒私のアプリケーションは毎秒データベースを節約し、データベースの破損の可能性が高いので、使用したくないn OS /電源障害。

クエリのための私のC SQLiteコードは次のとおりです。(省略/無関係な部品を取り扱うコメント/エラー)

// start transaction 
sqlite3_exec(db, "BEGIN TRANSACTION", NULL, NULL, NULL); 

// query 
sqlite3_stmt *statement = NULL; 
int out = sqlite3_prepare_v2(query.c_str(), -1, &statement, NULL); 
// bindings 
for(size_t x = 0, sz = bindings.size(); x < sz; x++) { 
    out = sqlite3_bind_text(statement, x+1, bindings[x].text_value.c_str(), bindings[x].text_value.size(), SQLITE_TRANSIENT); 
    ... 
} 

// execute 
out = sqlite3_step(statement); 

if (out != SQLITE_OK) { 
    // should finalize the query no mind the error 
    if (statement != NULL) { 
     sqlite3_finalize(statement); 
    } 
} 

// end the transaction 
sqlite3_exec(db, "END TRANSACTION", NULL, NULL, NULL); 

ご覧のとおり、それはTABLEかなり典型的ですが、数が少ないと私は無地のシンプルをやっている記録UPDATE正確に10回。 UPDATE回を減らすために何かできることはありますか?私は最新のSQLite 3.16.2を使用しています。

注:上記のタイミングは、単一のEND TRANSACTIONクエリから直接来ています。クエリは単純なトランザクションで行われ、私は です。

UPDATE:

私は有効トランザクションでいくつかのテストを行い、無効と様々なアップデートがカウントされます。

VACUUM; 
PRAGMA synchronous = NORMAL; -- def: FULL 
PRAGMA journal_mode = WAL; -- def: DELETE 
PRAGMA page_size = 4096;  -- def: 1024 

結果は以下のない:

ないトランザクション(10回の更新)

  • 0.30800秒(更新当たり0.0308)
  • 0.30200秒を私には、以下の設定でテストを行います
  • 0.36200秒
  • 0.28600s ECS

ないトランザクション(100回の更新)

  • 2.64400秒(0.02644各更新)
  • 2.61200秒
  • 2.76400秒
  • 2.68700秒

トランザクションなしONS(1,000更新)

  • 28.02800秒(0.028それぞれ更新)
  • 27.73700秒
  • ..

取引に(10回の更新)

  • 0.12800秒(各更新0.0128)
  • 0.08100秒
  • 0.16400秒
  • 0.10400秒取引に

(100回の更新)

  • 0.088秒(0.00088各更新)
  • 0.091秒
  • 0.052秒
  • 0。101秒取引に

(1,000更新)

  • 0.08900秒(0.000089各更新)
  • 0.15000秒
  • 0.11000秒
  • 0.09100秒

私の結論はtransactionstime cost per queryには意味がありません。多分、更新回数は膨大になりますが、その数には興味がありません。文字通り、のと1000の更新の間に時間的なコスト差はありません。しかし、私はこれが私のマシン上のハードウェアの制限であり、あまりできないのだろうかと思っています。それは、私はミリ秒以下の単一のトランザクションを使用して行くことができないと10-1000更新の範囲は、WALを使用しても。

トランザクションがない場合、固定時間コストは約0.025秒です。

+0

あなたはlanguiage C/C++を使用している場合は、正しいタグを使用します。さもなければ、それはC++のように見えますが、**別の**言語ではありません!これはコードレビューサイトではありません。 – Olaf

+0

@Olaf、 'C++ 'の唯一のものは' std :: string'です。残りは 'C 'です。私は特に上記を重視しています。第二に、誰かが私のコードを見直すことを望まない、私は問題を解決するためにSQLiteのより良いアプローチを望む – user6096479

+4

これはC言語ではないので、C言語ではない。あなたは同じセマンティクスを持っているとは限りません! C++が「クラスを持つC」であると言う人は誰もが間違っていて、自明ではないコードを書くのに十分なことは分かっていません。 – Olaf

答えて

3

、データベース動作自体の時間は重要ではありません。あなたが測定しているのは、OS、ファイルシステム、およびハードウェアに依存するトランザクションオーバーヘッド(ディスクへの書き込みを強制するのに必要な時間)です。

制限がある場合(ほとんどの場合、ネットワークが存在しない場合)は、WAL modeを有効にして非同期書き込みを使用できます。データベースにインデックスを追加

+0

'PRAGMA synchronous = NORMAL'と' PRAGMA journal_mode = WAL'を設定して 'WAL'を試みましたが、何の改善も得られませんでした。私はネットワークを全く必要とせず、私はWALの恩恵を受けたいと思います。私は何の利益も得られません(おそらくいくつかの追加オプションが必要ですか?反対側では、最大1秒間に最大20のクエリを '更新 'するだけです。それらの(クエリ)は少なくても、それ以上ではありません。 'synchronous = NORMAL or FULL'を使用すると、OSにハンドルを与えることを選択しない限り、' 10 ms/update query'の障壁を壊すことはできません。 – user6096479

+0

WALが有効かどうかをチェックするには、 'PRAGMA journal_mode;'を実行してください。 –

+0

なぜ私の 'PRAGMA journal_mode = WAL'が私のC呼び出しで全く照会されなかったのか分かりませんので、モードは' DELETE'のままです。 'PHPLiteAdmin'でクエリを使用して正常に実行したとき。しかし、私の時代はやや「0.07〜0.11」にやや減りました。 – user6096479

3

トランザクションのコミットに時間がかかることがあります。あなたの最初の例では、各トランザクションは約0.10で完了しました。これは10レコードを挿入するためのトランザクション時間にかなり近くなっています。 1回のトランザクションで100回または1000回の更新をバッチすると、どのような結果が得られますか?

また、SQLiteでは平均的なハードドライブでは約60トランザクション/秒しか期待していませんが、ディスクパフォ​​ーマンスはここで問題になるでしょうか?データのような少量の

https://sqlite.org/faq.html#q19

+0

ハードディスクの速度と同期モードのためにSQLiteが書き込まれたデータを確認するのを待っていますか?だから、もし私がパフォーマンス上の安全性を選んだのであれば、典型的な7200ディスクの更新クエリで '〜10ミリ秒 'に制限されますか?私のアプリケーションではトランザクションごとに最大15-20のクエリ(その間にいくつかのSELECTを含む)しか処理しないため、100または1000の更新でテストしなかったので、質問のシナリオをエミュレートしています。私は一週間前に私のディスクをデフラグしました。私はもう一度やり直します:) – user6096479

+0

いいえ、時間は依然として10クエリのトランザクションによって '0.10から0.14秒までの範囲です。 – user6096479

+0

私の質問の更新を参照してください – user6096479

0

試してみてください。

CREATE INDEX IDXname ON player (name) 
関連する問題