sql >> データベース >  >> RDS >> SQLite

SQLiteのパフォーマンスチューニング

    SQLiteは、アプリケーションに埋め込む人気のあるリレーショナルデータベースです。データベース内のデータ量が増えるにつれて、SQLiteパフォーマンスチューニングを適用する必要があります。この記事では、インデックスとその落とし穴、クエリプランナーの使用、ログ先行書き込み(WAL)ジャーナルモード、およびキャッシュサイズの増加について説明します。また、自動テストを使用して、微調整の影響を測定することの重要性についても詳しく説明します。

    はじめに

    SQLiteは人気のあるリレーショナルデータベース(DB)システムです 。 MySQLなどのより大きなクライアントサーバーベースの兄弟とは異なり、SQLiteはライブラリとしてアプリケーションに埋め込むことができます 。 SQLiteには非常によく似た機能セットがあり、パフォーマンスチューニングに関するいくつかのヒントとコツを知っていれば、何百万もの行を処理することもできます。次のセクションで示すように、インデックスを作成するだけでなく、SQLiteのパフォーマンスチューニングについて知っておくべきことがたくさんあります。

    インデックスを作成しますが、注意が必要です

    インデックスの基本的な考え方は、読み取りを高速化することです。 特定のデータの 、つまり、SELECT WHEREを含むステートメント 句。 インデックスは並べ替えも加速します データORDER BY )、またはJOIN テーブルを作成します。残念ながら、インデックスは追加のディスクスペースを消費し、データ操作を遅くするため、両刃の剣です(INSERTUPDATEDELETE

    一般的なアドバイスは、できるだけ少ないインデックスを作成することですが、必要なだけ多くのインデックスを作成することです 。また、インデックスは大きいに対してのみ意味があります 数千または数百万行のデータベース。

    クエリプランナーを使用してクエリを分析する

    SQLiteが内部でインデックスを使用する方法は文書化されていますが、理解するのは簡単ではありません。この記事でさらに詳しく説明するように、クエリの前にEXPLAIN QUERY PLANを付けてクエリを分析することをお勧めします。 。すべての出力行を見てください。そのうちの3つの基本的なバリエーションがあります。

    • SEARCH table ... 行は良い兆候です– SQLiteはあなたのインデックスの1つを使用します!
    • SCAN table ... USING INDEX 悪い兆候です
    • SCAN table ... さらに悪いです!

    SCAN table [using index]は避けてください EXPLAIN QUERY PLANの出力のエントリ 大規模なデータベースではパフォーマンスの問題が発生するため、可能な限り。 EXPLAIN QUERY PLANを使用します SCAN tableがなくなるまで、インデックスを繰り返し追加または変更します エントリが表示されます。

    IS NOTを含むクエリを最適化する

    IS NOT ...を確認しています 高い SQLiteはスキャンする必要があるためです テーブルのすべての行、影響を受ける列にインデックスがある場合でも 。インデックスは、特定の値、つまり<を含む比較を探す場合にのみ役立ちます。 (小さい)、> (より大きい)、または = (等しい)が、!=(等しくない)には適用されません。

    ちょっとしたコツは、WHERE column != valueを置き換えることができるということです。 WHERE column > value OR column < value 。これにより、列のインデックスが使用され、値がvalueと等しくないすべての行に効果的に影響します。 。同様に、WHERE stringColumn != '' WHERE stringColumn > ''に置き換えることができます 、文字列は並べ替え可能であるため。ただし、このトリックを適用するときは、SQLiteがNULLをどのように処理するかを知っていることを確認してください 比較。たとえば、SQLiteはNULL > ''を評価します FALSEとして 。

    このような比較トリックを使用する場合、クエリにWHEREが含まれている場合の別の注意点があります。 およびORDER BY 、それぞれに異なる列があります。これにより、クエリが再び非効率になります。可能であれば、同じを使用してください WHEREの列 およびORDER BY 、またはカバーインデックスを作成します これには、WHEREの両方が含まれます およびORDER BY 列。

    先行書き込みログを使用して、書き込み速度を向上させます

    先行書き込み(WAL) ジャーナルモードは、書き込み/更新のパフォーマンスを大幅に向上させます 、デフォルトのロールバックと比較 ジャーナルモード。ただし、ここに記載されているように、いくつかの注意事項があります 。たとえば、WALモードは特定のオペレーティングシステムでは使用できません。また、ハードウェア障害が発生した場合のデータ整合性の保証が低下します 。最初の数ページを読んで、何をしているかを理解してください。

    コマンドPRAGMA synchronous = NORMALが見つかりました 3〜4倍のスピードアップを提供します。 journal_modeの設定 WALへ その後、パフォーマンスが再び大幅に向上します(オペレーティングシステムによって異なりますが、約10倍以上)。

    すでに述べた警告とは別に、次の点にも注意する必要があります。

    • WALジャーナルモードを使用すると、ファイルシステムのデータベースファイルの横に2つの追加ファイルがあります。これらのファイルは、データベースと同じ名前ですが、接尾辞が「-shm」と「-wal」です。通常は気にする必要はありませんが、アプリケーションの実行中にデータベースを別のマシンに送信する場合は、これら2つのファイルを含めることを忘れないでください。 SQLiteは、開いているすべてのデータベース接続を通常閉じるたびに、これら2つのファイルをメインファイルに圧縮します。
    • クエリによってWALログファイルの内容がメインデータベースファイルにマージされるたびに、挿入または更新のパフォーマンスが低下することがあります。これはチェックポイントと呼ばれます 、こちらをご覧ください。
    • PRAGMAが見つかりました s journal_modeを変更する およびsynchronous データベースに永続的に保存されていないようです。したがって、私は常に 初めてテーブルを作成するときに実行するのではなく、新しいデータベース接続を開くたびに再実行します。
    すべてを測定する

    パフォーマンスの微調整を追加するときは、必ず影響を測定してください。 自動(単体)テストは、このための優れたアプローチです。 ドキュメント化に役立ちます あなたのチームのためのあなたの発見、そして彼らは時間の経過とともに逸脱した行動を明らかにするでしょう 、例:新しいSQLiteバージョンに更新するとき。測定できるものの例:

    • WALを使用するとどのような効果がありますか ロールバックでのジャーナルモード モード?他の(おそらく)パフォーマンスを向上させるPRAGMAの効果は何ですか s?
    • インデックスを追加/変更/削除したら、SELECTをどれだけ速く実行しますか ステートメントはなりますか? INSERT/DELETE/UPDATEの処理速度はどれくらい遅くなりますか ステートメントはなりますか?
    • インデックスはどのくらいの追加ディスクスペースを消費しますか?

    これらのテストのいずれについても、さまざまなデータベースサイズで繰り返すことを検討してください。例えば。空のデータベースで実行し、すでに数千(または数百万)のエントリが含まれているデータベースでも実行します。また、特に開発環境と本番環境が大幅に異なる場合は、さまざまなデバイスとオペレーティングシステムでテストを実行する必要があります。

    キャッシュサイズを調整する

    SQLiteは一時的な情報をキャッシュに保存します (RAM内)、例: SELECTの結果を作成している間 クエリ、またはまだコミットされていないデータを操作する場合。 デフォルトでは、このサイズはわずか2MBです 。最新のデスクトップマシンは、はるかに多くのことを惜しまない可能性があります。 PRAGMA cache_size = -kibibytesを実行します この値を増やすにはマイナスに注意してください 値の前にサインインしてください!)。詳細については、こちらをご覧ください。繰り返しますが、測定 この設定がパフォーマンスに与える影響!

    REPLACEINTOを使用して行を作成または更新します

    これは、ちょっとしたトリックなので、パフォーマンスの微調整ではないかもしれません。 更新する必要があるとします テーブルtの行 、または作成 まだ存在しない場合は行。 2つのクエリを使用するのではなく(SELECT 続いてINSERT またはUPDATE )、REPLACE INTOを使用します (公式ドキュメント)。

    これを機能させるには、ダミーの列を追加します(例:replacer )テーブルtUNIQUEがあります 制約します。列の宣言は、たとえば... replacer INTEGER UNIQUE ... これはCREATE TABLEの一部です 声明。次に、

    などのクエリを使用します
    REPLACE INTO t (col1, col2, ..., replacer) VALUES (?,?,...,1)Code language: SQL (Structured Query Language) (sql)

    このクエリを初めて実行すると、INSERTが実行されます。 。 2回目に実行すると、UNIQUE replacerの制約 列がトリガーされ、競合解決の動作により古い行が削除され、新しい行が自動的に作成されます。関連するUPSERTコマンドが役立つ場合もあります。

    結論

    データベースの行数が増えると、パフォーマンスの微調整が必​​要になります。インデックスは最も一般的な解決策です。これらは、時間の複雑さの改善とスペースの複雑さの減少を交換し、読み取り速度を改善する一方で、データ変更のパフォーマンスに悪影響を及ぼします。 A私が示したように、不平等を比較するときは、特に注意する必要があります。 SELECTで SQLiteはそのような種類の比較にインデックスを使用できないためです。通常、クエリプランナーを使用することをお勧めします これは、各SQLクエリの内部で何が起こるかを説明しています。何かを微調整するときはいつでも、影響を測定してください!


    1. データベースの最後のN行を順番に取得しますか?

    2. SQL Server Management Studio 2008でスクリプトの生成タスクを自動化するにはどうすればよいですか?

    3. SQL転置フルテーブル

    4. WindowsにMySQL8をインストールする方法