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

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

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

VBScriptでAccessをClose時に時間が掛かる

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

■97598 / inTopicNo.1)  VBScriptでAccessをClose時に時間が掛かる
  
□投稿者/ KenPin (4回)-(2021/06/11(Fri) 13:23:22)

分類:[VBScript] 

サーバ
Windows Server 2016
Office Pro 2016

クライアント
Windows10 Pro 20H2
InternetExplorer11

サーバ上に置いたAccessのデータ(1000件程度のデータテーブル1つ)を検索し表示するWEBページを作成しましたが、
ページが表示されるのに40秒かかる場合があります(時間を置いて1回目)
1回目:40秒
2回目:1秒未満
3回目:1秒未満

時間をおいて(数時間)
4回目:40秒
5回目:1秒未満
6回目:1秒未満

どこに時間が掛かるのか経過時間を各処理の間に記述して確認したところ、
ADO_DB.Closeの処理で時間が掛かっていました。
原因が分からず困っております。
Accessは閉じるときに最適化するようにはしておりません。
何か解決する方法ありますでしょうか?



<HTML>

<SCRIPT LANGUAGE="VBScript" RUNAT=Server>
DIM DB
DIM RS
DIM SQL

'Access接続処理
FUNCTION Access_Open()
	Set DB = Server.CreateObject("ADODB.Connection")
	DB.Open "Provider=Microsoft.ACE.OLEDB.12.0;Persist Security Info=False;Data Source=" & Server.MapPath("./test.accdb")	
END FUNCTION

'Access切断処理
FUNCTION Access_Close()
	ADO_DB.Close
END FUNCTION

'SQL発行
FUNCTION Search(SQL)
	RS.Open SQL,DB,3,3
END FUNCTION

</SCRIPT>

<BODY>
<%
	Call Access_Open()

	Set RS = Server.CreateObject("ADODB.Recordset")
	Call Search("SELECT * FROM TEST_TABLE")

	Do Until RS.EOF
		Response.Write("<TR>")
		Response.Write("<TD NOWRAP>" & RS("DATA1") & "<BR></TD>")
		Response.Write("<TD NOWRAP>" & RS("DATA2") & "<BR></TD>")
		Response.Write("</TR>" & CHR(13))

		RS.Movenext
	Loop
	
	SET RS = NOTHING

	Call Access_Close '←ここで時間が掛かる
%>
</BODY>
</HTML>

引用返信 編集キー/
■97600 / inTopicNo.2)  Re[1]: VBScriptでAccessをClose時に時間が掛かる
□投稿者/ 魔界の仮面弁士 (3127回)-(2021/06/11(Fri) 14:02:24)
2021/06/11(Fri) 14:23:47 編集(投稿者)

No97598 (KenPin さん) に返信
> <SCRIPT LANGUAGE="VBScript" RUNAT=Server>
> Set DB = Server.CreateObject("ADODB.Connection")

Classic ASP ですか?

Web アプリで ACE や Jet を使う事はあまりお奨めしませんが、
それとは別に気になったのが、ファイルの置き場所。

.accdb は、該当フォルダへの書き込みアクセス権を必要とするため、
 Server.MapPath("./test.accdb")
なパスに配置することはセキュリティ上望ましくありません。

Web サーバーから公開されたパスではなく、
非公開な物理パスに配置した方が良いでしょう。


> ADO_DB.Closeの処理で時間が掛かっていました。
そもそも、ADO_DB とは何ですか?
Option Explicit が無く、変数宣言にも見当たりません。

DB.Close や RS.Close とも違うようですし…Global.asa に
 <OBJECT RUNAT="Server" ID="ADO_DB" SCOPE=*** PROGID=***>
があったりするのでしょうか。


> 時間をおいて(数時間)
> 4回目:40秒
ADO_DB の正体が分からないので、何とも言えないですね。

状況的には、IIS のアプリケーション プールが解放された後の、
初回実行時に遅くなっているようですが…。


> DB.Open "Provider=Microsoft.ACE.OLEDB.12.0;Persist Security Info=False;Data Source=" & Server.MapPath("./test.accdb")
読み取り専用アクセスなら、DB.Open 時の接続文字列に
Mode プロパティを加えましょう。
https://accessvba.blog.ss-blog.jp/2011-12-27

読み書きが発生するのであれば、BeginTrans/CommitTrans を
必ず入れましょう。これらが無い場合、Jet/ACE は非同期コミットを
行うため、複数セッションからのアクセス時に問題になります。
http://www.canalian.com/workshop/access/JetCache.html
引用返信 編集キー/
■97601 / inTopicNo.3)  Re[1]: VBScriptでAccessをClose時に時間が掛かる
□投稿者/ WebSurfer (2262回)-(2021/06/11(Fri) 14:31:56)
No97598 (KenPin さん) に返信

> サーバ上に置いたAccessのデータ(1000件程度のデータテーブル1つ)を検索し表示するWEBページを作成しましたが、
> ページが表示されるのに40秒かかる場合があります(時間を置いて1回目)

「時間を置いて1回目」ということから想像するに、要求を受けてワーカープロセスが立ち上がって、
初期化するのに時間がかかっているということですが、そのあたりは確認していますか?

ASP.NET Web アプリで、ワーカープロセスがリサイクルされると、初回の要求の時に上記のことを行
うため、応答を返すまでに時間がかかるということはよく聞き話ですけど。

それに対処するため以下の手段が用意されています。

Auto-Start ASP.NET Applications (VS 2010 and .NET 4.0 Series)
https://weblogs.asp.net/scottgu/auto-start-asp-net-applications-vs-2010-and-net-4-0-series

ただ、質問者さんの Web アプリがクラシック ASP だとすると使えないかもしれませんが。
引用返信 編集キー/
■97602 / inTopicNo.4)  Re[2]: VBScriptでAccessをClose時に時間が掛かる
□投稿者/ KenPin (5回)-(2021/06/11(Fri) 14:41:16)
魔界の仮面弁士様

返信ありがとうございます。
>Classic ASP ですか?
そうです。

> そもそも、ADO_DB とは何ですか?
申し訳ありません誤記でした。
正しくは以下となります。
ADO_DB.Close

DB.Close

環境の記載不足、誤記申し訳ありません。

No97600 (魔界の仮面弁士 さん) に返信
> 2021/06/11(Fri) 14:23:47 編集(投稿者)
>
> ■No97598 (KenPin さん) に返信
>><SCRIPT LANGUAGE="VBScript" RUNAT=Server>
>>Set DB = Server.CreateObject("ADODB.Connection")
>
> Classic ASP ですか?
>
> Web アプリで ACE や Jet を使う事はあまりお奨めしませんが、
> それとは別に気になったのが、ファイルの置き場所。
>
> .accdb は、該当フォルダへの書き込みアクセス権を必要とするため、
>  Server.MapPath("./test.accdb")
> なパスに配置することはセキュリティ上望ましくありません。
>
> Web サーバーから公開されたパスではなく、
> 非公開な物理パスに配置した方が良いでしょう。
>
>
>>ADO_DB.Closeの処理で時間が掛かっていました。
> そもそも、ADO_DB とは何ですか?
> Option Explicit が無く、変数宣言にも見当たりません。
>
> DB.Close や RS.Close とも違うようですし…Global.asa に
>  <OBJECT RUNAT="Server" ID="ADO_DB" SCOPE=*** PROGID=***>
> があったりするのでしょうか。
>
>
>>時間をおいて(数時間)
>>4回目:40秒
> ADO_DB の正体が分からないので、何とも言えないですね。
>
> 状況的には、IIS のアプリケーション プールが解放された後の、
> 初回実行時に遅くなっているようですが…。
>
>
>>DB.Open "Provider=Microsoft.ACE.OLEDB.12.0;Persist Security Info=False;Data Source=" & Server.MapPath("./test.accdb")
> 読み取り専用アクセスなら、DB.Open 時の接続文字列に
> Mode プロパティを加えましょう。
> https://accessvba.blog.ss-blog.jp/2011-12-27
>
> 読み書きが発生するのであれば、BeginTrans/CommitTrans を
> 必ず入れましょう。これらが無い場合、Jet/ACE は非同期コミットを
> 行うため、複数セッションからのアクセス時に問題になります。
> http://www.canalian.com/workshop/access/JetCache.html
引用返信 編集キー/
■97603 / inTopicNo.5)  Re[2]: VBScriptでAccessをClose時に時間が掛かる
□投稿者/ KenPin (6回)-(2021/06/11(Fri) 14:43:57)
WebSurfer様

返信ありがとうございます。

> ただ、質問者さんの Web アプリがクラシック ASP だとすると使えないかもしれませんが。
クラシック ASP です。
教えて頂いた方法も試してみたいと思います。

No97601 (WebSurfer さん) に返信
> ■No97598 (KenPin さん) に返信
>
>>サーバ上に置いたAccessのデータ(1000件程度のデータテーブル1つ)を検索し表示するWEBページを作成しましたが、
>>ページが表示されるのに40秒かかる場合があります(時間を置いて1回目)
>
> 「時間を置いて1回目」ということから想像するに、要求を受けてワーカープロセスが立ち上がって、
> 初期化するのに時間がかかっているということですが、そのあたりは確認していますか?
>
> ASP.NET Web アプリで、ワーカープロセスがリサイクルされると、初回の要求の時に上記のことを行
> うため、応答を返すまでに時間がかかるということはよく聞き話ですけど。
>
> それに対処するため以下の手段が用意されています。
>
> Auto-Start ASP.NET Applications (VS 2010 and .NET 4.0 Series)
> https://weblogs.asp.net/scottgu/auto-start-asp-net-applications-vs-2010-and-net-4-0-series
>
> ただ、質問者さんの Web アプリがクラシック ASP だとすると使えないかもしれませんが。
引用返信 編集キー/
■97622 / inTopicNo.6)  Re[3]: VBScriptでAccessをClose時に時間が掛かる
□投稿者/ 魔界の仮面弁士 (3131回)-(2021/06/15(Tue) 11:10:53)
2021/06/15(Tue) 11:34:34 編集(投稿者)

No97602 (KenPin さん) に返信
>>> Call Access_Close '←ここで時間が掛かる

これといって解決策は思い当たらないですね。
接続時ならロード待ちでしょうけれど、終了時なので何かの同期待ちかな…と予想していますが。

ただ、40 秒というのはかかり過ぎなので、別の外部要因もありそうです。

Windows Update を行ってみて、それでも解決しないようなら、
システムコンポーネントの不整合を疑って、別のクリーンな
検証環境を立ててみて、同じ現象が起きる確認してみるとか。

もし、アンチウイルスソフトが動作しているのであれば、
一時的に .accdb フォルダーを除外対象にして様子を見てみるとか。

あとは Process Monitor 等で追跡できないか調べてみるとか…?


>>> 読み書きが発生するのであれば、BeginTrans/CommitTrans を
>>> 必ず入れましょう。これらが無い場合、Jet/ACE は非同期コミットを
>>> 行うため、複数セッションからのアクセス時に問題になります。
>>> http://www.canalian.com/workshop/access/JetCache.html

*.accdb や *.mdb を使う場合、トランザクション指定は必須です。

データベースを排他モードで開く場合や、一切編集が無いなら別ですが、
複数の接続から更新が行われる場合、非同期コミット(遅延書き込み)は
トラブルの元となります。


一応、.accdb に対する ACE Provider のリソースプールの利用可否も確認してみました。

ASP を実行できる環境が手元にないので、VBS 構文ではなく Access VBA での確認です。
(サンドボックス設定が異なりますし、VBScript からだと別の結果になるかも)


'=== プロバイダー名の確認(固定値) ===
' 下記が "Microsoft.ACE.OLEDB.12.0" を返した。
Debug.Print DB.Provider


'=== スレッドモデルの確認 ===
'『プールされるには、プロバイダーがフリースレッドモデルをサポートする
' 必要があります。 リソースプールは、DBPROP_THREADMODEL プロパティに
' 従って、プロバイダーのスレッドモデルを決定します。』
' https://docs.microsoft.com/ja-jp/cpp/data/oledb/ole-db-resource-pooling-and-services?WT.mc_id=DT-MVP-8907&view=msvc-160
'
Const DBPROPVAL_RT_FREETHREAD As Long = &H00000001&
Const DBPROPVAL_RT_APTMTTHREAD As Long = &H00000002&
Const DBPROPVAL_RT_SINGLETHREAD As Long = &H00000004&

' 下記が DBPROPVAL_RT_FREETHREAD を返した。
Debug.Print DB.Properties("Data Source Object Threading Model").Value


'=== プールの有効可否 ===
' https://docs.microsoft.com/en-us/previous-versions/windows/desktop/ms724518%28v=vs.85%29?WT.mc_id=DT-MVP-8907&view=msvc-160
'
Const DBPROPVAL_OS_DISABLEALL As Long = &H00000000&
Const DBPROPVAL_OS_RESOURCEPOOLING As Long = &H00000001&
Const DBPROPVAL_OS_TXNENLISTMENT As Long = &H00000002&
Const DBPROPVAL_OS_CLIENTCURSOR As Long = &H00000004&
Const DBPROPVAL_OS_AGR_AFTERSESSION As Long = &H00000008&
Const DBPROPVAL_OS_ENABLEALL As Long = &HFFFFFFFF&

services = DB.Properties("OLE DB Services").Value

' 下記は -2, プール無効を示した。
Debug.Print services
Debug.Print IIf(CBool(services And DBPROPVAL_OS_RESOURCEPOOLING), "プール有効", "プール無効")


'=== 内部暗黙トランザクションを使用した場合の書きこみ動作 ===
' R/W [DBPROP_JETOLEDB_IMPLICITCOMMITSYNC]
' True: 変更結果が同期的に書き込まれる。
' False:変更結果が非同期に書き込まれる。(既定値)
'
' 下記が False を返した
Debug.Print DB.Properties("Jet OLEDB:Implicit Commit Sync").Value


'=== ユーザーの明示的なトランザクションを使用した場合の書きこみ動作 ===
' R/W [DBPROP_JETOLEDB_USERCOMMITSYNC]
' True: 変更結果が同期的に書き込まれる。(既定値)
' False:変更結果が非同期に書き込まれる。
'
' 下記が True を返した
Debug.Print DB.Properties("Jet OLEDB:User Commit Sync").Value


'=== 非同期書き込みキャッシュがディスクにフラッシュされるまでの非アクティブ時間 ===
' R/W [DBPROP_JETOLEDB_FLUSHTRANSACTIONTIMEOUT]
' この値が 0 以外の場合、"Jet OLEDB:Shared Async Delay" と
' "Jet OLEDB:Exclusive Async Delay" は無視される。
'
' 下記が 0 を返した
Debug.Print DB.Properties("Jet OLEDB:Flush Transaction Timeout").Value


'=== 複数ユーザーモードで開かれているデータベースに、ディスクへの非同期書き込み遅延させる最大ミリ秒 ===
' R/W [DBPROP_JETOLEDB_SHAREDASYNCDELAY]
' この設定は、"Jet OLEDB:Flush Transaction Timeout" が 0 でない限り無視される。
'
' 下記が 0 を返した
Debug.Print DB.Properties("Jet OLEDB:Shared Async Delay").Value


'=== 排他モードで開かれているデータベースに、ディスクへの非同期書き込み遅延させる最大ミリ秒 ===
' R/W [DBPROP_JETOLEDB_EXCLUSIVEASYNCDELAY]
' この設定は、"Jet OLEDB:Flush Transaction Timeout" が 0 でない限り無視される。
'
' 下記が 0 を返した
Debug.Print DB.Properties("Jet OLEDB:Exclusive Async Delay").Value


'=== 解放時に BLOB ページを積極的に再利用するかどうか ===
' R/W [DBPROP_JETOLEDB_RECYCLELONGVALUEPAGES]
' ※ここでいう Long Value とは、恐らく LongBinary/LongText 型のこと。
' True:
'  共有モードのデータベースにユーザーが 1 人だけで、新しい Long Value 値が
'  データがデータベースに追加されたとエンジンが判断した後で、
'  その Long Value が確保していたページを再利用できるようになる。
' False:
'  破棄された Long Value 値のページは引き続きデータベース内のスペースを占有し、
'  最後のユーザーがデータベースを閉じた後にのみ再利用できるようになる。
'
' 下記が False を返した
Debug.Print DB.Properties("Jet OLEDB:Recycle Long-Valued Pages").Value
引用返信 編集キー/

このトピックをツリーで一括表示


トピック内ページ移動 / << 0 >>

このトピックに書きこむ