記事「MQL5におけるSQLiteの機能:銘柄とマジックナンバー別の取引統計を表示するダッシュボード」についてのディスカッション - ページ 2

 
SQLite: нативная работа с базами данных на SQL в MQL5
SQLite: нативная работа с базами данных на SQL в MQL5
  • 2020.02.18
  • www.mql5.com
Разработка торговых стратегий связана с обработкой больших объемов данных. Теперь прямо в MQL5 вы можете работать с базами данных с помощью SQL-запросов на основе SQLite. Важным преимуществом данного движка является то, что вся база данных содержится в единственном файле, который находится на компьютере пользователя.
 
本質を深く掘り下げずに、早合点してしまいました。申し訳ありません。「学生向けのおもちゃ」という表現は言い過ぎでした。SQLiteはそんな扱いを受けるべきではありません。

さらに深く掘り下げてみました(AIのOpus 5を活用し、テスト環境を構築して、50万件の取引データ、20のシンボル、20のマジックナンバーを用いた合成データを生成し、測定を行いました)。その結果を要約すると以下の通りです。

1) fxsaberの5分という処理時間は、ほぼ間違いなくSQLiteによるものではありません。

自動コミットで1取引ずつINSERTする場合:50万件で約245秒。
同じデータを1つのトランザクション内で一括処理した場合:2.35秒。

その差は104倍です。245秒――まさにあの「5分」そのものです。 1回の挿入ごとに、fsyncを伴う個別のトランザクションが実行されています。これは2行のコード、DatabaseTransactionBegin() / DatabaseTransactionCommit()で解決できます。この数字に比べれば、この議論の他の部分は些細なことです。

2) インデックスに関してはマキシムが正しいが、それはあのインデックスの話ではない。

記事のクエリ、インデックスなしのスキーマ:395ミリ秒。
同じクエリに通常のインデックス(MAGIC、ENTRY)を追加した場合:427 ms。つまり、全く役に立たない。
同じクエリにカバレッジインデックス(MAGIC、ENTRY、PROFIT、SWAP、COMMISSION)を追加した場合:80 ms。

完全なGROUP BYの場合、通常のインデックスは役に立たない――テーブルは結局丸ごと読み込まれるし、「SCAN ... USING INDEX」という実行計画は、実質的にスキャンと同じだ。 クエリのすべての列がインデックスに含まれている必要があり、その場合、実行計画は「SEARCH ... USING COVERING INDEX」となり、テーブルの行まで処理が進むことはありません。その場合は×5の速度向上となります。

一方、インデックスが実際に効果を発揮するのは、パネルが再描画のたびに実行する1文字単位の抽出処理です:WHERE SYMBOL=? AND ENTRY=1 — インデックスなしでは711ミリ秒、インデックスありでは208ミリ秒です。

3) 構造体の配列について。本質的には私の言う通りですが、必要なインデックスとメソッドを備えた独自のラッパークラスを記述する場合の話です。SQLiteを使えば、確かに開発時間は短縮されますが、その代償としてパフォーマンスとリソース消費が悪化します。

45.8 MBのバイナリファイル全体を読み込む場合:25 ms。
1回のスキャンで、マジック値およびシンボルによる集計を同時に行う場合:7 ms。
比較として、同じ50万行をSQLiteから構造体配列へ読み出す場合(DatabaseReadBind ループ):220ミリ秒。

実際のパフォーマンス向上は、操作によって4~18倍です。また、220 ms 対 25 ms という数値は示唆に富んでいます。もし統計データをMQL5で読み込むのであれば、このシナリオではデータベースは単に低速なファイル形式として機能するに過ぎません。

しかし、ディスク上のデータベースは84MBであるのに対し、バイナリファイルは46MBです。この余分な38MBの代償として、任意のフィルタ、ソート、ページネーション、そしてあらゆる新しいレポートを無料で利用できるようになります。 構造体配列には、手作業で実装しない限り、それらは存在しません。したがって、「データベースなど必要ない」という主張は、事前に想定していなかったクエリが必要になるその瞬間までは正しいと言えます。 この点についてはEnriqueの言う通りです。データを単に読み込むだけでなく、クエリを実行する必要がある場合、SQLには敵いません。

4) PostgreSQLについては、先ほどの発言を撤回します。

これはクライアント・サーバー型であり、組み込むことはできません。独立したプロセス、インストール、ポート、管理作業が必要です。 サンドボックス内のシングルユーザー端末にとっては、アーキテクチャ的に適合しません。また、ローカルでの分析においては、SQLiteの方が多くの場合さらに高速です――IPCやラウンドトリップがないからです。 JSONBに関する議論もすでに古くなっています。SQLiteにはバージョン3.45からJSONBが搭載されていますが、トランザクション履歴にはそもそもJSONは必要ありません。そこには厳密に型指定されたカラムがあるからです。

まとめ

この記事に対する主な不満は、スキーマとコードにあり、エンジンそのものにはありません。「記事にあるようなSQLite」と「正しく実装されたSQLite」との差は100倍です。正しく実装されたSQLiteと構造体の配列との差は、わずか数倍です。

そして、このスレッドで最も的を射た指摘をしたのは92746290さんだ。履歴を丸ごと再読み込みするのではなく、最後に記録されたトランザクションから追加で読み込むようにすべきだ。これは、バイナリデータかデータベースかに関わらず、問題を解決する。

カバーインデックス、バッチ挿入、増分 Sync() を用いたスキーマに加え、構造体配列を使ったバージョンも、興味があれば公開できます。

繰り返しになりますが、私自身はもちろん、データベースを一切使用せず、インデックスと必要なメソッドを備えた軽量なクラスを使用しています。これにより、リソース消費とパフォーマンスの面で明らかなメリットが得られます。
 
Nikolai Semko #:
本質を深く掘り下げずに、早合点してしまいました。申し訳ありません。「学生向けのおもちゃ」という表現は言い過ぎでした。SQLiteはそんな扱いを受けるべきではありません。

学生向けではないかもしれませんが、やはり「おもちゃ」には違いありません。というのも、SQLite を使う前に、 履歴をすべて「掘り起こして」、項目ごとにテーブルに格納しなければならないからです。 これには膨大な時間がかかります。もしこれをMQL5に組み込むなら、注文や取引の履歴の読み取りも、直接テーブルで行う必要があります…私見ですが

 
Nikolai Semko #:
さらに深く掘り下げてみた(AI「Opus 5」を活用し、テスト環境を構築して、50万件の取引データ、20の銘柄、20のマジックナンバーを用いた合成データを生成し、パフォーマンス測定を実施した)。

余談ですが、MonetDB/eとの比較も興味深いでしょう。SQLiteと同様に組み込み型のサーバーレスですが、いくつかの理由から、複雑なクエリでは格段に高速であるはずです。もちろん、適切なスキーマが前提ですが :-)

 
Maxim Kuznetsov #:

余談ですが、MonetDB/eとの比較も興味深いでしょう。SQLiteと同様に組み込み型のサーバーレスですが、いくつかの理由から、複雑なクエリでは格段に高速であるはずです。もちろん、スキーマが適切であることが前提ですが :-)

もしかすると
私もそれについて考えていました
配列に関してはNoSQLの方が適している
試してみる価値がある。AIを使えば、今ならすぐに確認できる