従来のASP(VBScript)でMS SQL Server 2012データベースに接続しています。これは私の接続文字列です。
Provider=SQL Server Native Client 11.0;Server=localhost;
Database=databank;Uid=myuser;Pwd=mypassword;
このSQLコマンドを実行すると:
UPDATE [info] SET [stamp]='2014-03-18 01:00:02',
[data]='12533 characters goes here',
[saved]='2014-03-18 01:00:00',
[confirmed]=0,[ip]=0,[mode]=3,[rebuild]=0,
[updated]=1,[findable]=0
WHERE [ID]=193246;
次のエラーが表示されます。
Microsoft SQL Server Native Client 11.0
error '80040e31'
Query timeout expired
/functions.asp, line 476
SQLクエリは非常に長く、データフィールドは12533文字で更新されます。 ID列にはインデックスが付けられているため、ID 193246の投稿をすばやく見つけることができます。
SQL Server Management Studioでまったく同じSQL式(コピーアンドペースト)を実行すると、すぐに正常に完了します。問題はありません。したがって、SQL自体に問題はありません。私はADODB.Recordsetオブジェクトを使用して、それを介して更新(自己記述のSQLなし)を試みましたが、それでも同じタイムアウトエラーが発生します。
Management Studioで[ツール]> [オプション]> [クエリの実行]に移動すると、実行タイムアウトが0(無限)に設定されていることがわかります。 [ツール]> [オプション]> [デザイナー]で、トランザクションタイムアウトが30秒に設定されていることがわかります。これは、スクリプトとデータベースが同じコンピューター上にあるため十分なはずです( "localhost"は接続文字列にあります)。
ここで何が起こっていますか? ASPコードではなく、Management StudioでSQLを実行できるのはなぜですか?
編集:念のため、[デザイナー]タブで30秒のタイムアウトを600秒に設定しようとしましたが、同じエラーが表示されます(30秒のページ読み込み後に発生します)。
ASPページでSQLを実行するために使用するコードは次のとおりです。
Set Conn = Server.CreateObject("ADODB.Connection")
Conn.Open "Provider=SQL Server Native Client 11.0;
Server=localhost;Database=databank;Uid=myuser;Pwd=mypassword;"
Conn.Execute "UPDATE [info] SET [stamp]='2014-03-18 01:00:02',
[data]='12533 characters goes here',[saved]='2014-03-18 01:00:00',
[confirmed]=0,[ip]=0,[mode]=3,[rebuild]=0,[updated]=1,[findable]=0
WHERE [ID]=193246;"
編集2:使用Conn.CommandTimeout = 0
クエリに無限の実行時間を与えることは何もせず、クエリを永久に実行させます。 25分待ったが、まだ実行中でした。
次に、SQLを2つのSQLステートメントに分割しようとしました。1つは長いデータの更新で、もう1つは他の更新です。それでも長いデータフィールドは更新されず、タイムアウトになります。
2つの追加の接続文字列でこれを試しました。
Driver={SQL Server};Server=localhost;Database=databank;Uid=myuser;Pwd=mypassword;
Driver={SQL Server Native Client 11.0};Server=localhost;Database=databank;Uid=myuser;Pwd=mypassword;
うまくいきませんでした。実際のデータが問題を引き起こしているかどうかを確認するために、データを12533 Aに変更することさえ試みました。いいえ、同じ問題。
その後、私は何か面白いことを発見しました。データフィールドを長時間更新する前に、最初に短いSQLを実行しようとしました。また、クエリタイムアウト例外が発生しました...
しかし、なぜ?更新するものはほとんどありません(SQLステートメント全体が200文字未満です)。さらに調査します。
編集3:ログインに関係しているのではないかと思っていましたが、間違っているように見えるものは見つかりませんでした。接続文字列を変更してsaアカウントを使用しようとしましたが、それでも機能せず、「クエリタイムアウトが期限切れ」になりました。
これは私を怒らせています。解決策も回避策もありませんし、最悪の場合はアイデアもありません!
編集4: Management Studioの[ツール]> [オプション]> [デザイナー]に移動し、[テーブルの再作成が必要な変更の保存を防ぐ]にチェックマークを付けました。何もしませんでした。
「data」列のデータ型を「nvarchar(MAX)」から下位の「ntext」型に変更しようとしました(必死になっています)。うまくいきませんでした。
私が考えることができるポストで最小の変更を実行しようとしました:
UPDATE [info] SET [confirmed]=0 WHERE [ID]=193246;
これにより、ビット列がfalseに設定されます。うまくいきませんでした。 Management Studioでまったく同じクエリを実行してみましたが、問題なく動作しました。
私は今、本当に不足しているので、もしあなたがそれらを持っているなら、私にいくつかのアイデアを投げてください。
編集5:次の接続文字列も試してみました:
Provider=SQLOLEDB.1;Password=mypassword;Persist Security Info=True;User ID=myuser;Initial Catalog=databank;Data Source=localhost
うまくいきませんでした。確認済みをfalseに設定しようとしましたが、まだタイムアウトになりました。
編集6:同じテーブルの別の投稿を更新しようとしました:
UPDATE [info] SET [confirmed]=0 WHERE [ID]=1;
また、タイムアウトエラーが発生しました。だから今、私たちはそれが特定の投稿ではないことを知っています。
ASPを介して、同じ「データバンク」データベース内の他のテーブルの投稿を更新できます。ローカルホスト上の他のデータベースのテーブルを更新することもできます。
[info]テーブルで何か壊れている可能性はありますか? MS Accessウィザードを使用して、AccessからMS SQL Server 2012にデータを自動移動し、データ型「ntext」の列を作成し、手動で行って、ntextが廃止されたため「nvarchar(MAX)」に変更しました。何かが壊れていませんか?データ型を変更したときにテーブルを再作成する必要がありました。
少し眠らなければなりませんが、誰かが私に返事をくれたら明日またチェックします。あなたが言うことを勇気づけるものだけを持っていても、してください。
編集7:就寝前のクイック編集。接続文字列でもプロバイダーを「SQLNCLI11」として定義しようとしました(実際のプロバイダー名の代わりにDLL nameを使用)。違いはありません。接続は同様に作成されますが、タイムアウトは引き続き発生します。
また、私はMS SQL Server 2012 Expressを使用していません(私の知る限り、「Express」はインストール中にどこにも言及されていませんでした)。それは完全なものです。
役立つ場合は、Management Studioによって提供される[ヘルプ]> [バージョン情報]の情報を次に示します。
Microsoft SQL Server Management Studio: 11.0.2100.60
Microsoft Analysis Services Client Tools: 11.0.2100.60
Microsoft Data Access Components (MDAC): 6.3.9600.16384
Microsoft MSXML: 3.0 5.0 6.0
Microsoft Internet Explorer: 9.11.9600.16521
Microsoft .NET Framework: 4.0.30319.34011
Operating System: 6.3.9600
編集8(「プログラマーはスリープしない」編集とも呼ばれます):
いくつかのことを試した後、最終的にデータベース接続を閉じて、SQLステートメントを実行する直前に再度開くことを試みました。それは突然働きました。なに…?
私は自分のコードをサブルーチンの中に入れましたが、それの外側で私が更新しようとしている投稿はすでに開かれていました!そのため、タイムアウトの理由は、ポストまたはテーブル全体が更新しようとしたのと同じ接続によってロックされていたであったためです。そのため、接続(またはCPUスレッド)はロックが解除されないロックを待機していました。
とても一生懸命やった後、とてもシンプルだとわかったときは嫌いです。
投稿は、次の簡単なコードによってサブルーチンの外部で開かれていました。
Set RecSet = Conn.Execute("SELECT etc")
サブルーチンを呼び出す前に、次を追加しました。
RecSet.Close
Set RecSet = Nothing
これが私の心を決して渡らなかった理由は、単にこれがMS Accessで許可されていたからですが、今ではMS SQL Serverに変更しましたが、それほど親切ではありませんでした。 Conn.Execute()によって作成されたRecSetは、以前データベースにロックされた投稿を作成したことはありませんでしたが、今では突然作成されました。接続文字列と実際のデータベースが変更されたため、それほど奇妙ではありません。
MS AccessからMS SQL Serverに移行する場合、この投稿が他の人の頭痛の種になることを願っています。最近、世界中に多くのAccessユーザーが残っているとは想像できませんが。
投稿(またはテーブル全体)が、投稿を更新しようとした接続とまったく同じ接続によってロックされていたことがわかりました。
私が作成した投稿のオープンレコードセットがありました。
Set RecSet = Conn.Execute()
このタイプのレコードセットは読み取り専用であると想定されており、データベースとしてMS Accessを使用していたときは何もロックしませんでした。しかし、どうやらこのタイプのレコードセットは、MS SQL Server 2012で何かをロックしたようです。UPDATESQLステートメントを実行する前にこれらのコード行を追加すると...
RecSet.Close
Set RecSet = Nothing
...すべてがうまくいきました。
つまり、開いているレコードセットには注意が必要です。たとえ読み取り専用であっても、更新からテーブルをロックする可能性があります。