C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

Re[13]: Adapter.Fill実行1回目が遅い


(過去ログ 172 を表示中)

[トピック内 24 記事 (1 - 20 表示)]  << 0 | 1 >>

■99119 / inTopicNo.1)  Adapter.Fill実行1回目が遅い
  
□投稿者/ ど (1回)-(2022/02/07(Mon) 09:25:16)

分類:[.NET 全般] 

ボタンを押すとデータベースからデータを取得して画面に表示するというアプリを作っています。
DataAdapter.Fillメソッドを使ってDataSetにデータを格納しています。

アプリを起動して1回目にDataSetにデータを格納する時は数秒かかりますが、2回目からは1秒以内に結果が返ってきます。2回目に走らせる場合は検索条件は違うのに、2回目以降は遅さを感じません。

なぜ1回目がやたらと遅くて2回目が普通に検索できるのかがわかりません。何が考えられるでしょうか?



引用返信 編集キー/
■99120 / inTopicNo.2)  Re[1]: Adapter.Fill実行1回目が遅い
□投稿者/ WebSurfer (2439回)-(2022/02/07(Mon) 09:45:46)
No99119 (ど さん) に返信

> なぜ1回目がやたらと遅くて2回目が普通に検索できるのかがわかりません。何が考えられるでしょうか?

接続プールを作るのに時間がかかっているとか?
引用返信 編集キー/
■99121 / inTopicNo.3)  Re[2]: Adapter.Fill実行1回目が遅い
□投稿者/ ど (2回)-(2022/02/07(Mon) 10:41:46)
> 接続プールを作るのに時間がかかっているとか?

接続プールが何かわからなかったので調べてみてわかりました。
1回目から遅延がないようにする方法は何かあるのでしょうか?
引用返信 編集キー/
■99122 / inTopicNo.4)  Re[3]: Adapter.Fill実行1回目が遅い
□投稿者/ 古谷 (27回)-(2022/02/07(Mon) 11:43:53)
No99121 (ど さん) に返信

ダミーのクエリを実行すればいんじゃないかな
SELECT GETDATE()
とか

コネクションプールが作られるのがConnectionをOpenしたときなら
Openだけでいいかも、要実験
引用返信 編集キー/
■99123 / inTopicNo.5)  Re[3]: Adapter.Fill実行1回目が遅い
□投稿者/ radian (10回)-(2022/02/07(Mon) 11:49:49)
> 接続プールが何かわからなかったので調べてみてわかりました。
> 1回目から遅延がないようにする方法は何かあるのでしょうか?

Task.Run(() =>
   {
       using (var con = new OdbcConnection(connectionString))
       {
           con.Open();
       }
   }
);

みたいなのをプログラムの起動時に実行しておくとか。
(OdbcConnectionじゃない場合は自分の使う奴に置き換えてください)
接続出来なかった場合の例外処理はしてください。
いずれにせよ、接続終わる前にSQL処理実行されたら時間掛かるでしょうけど。

引用返信 編集キー/
■99124 / inTopicNo.6)  Re[3]: Adapter.Fill実行1回目が遅い
□投稿者/ WebSurfer (2440回)-(2022/02/07(Mon) 11:58:03)
No99121 (ど さん) に返信
>>接続プールを作るのに時間がかかっているとか?
>
> 接続プールが何かわからなかったので調べてみてわかりました。
> 1回目から遅延がないようにする方法は何かあるのでしょうか?

そもそも接続文字列を作るのに時間がかかっているのが原因かどうかもわかりませんが
(実は使ってないかもしれない)、それが原因だとして・・・

データベースが何か、それに使うプロバイダが何か、接続文字列をどう設定しているか、
そういう情報が一切ないので分かりません。それを書いてから質問してください。
引用返信 編集キー/
■99125 / inTopicNo.7)  Re[4]: Adapter.Fill実行1回目が遅い
□投稿者/ WebSurfer (2441回)-(2022/02/07(Mon) 12:02:22)
No99124 訂正します

×: そもそも接続文字列を作るのに・・・
〇: そもそも接続プールを作るのに・・・

引用返信 編集キー/
■99126 / inTopicNo.8)  Re[5]: Adapter.Fill実行1回目が遅い
□投稿者/ くま (160回)-(2022/02/07(Mon) 14:47:01)
DBの種類とSQLが分からないけれども
キャッシュが利いているからってオチはないよね?

https://memorandom-nishi.hatenablog.jp/entry/2017/02/05/180525
https://qiita.com/Masayuki_Ozawa/items/f700b32ce54a382d23a6
引用返信 編集キー/
■99136 / inTopicNo.9)  Re[6]: Adapter.Fill実行1回目が遅い
□投稿者/ 大谷刑部 (172回)-(2022/02/09(Wed) 09:48:48)
No99126 (くま さん) に返信
> DBの種類とSQLが分からないけれども
> キャッシュが利いているからってオチはないよね?
>
> https://memorandom-nishi.hatenablog.jp/entry/2017/02/05/180525
> https://qiita.com/Masayuki_Ozawa/items/f700b32ce54a382d23a6

2回目からは速いならその可能性が一番高い気が。

質問者さん、
まずは、SQL直叩きとアプリ(話の流れ的にADO.net?)通したときのパフォーマンスの違いを計測した方がいいかも。
引用返信 編集キー/
■99137 / inTopicNo.10)  Re[7]: Adapter.Fill実行1回目が遅い
□投稿者/ ど (3回)-(2022/02/09(Wed) 11:30:25)
MSACCESSとSQLITEで試してみましたが結果は変わりませんでした。1回目は遅く、2回目は速いです。
接続文字列は以下のようになっています。

connectionString="Provider=Microsoft.ACE.OLEDB.12.0;Data Source=C:mydb.accdb"
Data Source=c:\mydb.db;Version=3;

データベースを直接さわってクエリを投げてみましたが、1秒以内には結果が返ってきました。

キャッシュに関するページをご紹介頂きましたが、ほとんど理解できませんでした・・・
引用返信 編集キー/
■99138 / inTopicNo.11)  Re[8]: Adapter.Fill実行1回目が遅い
□投稿者/ ど (4回)-(2022/02/09(Wed) 12:18:14)
データベースにはこのようなかたちで接続しています。

OleDbConnection nwindConn = new OleDbConnection(connectionString="Provider=Microsoft.ACE.OLEDB.12.0;Data Source=C:mydb.accdb");  
OleDbCommand selectCMD = new OleDbCommand("SELECT CustomerID, CompanyName FROM Customers", nwindConn);  
  
OleDbDataAdapter customerDA = new OleDbDataAdapter();  
customerDA.SelectCommand = selectCMD;  
DataSet customerDS = new DataSet();  
customerDA.Fill(customerDS, "Customers");  

引用返信 編集キー/
■99139 / inTopicNo.12)  Re[9]: Adapter.Fill実行1回目が遅い
□投稿者/ shu (1272回)-(2022/02/09(Wed) 13:06:21)
No99138 (ど さん) に返信
> データベースにはこのようなかたちで接続しています。
>
> OleDbConnection nwindConn = new OleDbConnection(connectionString="Provider=Microsoft.ACE.OLEDB.12.0;Data Source=C:mydb.accdb");
> OleDbCommand selectCMD = new OleDbCommand("SELECT CustomerID, CompanyName FROM Customers", nwindConn);
>
> OleDbDataAdapter customerDA = new OleDbDataAdapter();
> customerDA.SelectCommand = selectCMD;
> DataSet customerDS = new DataSet();
> customerDA.Fill(customerDS, "Customers");

AccessDBへのアクセスは
最初ファイルオープンを伴うのでその分時間がかかります。
引用返信 編集キー/
■99140 / inTopicNo.13)  Re[8]: Adapter.Fill実行1回目が遅い
□投稿者/ 大谷刑部 (173回)-(2022/02/09(Wed) 13:23:05)
No99137 (ど さん) に返信
> MSACCESSとSQLITEで試してみましたが結果は変わりませんでした。1回目は遅く、2回目は速いです。
> 接続文字列は以下のようになっています。
>
> connectionString="Provider=Microsoft.ACE.OLEDB.12.0;Data Source=C:mydb.accdb"
> Data Source=c:\mydb.db;Version=3;

Accessなら、1回目を速くするのはほぼ不可能でしょうね。
SQL文自体を見直すなどで全体を速くすることは可能でしょうが。
SQLServerやOracleであれば、1回目のSQLが例えば画面を表示した後の何らかのボタンクリック時に実行されるとしたら、
Form_Load等で統計情報を取得しておけば、毎回似たようなレコードがヒットするのであれば、相対的に速くすることは可能です。
ただそれも、1回目を2回目以降とほぼ同じスピードでというのを保証するものではありません。

SQLiteはそもそもメモリを軽量で済むようにする代わりにDBとしての機能をだいぶそぎ落としたツールなので、
3秒で遅いと気にするくらいの性能目標があるシステムではそもそも使うべきではありません。
同じフリーでもMySQLかポスグレを使うべきでしょう。

> データベースを直接さわってクエリを投げてみましたが、1秒以内には結果が返ってきました。

そうであればSQLの実行自体よりも持ってきたレコードを器(Dataset)に入れるのに時間がかかってるという可能性はありますが、
基本的には1回目が遅いのはごく普通のことなので、それをどこまでユーザーが気にするかどうかです。

> キャッシュに関するページをご紹介頂きましたが、ほとんど理解できませんでした・・・

簡単に言えば1回目はキャッシュが利用できないからおそいが、2回目以降は利用できるので速いというイメージです。
引用返信 編集キー/
■99141 / inTopicNo.14)  Re[9]: Adapter.Fill実行1回目が遅い
□投稿者/ ど (5回)-(2022/02/10(Thu) 11:00:00)
ポスグレ等のサーバーがたてる環境に無かったのでSQLITE等を使っています。
これらを使っている分には1回目を速くするのは難しいのは理解できました。

C#からDBにアクセスしてデータを抽出後にデータベースとの切断は切れています。
毎回似たようなデータしか検索しませんが、毎回行う検索は違います。
なので、キャッシュと言われていますが、何がキャッシュされているから
2回目以降の検索が速くなるのでしょうか?

今後はフォームロード時に一度何らかのクエリをDBに投げてみようと思います。
引用返信 編集キー/
■99142 / inTopicNo.15)  Re[10]: Adapter.Fill実行1回目が遅い
□投稿者/ 古谷 (29回)-(2022/02/10(Thu) 11:45:56)
ふーむ、速度差の違いはなんだろうね
JITコンパイルの影響もありそうな気がする

https://ufcpp.net/study/csharp/framework/fwjitcompilation/#jit-compilation
> クラスやメソッドなどを初めて使う瞬間にコンパイルが走ります。2回目以降の利用はかなり高速に動作できます。
引用返信 編集キー/
■99143 / inTopicNo.16)  Re[9]: Adapter.Fill実行1回目が遅い
□投稿者/ 魔界の仮面弁士 (3289回)-(2022/02/10(Thu) 16:47:07)
No99138 (ど さん) に返信
> データベースにはこのようなかたちで接続しています。
> OleDbConnection nwindConn = new OleDbConnection(connectionString="Provider=Microsoft.ACE.OLEDB.12.0;Data Source=C:mydb.accdb");

ネットワークフォルダーに配置してあったりすると、ネットワーク構成の問題で
初回接続に時間がかかることがあるのですが、現状はローカルフォルダーのようですね。

ただ、Data Source の指定が相対パスになっているように見えますね。
絶対パスで指定したらどうなりますか?

たとえば、ファイルサイズの異なる同名の 3 つのファイルを
 C:\example.txt
 C:\folder1\example.txt
 C:\folder1\folder2\example.txt
というパスに配置して、コマンドラインから

CD /D C:\
DIR C:example.txt
CD /D C:\folder1\
DIR C:example.txt
CD /D C:\folder1\folder2\
DIR C:example.txt

を実行すると、DIR で指定した相対パスはすべて同一であるものの、
実際に指し示す絶対パスは異なっているため、
それぞれ別のファイルサイズが表示されることになります。


また、今回の件にかかわらず、C:\ にファイルを配置することは避けた方が良いでしょう。
ここは非管理者にとっては読み取り専用の領域であるため、セキュリティ面でブロックされたり、
あるいは VirtualStore へのリダイレクトが発生してしまうなどの問題を生じることがあるためです。


> customerDA.Fill(customerDS, "Customers");
Fill する前に、明示的に nwindConn.Open(); を実施し、
Fill した後に、明示的に nwindConn.Close(); を呼び出した場合、
時間がかかるのはどの行ですか?


初回の Open だけが時間がかかるのか
Open ではなく Fill のタイミングで時間がかかるのか。
引用返信 編集キー/
■99147 / inTopicNo.17)  Re[10]: Adapter.Fill実行1回目が遅い
□投稿者/ ど (6回)-(2022/02/10(Thu) 19:48:42)
コードをはしおってしまって申し訳ないです。
明示的にOpen、Closeはおこなっています。

一部コードを省略していますが、DataSetの結果に基づいてInsert処理を走らせています。
ブレークポイントを設定して調査するとcustomerDA.Fillの箇所が一番時間がかかります。
それ以外のところは全く時間がかかりません。例えば初回にDataSetに入れるところが3〜5秒くらいだとすると、2回目以降にDataSetに入れるところは1秒以内で処理が完了します。

テーブルのデータを空っぽにしても結果は同じです。Indexも張っています。

C以外にも、Dドライブ直下、D:\testフォルダ、ネットワークフォルダなど全部試しましたが結果は1回目が
遅く2回目以降は速いです。これらのファイルは絶対パスで指定います。

ちなみに.Net Frameworkのバージョンは4.7.2になります。

OleDbConnection nwindConn = new OleDbConnection(connectionString="Provider=Microsoft.ACE.OLEDB.12.0;Data Source=C\:test\mydb.accdb");  

nwindConn.Open();
OleDbConnection nwindTransaction = nwindConn.BeginTransaction(IsolationLevel.ReadCommitted);

OleDbCommand selectCMD = new OleDbCommand("SELECT CustomerID, CompanyName FROM Customers", nwindConn);  

OleDbDataAdapter customerDA = new OleDbDataAdapter();  
customerDA.SelectCommand = selectCMD;  
DataSet customerDS = new DataSet();  
customerDA.Fill(customerDS, "Customers"); 

// INSERT処理
selectCMD.Dispose();
nwindConn.Close();
nwindTransaction.Commit();
nwindTransaction.Dispose();
nwindTransaction = null;

引用返信 編集キー/
■99148 / inTopicNo.18)  Re[11]: Adapter.Fill実行1回目が遅い
□投稿者/ 古谷 (30回)-(2022/02/10(Thu) 20:57:09)
ぜんぜん関係ないけどコネクションのクローズとトランザクションのコミットは逆にした方が…
引用返信 編集キー/
■99149 / inTopicNo.19)  Re[11]: Adapter.Fill実行1回目が遅い
□投稿者/ 魔界の仮面弁士 (3291回)-(2022/02/10(Thu) 21:59:45)
No99147 (ど さん) に返信
> コードをはしおってしまって申し訳ないです。
> OleDbConnection nwindConn = new OleDbConnection(connectionString="Provider=Microsoft.ACE.OLEDB.12.0;Data Source=C\:test\mydb.accdb");
これ、そもそも構文エラーになりません?
パスだけでなく、トランザクション処理もなんだか不自然…。


> OleDbCommand selectCMD = new OleDbCommand("SELECT CustomerID, CompanyName FROM Customers", nwindConn);
nwindConn という名前からして、Access テンプレートの
「ノースウィンド 2007」サンプルデータベースかと思いましたが、
Customers テーブルの列定義が違っていますね。


第三者が検証できるよう、初回低速化が発生している accdb のサンプルを共有いただくことはできますか?
あるいはデータベースファイルを新規に作成し、そこにテーブルをエクスポートしてみた場合、
新規ファイルでも同様に初回低速の現象が見られますか?
(特定のファイルだけで起きる事象なのか、環境依存の問題なのかを切り分ける意図です)

で。
Open が特に遅いわけではなく、初回の Fill のみが遅いとなると、
 (1) 断片化などにより、初回のスキーマ抽出に時間がかかっている
 (2) 使用中のセキュリティソフトによる監査が初回アクセス時にのみ発生してしまっている
 (3) ADO.NET 内部のビルトイン データ アクセス トレース(BidTrace) による影響
ぐらいしか思い当たりませんでした。
引用返信 編集キー/
■99150 / inTopicNo.20)  Re[12]: Adapter.Fill実行1回目が遅い
 
□投稿者/ WebSurfer (2442回)-(2022/02/11(Fri) 09:43:41)
No99149 (魔界の仮面弁士 さん) に返信
No99147 (ど さん) に返信

>>OleDbCommand selectCMD = new OleDbCommand("SELECT CustomerID, CompanyName FROM Customers", nwindConn);
> nwindConn という名前からして、Access テンプレートの
> 「ノースウィンド 2007」サンプルデータベースかと思いましたが、
> Customers テーブルの列定義が違っていますね。

英語版の Northwind.accdb というのがあって、その中に Customers と Customers 2007 というテーブル
がありますが、後者のフィールドが CustomerID, CompanyName, ContactName ... となっています。

質問者さん、それを使ってますか?




引用返信 編集キー/

次の20件>
トピック内ページ移動 / << 0 | 1 >>

管理者用

- Child Tree -