中央競馬の予想や購入したもののメモなどを書いて行こうかと。まあ、個人的なメモ的なブログです。
[PR]上記の広告は3ヶ月以上新規記事投稿のないブログに表示されています。新しい記事を書く事で広告が消えます。
ブログにはひと月ぶりの書き込みですが、昨年末からの入退院の繰り返しもどうにか一段落したので、本業の三交代勤務でプログラミングし放題ではなくなったので、若干のスローダウンはしてますが、開発は続行中。今現在も通算何度目になるのか分からなくなってるフルセットアップ実行中。
実は先週初めからここまでのJV-Linkでのデータ読込にJVReadを使ってたのを思い切って変更してみようと着手。開発当初から少しパフォーマンスが上がると言われるJVGetsの存在は知ってたけど、メモリリークが改善出来ず、1年分取得途中でメモリ不足で止まるんだったか、まあ、対処にあまり時間取られるのも嫌だったのでJVReadで開発進めてました。で、JRA-VANの掲示板にて参考になる書き込みが有り、少しでも改善されるならとJVGetsでのデータ読込に書き換えてテストしてたりしました。
まあ、C#では自動でガーベッジコレクションされるからって事が逆に仇になってる感じで、JVGetsで取得するデータをデータベースに登録する際にゴニョゴニョしてると一向にガーベッジコレクション対象と認識されないって事の様で、この対処方法としてSafeArrayなるものを利用すればって話で、これ使ってJVGetsを採用する事が可能になりました。で、JRA-VANからデータ構造体なんかのクラス定義等が提供されているんですが、このC#版に実装されているメソッドが当初は文字列を構造体に代入する感じなのが普通に思えてたんですが、今回のSafeArrayかます関係でbyte配列を文字列にしてこのクラスメソッドにすると結局オーバーヘッドが高くなりJVReadからJVGetsへ変更るメリットが帳消しになると思ってたら、このクラス自体文字列で受けてわざわざbyte配列に最初にコピーしてるではないですか。で、このクラスをbyte配列を受けて構造体に代入するものを書き加えて後数時間で、JVGetsでのフルセットアップが終わる予定です。
JVReadでのフルセットアップには14時間17分掛かってました。本日中番出勤直前まで作業して12:19にセットアップ開始してるので、そろそろ12時間経過。もう少しで2018年まで終わりそうなので、残り3年ちょいは2時間までは掛からないだろうから多少の改善は見込めそう^^
ふと、遠い昔の記憶からデータベースでのインデックスの存在を思い出し、グーグル先生に確認しながら実装してみました。先に結果からですが、やはり画期的にスピードは上がりました。これならどうにか使えるんじゃないかと自己解決にしようかなっと。
インデックス作成はインデックスにもよりますが、当たり前ですが時間も掛かるしデータベース容量も増えるって事でメリットとデメリットがある訳で、データ登録はかなり良好なスピードなので、インデックス常駐にはしたくないかと思い、使う場所で
CREATE INDEX xxx ON table(column)
な感じで。流石に初回作成時には数十秒、1分までは行かない感じなのでギリ許容範囲かな~っと。で、使い終わる時に
DROP INDEX xxx
しておけば、データ登録に悪影響は無いかな~っと安易に考えてます。
このインデックス作成もキャッシュに乗る感じで、2回目はかなり早くなる。なので、1回目だけ少し我慢な感じです。
業務ではほぼDB関連の仕事してないので、ほぼというのは全くではないけど、管理者としては関わってないけど、DB絡みのプロジェクトは経験有り、他の開発者とはDBとは的な話はした事はある。ってか、多分偉そうな事を言った気がする。学生時代の記憶からだと思うが、DBとは的な知識からリレーショナルDBとインデックスシーケンシャルなデータファイル管理とかの話だったかもだけど、間違ってはなかったとは思うが、偉そうに言えるレベルではなかったかも^^;
なんにしても、SQLite3にデータ登録は納得がいくレベルで処理出来る所まで来てると思うけど、いやね、実際にはまだ少し手を抜いてるから早いだけな気もしてますが、そこは置いておいて、今回は登録済んだので、そのデータの利用な部分なんですが、これがまた当初はEntity Frameworkの遅さがって事だったんですが、EF無でも遅いのは...
もう、ここ数日色々グーグル先生にも問い合わせましたが的確な回答は得られず、随分色々と試しましたが、現時点の自分の力量ではここは放置が吉と判断して、別処理の開発に進む事にしました。まあ、その際、ちょっとだけごまかしじゃないけど、見た目としての逃げでForm_Loadイベントで全てこなすと表示されるまで延々と何も起きないのを待つのはユーザーには問題かな~っと時間掛かる処理をForm_Shownイベントに移動する事で画面上では少し変化した状態で固まる(笑)感じにしてみた。これなら何となくWindowsかSystemが遅いのかな~って感じにも見えなくはないので苦肉の策です。余裕が出来たら改善してみる努力はしようかな~っと^^ いやね、リッチにSQLiteのDBファイルをSSDに丸ごと乗せればもう少しレスポンスも早いだろうとか、ねぇ~(笑) 自分では絶対にSSDの寿命縮めるので試しませんけど^^;
少し考えてたのですが、今回自分がやっている事はあくまでEntity FrameworkでSQLiteを扱うって事なんですが、今回のコードファーストやり始め、SQL Server Expressに対しては本当に楽でしたので、このEntity FrameworkはSQL Server 相手なら悪くないパフォーマンスだから世の中の多数の人達は何ら問題なく使っているのかも? マイグレーションとかも不要だったし...でも、サーバー立ち上げてとか避けたくSQLiteに落ち着いたので、ここは自分自身が選んだ道だからやるしかないのかな^^;
ほんの小さなテーブルの1レコード取得してくる位はEnity Frameworkでも行けるんじゃないかと手を抜くと、普通に遅かった。なので、今回全てのDBアクセスはEntity Framework抜きで行く。なら、Microsoft.EntityFrameworkCoreだったかな?これも本来不要だったかもですが、なんだったか必要な時があった気がする。ああ、AsNoTrackingか^^; これも使わないからマイグレーションのみの理由で使う事になるのか。
で、基本的なアクセスはSQL文用意してExecuteReader()使ってレコード取得して処理するんですが、以前データ登録ではExecuteNonQuery()で戻り無しだったけど、レコード受けるヴァリアント型を解放しないと
'DataReader already active on this command'
ってエラーが出る。なので、使い終わったらDisposeAsync()で空にしておけば問題ない感じです。
追記 2022/02/15 16:39
上記DisposeAsync()ですが、問題は解消されたので間違いではないと思われますが、本来普通にClose()すれば良い感じなのでこちらに変更。
大昔、世の中にADO.NETがやっと現れた頃に早速飛びついて今回やってる事と同じ事を試してデータベース作成に挑み、1年分のデータ登録に1日とか余りの激遅に一旦投げた事があるんですが、月日が流れても便利な機能にはその代償があるんですかね? それとも単に自分自身が消化不良で機能を生かし切れていないのか^^;
今回のEntity Frameworkやコードファーストも凄く便利な機能で、随分と楽にデータベース開発が出来る様になったな~と必死に書いてるんですが、60ギガバイトのデータベースが悪いのかな~っとかDB分割によるダイエットも結局7分割まで行いました。でも、アクセスが非常に遅く、使い物にならないな~っと。データベース作成時はSQLiteの特性(?)でトランザクション明示的にするとかで、Entity Frameworkを避けて手動でパラメーター用意して登録するって変更とデバッグに相当な時間を費やしました。
出来上がったデータベース参照もまあ、もしかしたらDbContextのコンストラクタを上手く書き上げればクリア出来るものなのかもですが、デーベース作成時と同様に自力でオープンするスタイルに変更してみました。
using (var db = new KSD_DB())
{
var races = db.RACEINFO.Where(r => r.JOUCD.StartsWith("0") ||
r.JOUCD.StartsWith("1"))
.OrderByDescending(r => r.KAISAIBI)
.AsNoTracking()
.ToArray();
foreach (var race in races)
{
って感じで書いてたものを
SqliteConnectionStringBuilder sqlBuilder = new SQLiteConnectionStringBuilder()
{
DataSource = "KSD_DB.db",
ReadOnly = true
};
using (SQLiteConnection con = new SQLiteConnection(sqlBuilder.ToString())
{
con.Open();
using (SQLiteCommand cmd = new SQLiteCommand(con))
{
cmd.CommandText = "SELECT KAISAIBI FROM RACEINFO " +
"WHERE JOUCD LIKE '0%' OR JOUCD LIKE '1%' " +
"ORDER BY KAISAIBI DESC";
var races = cmd.ExecuteReader();
while (races.Read())
{
としてみると、数分掛かっていたツリービュー表示が数秒とやっと期待通りの反応になってくれました。もっと勉強してEntity Frameworkを使いこなせば、やりたい事が数秒で出来るのかは不明ですが、ここは作業進める事を優先します。ただ、Entity Frameworkってもうリリースから随分経つ訳で、あんな激遅では誰も使わない筈なので使い方把握出来てないだけと信じたいですね。そして、理解出来る日が近い将来来る事を願いグーグル先生に色々教えて貰えればと思います^^